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