github.com/theQRL/go-zond@v0.1.1/internal/ethapi/transaction_args.go (about) 1 // Copyright 2021 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package ethapi 18 19 import ( 20 "bytes" 21 "context" 22 "errors" 23 "fmt" 24 "math/big" 25 26 "github.com/theQRL/go-zond/common" 27 "github.com/theQRL/go-zond/common/hexutil" 28 "github.com/theQRL/go-zond/common/math" 29 "github.com/theQRL/go-zond/core" 30 "github.com/theQRL/go-zond/core/types" 31 "github.com/theQRL/go-zond/log" 32 "github.com/theQRL/go-zond/rpc" 33 ) 34 35 // TransactionArgs represents the arguments to construct a new transaction 36 // or a message call. 37 type TransactionArgs struct { 38 From *common.Address `json:"from"` 39 To *common.Address `json:"to"` 40 Gas *hexutil.Uint64 `json:"gas"` 41 GasPrice *hexutil.Big `json:"gasPrice"` 42 MaxFeePerGas *hexutil.Big `json:"maxFeePerGas"` 43 MaxPriorityFeePerGas *hexutil.Big `json:"maxPriorityFeePerGas"` 44 Value *hexutil.Big `json:"value"` 45 Nonce *hexutil.Uint64 `json:"nonce"` 46 47 // We accept "data" and "input" for backwards-compatibility reasons. 48 // "input" is the newer name and should be preferred by clients. 49 // Issue detail: https://github.com/theQRL/go-zond/issues/15628 50 Data *hexutil.Bytes `json:"data"` 51 Input *hexutil.Bytes `json:"input"` 52 53 // Introduced by AccessListTxType transaction. 54 AccessList *types.AccessList `json:"accessList,omitempty"` 55 ChainID *hexutil.Big `json:"chainId,omitempty"` 56 } 57 58 // from retrieves the transaction sender address. 59 func (args *TransactionArgs) from() common.Address { 60 if args.From == nil { 61 return common.Address{} 62 } 63 return *args.From 64 } 65 66 // data retrieves the transaction calldata. Input field is preferred. 67 func (args *TransactionArgs) data() []byte { 68 if args.Input != nil { 69 return *args.Input 70 } 71 if args.Data != nil { 72 return *args.Data 73 } 74 return nil 75 } 76 77 // setDefaults fills in default values for unspecified tx fields. 78 func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend) error { 79 if err := args.setFeeDefaults(ctx, b); err != nil { 80 return err 81 } 82 if args.Value == nil { 83 args.Value = new(hexutil.Big) 84 } 85 if args.Nonce == nil { 86 nonce, err := b.GetPoolNonce(ctx, args.from()) 87 if err != nil { 88 return err 89 } 90 args.Nonce = (*hexutil.Uint64)(&nonce) 91 } 92 if args.Data != nil && args.Input != nil && !bytes.Equal(*args.Data, *args.Input) { 93 return errors.New(`both "data" and "input" are set and not equal. Please use "input" to pass transaction call data`) 94 } 95 if args.To == nil && len(args.data()) == 0 { 96 return errors.New(`contract creation without any data provided`) 97 } 98 // Estimate the gas usage if necessary. 99 if args.Gas == nil { 100 // These fields are immutable during the estimation, safe to 101 // pass the pointer directly. 102 data := args.data() 103 callArgs := TransactionArgs{ 104 From: args.From, 105 To: args.To, 106 GasPrice: args.GasPrice, 107 MaxFeePerGas: args.MaxFeePerGas, 108 MaxPriorityFeePerGas: args.MaxPriorityFeePerGas, 109 Value: args.Value, 110 Data: (*hexutil.Bytes)(&data), 111 AccessList: args.AccessList, 112 } 113 pendingBlockNr := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber) 114 estimated, err := DoEstimateGas(ctx, b, callArgs, pendingBlockNr, nil, b.RPCGasCap()) 115 if err != nil { 116 return err 117 } 118 args.Gas = &estimated 119 log.Trace("Estimate gas usage automatically", "gas", args.Gas) 120 } 121 // If chain id is provided, ensure it matches the local chain id. Otherwise, set the local 122 // chain id as the default. 123 want := b.ChainConfig().ChainID 124 if args.ChainID != nil { 125 if have := (*big.Int)(args.ChainID); have.Cmp(want) != 0 { 126 return fmt.Errorf("chainId does not match node's (have=%v, want=%v)", have, want) 127 } 128 } else { 129 args.ChainID = (*hexutil.Big)(want) 130 } 131 return nil 132 } 133 134 // setFeeDefaults fills in default fee values for unspecified tx fields. 135 func (args *TransactionArgs) setFeeDefaults(ctx context.Context, b Backend) error { 136 // If both gasPrice and at least one of the EIP-1559 fee parameters are specified, error. 137 if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) { 138 return errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified") 139 } 140 // If the tx has completely specified a fee mechanism, no default is needed. This allows users 141 // who are not yet synced past London to get defaults for other tx values. See 142 // https://github.com/theQRL/go-zond/pull/23274 for more information. 143 eip1559ParamsSet := args.MaxFeePerGas != nil && args.MaxPriorityFeePerGas != nil 144 if (args.GasPrice != nil && !eip1559ParamsSet) || (args.GasPrice == nil && eip1559ParamsSet) { 145 // Sanity check the EIP-1559 fee parameters if present. 146 if args.GasPrice == nil && args.MaxFeePerGas.ToInt().Cmp(args.MaxPriorityFeePerGas.ToInt()) < 0 { 147 return fmt.Errorf("maxFeePerGas (%v) < maxPriorityFeePerGas (%v)", args.MaxFeePerGas, args.MaxPriorityFeePerGas) 148 } 149 return nil 150 } 151 // Now attempt to fill in default value depending on whether London is active or not. 152 head := b.CurrentHeader() 153 if b.ChainConfig().IsLondon(head.Number) { 154 // London is active, set maxPriorityFeePerGas and maxFeePerGas. 155 if err := args.setLondonFeeDefaults(ctx, head, b); err != nil { 156 return err 157 } 158 } else { 159 if args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil { 160 return errors.New("maxFeePerGas and maxPriorityFeePerGas are not valid before London is active") 161 } 162 // London not active, set gas price. 163 price, err := b.SuggestGasTipCap(ctx) 164 if err != nil { 165 return err 166 } 167 args.GasPrice = (*hexutil.Big)(price) 168 } 169 return nil 170 } 171 172 // setLondonFeeDefaults fills in reasonable default fee values for unspecified fields. 173 func (args *TransactionArgs) setLondonFeeDefaults(ctx context.Context, head *types.Header, b Backend) error { 174 // Set maxPriorityFeePerGas if it is missing. 175 if args.MaxPriorityFeePerGas == nil { 176 tip, err := b.SuggestGasTipCap(ctx) 177 if err != nil { 178 return err 179 } 180 args.MaxPriorityFeePerGas = (*hexutil.Big)(tip) 181 } 182 // Set maxFeePerGas if it is missing. 183 if args.MaxFeePerGas == nil { 184 // Set the max fee to be 2 times larger than the previous block's base fee. 185 // The additional slack allows the tx to not become invalidated if the base 186 // fee is rising. 187 val := new(big.Int).Add( 188 args.MaxPriorityFeePerGas.ToInt(), 189 new(big.Int).Mul(head.BaseFee, big.NewInt(2)), 190 ) 191 args.MaxFeePerGas = (*hexutil.Big)(val) 192 } 193 // Both EIP-1559 fee parameters are now set; sanity check them. 194 if args.MaxFeePerGas.ToInt().Cmp(args.MaxPriorityFeePerGas.ToInt()) < 0 { 195 return fmt.Errorf("maxFeePerGas (%v) < maxPriorityFeePerGas (%v)", args.MaxFeePerGas, args.MaxPriorityFeePerGas) 196 } 197 return nil 198 } 199 200 // ToMessage converts the transaction arguments to the Message type used by the 201 // core evm. This method is used in calls and traces that do not require a real 202 // live transaction. 203 func (args *TransactionArgs) ToMessage(globalGasCap uint64, baseFee *big.Int) (*core.Message, error) { 204 // Reject invalid combinations of pre- and post-1559 fee styles 205 if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) { 206 return nil, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified") 207 } 208 // Set sender address or use zero address if none specified. 209 addr := args.from() 210 211 // Set default gas & gas price if none were set 212 gas := globalGasCap 213 if gas == 0 { 214 gas = uint64(math.MaxUint64 / 2) 215 } 216 if args.Gas != nil { 217 gas = uint64(*args.Gas) 218 } 219 if globalGasCap != 0 && globalGasCap < gas { 220 log.Warn("Caller gas above allowance, capping", "requested", gas, "cap", globalGasCap) 221 gas = globalGasCap 222 } 223 var ( 224 gasPrice *big.Int 225 gasFeeCap *big.Int 226 gasTipCap *big.Int 227 ) 228 if baseFee == nil { 229 // If there's no basefee, then it must be a non-1559 execution 230 gasPrice = new(big.Int) 231 if args.GasPrice != nil { 232 gasPrice = args.GasPrice.ToInt() 233 } 234 gasFeeCap, gasTipCap = gasPrice, gasPrice 235 } else { 236 // A basefee is provided, necessitating 1559-type execution 237 if args.GasPrice != nil { 238 // User specified the legacy gas field, convert to 1559 gas typing 239 gasPrice = args.GasPrice.ToInt() 240 gasFeeCap, gasTipCap = gasPrice, gasPrice 241 } else { 242 // User specified 1559 gas fields (or none), use those 243 gasFeeCap = new(big.Int) 244 if args.MaxFeePerGas != nil { 245 gasFeeCap = args.MaxFeePerGas.ToInt() 246 } 247 gasTipCap = new(big.Int) 248 if args.MaxPriorityFeePerGas != nil { 249 gasTipCap = args.MaxPriorityFeePerGas.ToInt() 250 } 251 // Backfill the legacy gasPrice for EVM execution, unless we're all zeroes 252 gasPrice = new(big.Int) 253 if gasFeeCap.BitLen() > 0 || gasTipCap.BitLen() > 0 { 254 gasPrice = math.BigMin(new(big.Int).Add(gasTipCap, baseFee), gasFeeCap) 255 } 256 } 257 } 258 value := new(big.Int) 259 if args.Value != nil { 260 value = args.Value.ToInt() 261 } 262 data := args.data() 263 var accessList types.AccessList 264 if args.AccessList != nil { 265 accessList = *args.AccessList 266 } 267 msg := &core.Message{ 268 From: addr, 269 To: args.To, 270 Value: value, 271 GasLimit: gas, 272 GasPrice: gasPrice, 273 GasFeeCap: gasFeeCap, 274 GasTipCap: gasTipCap, 275 Data: data, 276 AccessList: accessList, 277 SkipAccountChecks: true, 278 } 279 return msg, nil 280 } 281 282 // toTransaction converts the arguments to a transaction. 283 // This assumes that setDefaults has been called. 284 func (args *TransactionArgs) toTransaction() *types.Transaction { 285 var data types.TxData 286 switch { 287 case args.MaxFeePerGas != nil: 288 al := types.AccessList{} 289 if args.AccessList != nil { 290 al = *args.AccessList 291 } 292 data = &types.DynamicFeeTx{ 293 To: args.To, 294 ChainID: (*big.Int)(args.ChainID), 295 Nonce: uint64(*args.Nonce), 296 Gas: uint64(*args.Gas), 297 GasFeeCap: (*big.Int)(args.MaxFeePerGas), 298 GasTipCap: (*big.Int)(args.MaxPriorityFeePerGas), 299 Value: (*big.Int)(args.Value), 300 Data: args.data(), 301 AccessList: al, 302 } 303 case args.AccessList != nil: 304 data = &types.AccessListTx{ 305 To: args.To, 306 ChainID: (*big.Int)(args.ChainID), 307 Nonce: uint64(*args.Nonce), 308 Gas: uint64(*args.Gas), 309 GasPrice: (*big.Int)(args.GasPrice), 310 Value: (*big.Int)(args.Value), 311 Data: args.data(), 312 AccessList: *args.AccessList, 313 } 314 default: 315 data = &types.LegacyTx{ 316 To: args.To, 317 Nonce: uint64(*args.Nonce), 318 Gas: uint64(*args.Gas), 319 GasPrice: (*big.Int)(args.GasPrice), 320 Value: (*big.Int)(args.Value), 321 Data: args.data(), 322 } 323 } 324 return types.NewTx(data) 325 } 326 327 // ToTransaction converts the arguments to a transaction. 328 // This assumes that setDefaults has been called. 329 func (args *TransactionArgs) ToTransaction() *types.Transaction { 330 return args.toTransaction() 331 }