gitlab.com/flarenetwork/coreth@v0.1.1/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/ethereum/go-ethereum/common" 37 "github.com/ethereum/go-ethereum/common/hexutil" 38 "github.com/ethereum/go-ethereum/common/math" 39 "github.com/ethereum/go-ethereum/log" 40 "gitlab.com/flarenetwork/coreth/core/types" 41 "gitlab.com/flarenetwork/coreth/rpc" 42 ) 43 44 // TransactionArgs represents the arguments to construct a new transaction 45 // or a message call. 46 type TransactionArgs struct { 47 From *common.Address `json:"from"` 48 To *common.Address `json:"to"` 49 Gas *hexutil.Uint64 `json:"gas"` 50 GasPrice *hexutil.Big `json:"gasPrice"` 51 MaxFeePerGas *hexutil.Big `json:"maxFeePerGas"` 52 MaxPriorityFeePerGas *hexutil.Big `json:"maxPriorityFeePerGas"` 53 Value *hexutil.Big `json:"value"` 54 Nonce *hexutil.Uint64 `json:"nonce"` 55 56 // We accept "data" and "input" for backwards-compatibility reasons. 57 // "input" is the newer name and should be preferred by clients. 58 // Issue detail: https://github.com/ethereum/go-ethereum/issues/15628 59 Data *hexutil.Bytes `json:"data"` 60 Input *hexutil.Bytes `json:"input"` 61 62 // Introduced by AccessListTxType transaction. 63 AccessList *types.AccessList `json:"accessList,omitempty"` 64 ChainID *hexutil.Big `json:"chainId,omitempty"` 65 } 66 67 // from retrieves the transaction sender address. 68 func (arg *TransactionArgs) from() common.Address { 69 if arg.From == nil { 70 return common.Address{} 71 } 72 return *arg.From 73 } 74 75 // data retrieves the transaction calldata. Input field is preferred. 76 func (arg *TransactionArgs) data() []byte { 77 if arg.Input != nil { 78 return *arg.Input 79 } 80 if arg.Data != nil { 81 return *arg.Data 82 } 83 return nil 84 } 85 86 // setDefaults fills in default values for unspecified tx fields. 87 func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend) error { 88 if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) { 89 return errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified") 90 } 91 // After london, default to 1559 unless gasPrice is set 92 head := b.CurrentHeader() 93 // If user specifies both maxPriorityfee and maxFee, then we do not 94 // need to consult the chain for defaults. It's definitely a London tx. 95 if args.MaxPriorityFeePerGas == nil || args.MaxFeePerGas == nil { 96 // In this clause, user left some fields unspecified. 97 if b.ChainConfig().IsApricotPhase3(new(big.Int).SetUint64(head.Time)) && args.GasPrice == nil { 98 if args.MaxPriorityFeePerGas == nil { 99 tip, err := b.SuggestGasTipCap(ctx) 100 if err != nil { 101 return err 102 } 103 args.MaxPriorityFeePerGas = (*hexutil.Big)(tip) 104 } 105 if args.MaxFeePerGas == nil { 106 gasFeeCap := new(big.Int).Add( 107 (*big.Int)(args.MaxPriorityFeePerGas), 108 new(big.Int).Mul(head.BaseFee, big.NewInt(2)), 109 ) 110 args.MaxFeePerGas = (*hexutil.Big)(gasFeeCap) 111 } 112 if args.MaxFeePerGas.ToInt().Cmp(args.MaxPriorityFeePerGas.ToInt()) < 0 { 113 return fmt.Errorf("maxFeePerGas (%v) < maxPriorityFeePerGas (%v)", args.MaxFeePerGas, args.MaxPriorityFeePerGas) 114 } 115 } else { 116 if args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil { 117 return errors.New("maxFeePerGas or maxPriorityFeePerGas specified but london is not active yet") 118 } 119 if args.GasPrice == nil { 120 price, err := b.SuggestGasTipCap(ctx) 121 if err != nil { 122 return err 123 } 124 if b.ChainConfig().IsApricotPhase3(new(big.Int).SetUint64(head.Time)) { 125 // The legacy tx gas price suggestion should not add 2x base fee 126 // because all fees are consumed, so it would result in a spiral 127 // upwards. 128 price.Add(price, head.BaseFee) 129 } 130 args.GasPrice = (*hexutil.Big)(price) 131 } 132 } 133 } else { 134 // Both maxPriorityfee and maxFee set by caller. Sanity-check their internal relation 135 if args.MaxFeePerGas.ToInt().Cmp(args.MaxPriorityFeePerGas.ToInt()) < 0 { 136 return fmt.Errorf("maxFeePerGas (%v) < maxPriorityFeePerGas (%v)", args.MaxFeePerGas, args.MaxPriorityFeePerGas) 137 } 138 } 139 if args.Value == nil { 140 args.Value = new(hexutil.Big) 141 } 142 if args.Nonce == nil { 143 nonce, err := b.GetPoolNonce(ctx, args.from()) 144 if err != nil { 145 return err 146 } 147 args.Nonce = (*hexutil.Uint64)(&nonce) 148 } 149 if args.Data != nil && args.Input != nil && !bytes.Equal(*args.Data, *args.Input) { 150 return errors.New(`both "data" and "input" are set and not equal. Please use "input" to pass transaction call data`) 151 } 152 if args.To == nil && len(args.data()) == 0 { 153 return errors.New(`contract creation without any data provided`) 154 } 155 // Estimate the gas usage if necessary. 156 if args.Gas == nil { 157 // These fields are immutable during the estimation, safe to 158 // pass the pointer directly. 159 callArgs := TransactionArgs{ 160 From: args.From, 161 To: args.To, 162 GasPrice: args.GasPrice, 163 MaxFeePerGas: args.MaxFeePerGas, 164 MaxPriorityFeePerGas: args.MaxPriorityFeePerGas, 165 Value: args.Value, 166 Data: args.Data, 167 AccessList: args.AccessList, 168 } 169 pendingBlockNr := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber) 170 estimated, err := DoEstimateGas(ctx, b, callArgs, pendingBlockNr, b.RPCGasCap()) 171 if err != nil { 172 return err 173 } 174 args.Gas = &estimated 175 log.Trace("Estimate gas usage automatically", "gas", args.Gas) 176 } 177 if args.ChainID == nil { 178 id := (*hexutil.Big)(b.ChainConfig().ChainID) 179 args.ChainID = id 180 } 181 return nil 182 } 183 184 // ToMessage converts the transaction arguments to the Message type used by the 185 // core evm. This method is used in calls and traces that do not require a real 186 // live transaction. 187 func (args *TransactionArgs) ToMessage(globalGasCap uint64, baseFee *big.Int) (types.Message, error) { 188 // Reject invalid combinations of pre- and post-1559 fee styles 189 if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) { 190 return types.Message{}, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified") 191 } 192 // Set sender address or use zero address if none specified. 193 addr := args.from() 194 195 // Set default gas & gas price if none were set 196 gas := globalGasCap 197 if gas == 0 { 198 gas = uint64(math.MaxUint64 / 2) 199 } 200 if args.Gas != nil { 201 gas = uint64(*args.Gas) 202 } 203 if globalGasCap != 0 && globalGasCap < gas { 204 log.Warn("Caller gas above allowance, capping", "requested", gas, "cap", globalGasCap) 205 gas = globalGasCap 206 } 207 var ( 208 gasPrice *big.Int 209 gasFeeCap *big.Int 210 gasTipCap *big.Int 211 ) 212 if baseFee == nil { 213 // If there's no basefee, then it must be a non-1559 execution 214 gasPrice = new(big.Int) 215 if args.GasPrice != nil { 216 gasPrice = args.GasPrice.ToInt() 217 } 218 gasFeeCap, gasTipCap = gasPrice, gasPrice 219 } else { 220 // A basefee is provided, necessitating 1559-type execution 221 if args.GasPrice != nil { 222 // User specified the legacy gas field, convert to 1559 gas typing 223 gasPrice = args.GasPrice.ToInt() 224 gasFeeCap, gasTipCap = gasPrice, gasPrice 225 } else { 226 // User specified 1559 gas feilds (or none), use those 227 gasFeeCap = new(big.Int) 228 if args.MaxFeePerGas != nil { 229 gasFeeCap = args.MaxFeePerGas.ToInt() 230 } 231 gasTipCap = new(big.Int) 232 if args.MaxPriorityFeePerGas != nil { 233 gasTipCap = args.MaxPriorityFeePerGas.ToInt() 234 } 235 // Backfill the legacy gasPrice for EVM execution, unless we're all zeroes 236 gasPrice = new(big.Int) 237 if gasFeeCap.BitLen() > 0 || gasTipCap.BitLen() > 0 { 238 gasPrice = math.BigMin(new(big.Int).Add(gasTipCap, baseFee), gasFeeCap) 239 } 240 } 241 } 242 value := new(big.Int) 243 if args.Value != nil { 244 value = args.Value.ToInt() 245 } 246 data := args.data() 247 var accessList types.AccessList 248 if args.AccessList != nil { 249 accessList = *args.AccessList 250 } 251 msg := types.NewMessage(addr, args.To, 0, value, gas, gasPrice, gasFeeCap, gasTipCap, data, accessList, true) 252 return msg, nil 253 } 254 255 // toTransaction converts the arguments to a transaction. 256 // This assumes that setDefaults has been called. 257 func (args *TransactionArgs) toTransaction() *types.Transaction { 258 var data types.TxData 259 switch { 260 case args.MaxFeePerGas != nil: 261 al := types.AccessList{} 262 if args.AccessList != nil { 263 al = *args.AccessList 264 } 265 data = &types.DynamicFeeTx{ 266 To: args.To, 267 ChainID: (*big.Int)(args.ChainID), 268 Nonce: uint64(*args.Nonce), 269 Gas: uint64(*args.Gas), 270 GasFeeCap: (*big.Int)(args.MaxFeePerGas), 271 GasTipCap: (*big.Int)(args.MaxPriorityFeePerGas), 272 Value: (*big.Int)(args.Value), 273 Data: args.data(), 274 AccessList: al, 275 } 276 case args.AccessList != nil: 277 data = &types.AccessListTx{ 278 To: args.To, 279 ChainID: (*big.Int)(args.ChainID), 280 Nonce: uint64(*args.Nonce), 281 Gas: uint64(*args.Gas), 282 GasPrice: (*big.Int)(args.GasPrice), 283 Value: (*big.Int)(args.Value), 284 Data: args.data(), 285 AccessList: *args.AccessList, 286 } 287 default: 288 data = &types.LegacyTx{ 289 To: args.To, 290 Nonce: uint64(*args.Nonce), 291 Gas: uint64(*args.Gas), 292 GasPrice: (*big.Int)(args.GasPrice), 293 Value: (*big.Int)(args.Value), 294 Data: args.data(), 295 } 296 } 297 return types.NewTx(data) 298 } 299 300 // ToTransaction converts the arguments to a transaction. 301 // This assumes that setDefaults has been called. 302 func (args *TransactionArgs) ToTransaction() *types.Transaction { 303 return args.toTransaction() 304 }