github.com/ethereum/go-ethereum@v1.16.1/internal/ethapi/transaction_args_test.go (about) 1 // Copyright 2022 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 "context" 21 "errors" 22 "math/big" 23 "reflect" 24 "testing" 25 "time" 26 27 "github.com/ethereum/go-ethereum" 28 "github.com/ethereum/go-ethereum/accounts" 29 "github.com/ethereum/go-ethereum/common" 30 "github.com/ethereum/go-ethereum/common/hexutil" 31 "github.com/ethereum/go-ethereum/consensus" 32 "github.com/ethereum/go-ethereum/core" 33 "github.com/ethereum/go-ethereum/core/filtermaps" 34 "github.com/ethereum/go-ethereum/core/state" 35 "github.com/ethereum/go-ethereum/core/types" 36 "github.com/ethereum/go-ethereum/core/vm" 37 "github.com/ethereum/go-ethereum/ethdb" 38 "github.com/ethereum/go-ethereum/event" 39 "github.com/ethereum/go-ethereum/params" 40 "github.com/ethereum/go-ethereum/rpc" 41 ) 42 43 // TestSetFeeDefaults tests the logic for filling in default fee values works as expected. 44 func TestSetFeeDefaults(t *testing.T) { 45 t.Parallel() 46 47 type test struct { 48 name string 49 fork string // options: legacy, london, cancun 50 in *TransactionArgs 51 want *TransactionArgs 52 err error 53 } 54 55 var ( 56 b = newBackendMock() 57 zero = (*hexutil.Big)(big.NewInt(0)) 58 fortytwo = (*hexutil.Big)(big.NewInt(42)) 59 maxFee = (*hexutil.Big)(new(big.Int).Add(new(big.Int).Mul(b.current.BaseFee, big.NewInt(2)), fortytwo.ToInt())) 60 al = &types.AccessList{types.AccessTuple{Address: common.Address{0xaa}, StorageKeys: []common.Hash{{0x01}}}} 61 ) 62 63 tests := []test{ 64 // Legacy txs 65 { 66 "legacy tx pre-London", 67 "legacy", 68 &TransactionArgs{}, 69 &TransactionArgs{GasPrice: fortytwo}, 70 nil, 71 }, 72 { 73 "legacy tx pre-London with zero price", 74 "legacy", 75 &TransactionArgs{GasPrice: zero}, 76 &TransactionArgs{GasPrice: zero}, 77 nil, 78 }, 79 { 80 "legacy tx post-London, explicit gas price", 81 "london", 82 &TransactionArgs{GasPrice: fortytwo}, 83 &TransactionArgs{GasPrice: fortytwo}, 84 nil, 85 }, 86 { 87 "legacy tx post-London with zero price", 88 "london", 89 &TransactionArgs{GasPrice: zero}, 90 nil, 91 errors.New("gasPrice must be non-zero after london fork"), 92 }, 93 94 // Access list txs 95 { 96 "access list tx pre-London", 97 "legacy", 98 &TransactionArgs{AccessList: al}, 99 &TransactionArgs{AccessList: al, GasPrice: fortytwo}, 100 nil, 101 }, 102 { 103 "access list tx post-London, explicit gas price", 104 "legacy", 105 &TransactionArgs{AccessList: al, GasPrice: fortytwo}, 106 &TransactionArgs{AccessList: al, GasPrice: fortytwo}, 107 nil, 108 }, 109 { 110 "access list tx post-London", 111 "london", 112 &TransactionArgs{AccessList: al}, 113 &TransactionArgs{AccessList: al, MaxFeePerGas: maxFee, MaxPriorityFeePerGas: fortytwo}, 114 nil, 115 }, 116 { 117 "access list tx post-London, only max fee", 118 "london", 119 &TransactionArgs{AccessList: al, MaxFeePerGas: maxFee}, 120 &TransactionArgs{AccessList: al, MaxFeePerGas: maxFee, MaxPriorityFeePerGas: fortytwo}, 121 nil, 122 }, 123 { 124 "access list tx post-London, only priority fee", 125 "london", 126 &TransactionArgs{AccessList: al, MaxFeePerGas: maxFee}, 127 &TransactionArgs{AccessList: al, MaxFeePerGas: maxFee, MaxPriorityFeePerGas: fortytwo}, 128 nil, 129 }, 130 131 // Dynamic fee txs 132 { 133 "dynamic tx post-London", 134 "london", 135 &TransactionArgs{}, 136 &TransactionArgs{MaxFeePerGas: maxFee, MaxPriorityFeePerGas: fortytwo}, 137 nil, 138 }, 139 { 140 "dynamic tx post-London, only max fee", 141 "london", 142 &TransactionArgs{MaxFeePerGas: maxFee}, 143 &TransactionArgs{MaxFeePerGas: maxFee, MaxPriorityFeePerGas: fortytwo}, 144 nil, 145 }, 146 { 147 "dynamic tx post-London, only priority fee", 148 "london", 149 &TransactionArgs{MaxFeePerGas: maxFee}, 150 &TransactionArgs{MaxFeePerGas: maxFee, MaxPriorityFeePerGas: fortytwo}, 151 nil, 152 }, 153 { 154 "dynamic fee tx pre-London, maxFee set", 155 "legacy", 156 &TransactionArgs{MaxFeePerGas: maxFee}, 157 nil, 158 errors.New("maxFeePerGas and maxPriorityFeePerGas are not valid before London is active"), 159 }, 160 { 161 "dynamic fee tx pre-London, priorityFee set", 162 "legacy", 163 &TransactionArgs{MaxPriorityFeePerGas: fortytwo}, 164 nil, 165 errors.New("maxFeePerGas and maxPriorityFeePerGas are not valid before London is active"), 166 }, 167 { 168 "dynamic fee tx, maxFee < priorityFee", 169 "london", 170 &TransactionArgs{MaxFeePerGas: maxFee, MaxPriorityFeePerGas: (*hexutil.Big)(big.NewInt(1000))}, 171 nil, 172 errors.New("maxFeePerGas (0x3e) < maxPriorityFeePerGas (0x3e8)"), 173 }, 174 { 175 "dynamic fee tx, maxFee < priorityFee while setting default", 176 "london", 177 &TransactionArgs{MaxFeePerGas: (*hexutil.Big)(big.NewInt(7))}, 178 nil, 179 errors.New("maxFeePerGas (0x7) < maxPriorityFeePerGas (0x2a)"), 180 }, 181 { 182 "dynamic fee tx post-London, explicit gas price", 183 "london", 184 &TransactionArgs{MaxFeePerGas: zero, MaxPriorityFeePerGas: zero}, 185 nil, 186 errors.New("maxFeePerGas must be non-zero"), 187 }, 188 189 // Misc 190 { 191 "set all fee parameters", 192 "legacy", 193 &TransactionArgs{GasPrice: fortytwo, MaxFeePerGas: maxFee, MaxPriorityFeePerGas: fortytwo}, 194 nil, 195 errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified"), 196 }, 197 { 198 "set gas price and maxPriorityFee", 199 "legacy", 200 &TransactionArgs{GasPrice: fortytwo, MaxPriorityFeePerGas: fortytwo}, 201 nil, 202 errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified"), 203 }, 204 { 205 "set gas price and maxFee", 206 "london", 207 &TransactionArgs{GasPrice: fortytwo, MaxFeePerGas: maxFee}, 208 nil, 209 errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified"), 210 }, 211 // EIP-4844 212 { 213 "set gas price and maxFee for blob transaction", 214 "cancun", 215 &TransactionArgs{GasPrice: fortytwo, MaxFeePerGas: maxFee, BlobHashes: []common.Hash{}}, 216 nil, 217 errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified"), 218 }, 219 { 220 "fill maxFeePerBlobGas", 221 "cancun", 222 &TransactionArgs{BlobHashes: []common.Hash{}}, 223 &TransactionArgs{BlobHashes: []common.Hash{}, BlobFeeCap: (*hexutil.Big)(big.NewInt(4)), MaxFeePerGas: maxFee, MaxPriorityFeePerGas: fortytwo}, 224 nil, 225 }, 226 { 227 "fill maxFeePerBlobGas when dynamic fees are set", 228 "cancun", 229 &TransactionArgs{BlobHashes: []common.Hash{}, MaxFeePerGas: maxFee, MaxPriorityFeePerGas: fortytwo}, 230 &TransactionArgs{BlobHashes: []common.Hash{}, BlobFeeCap: (*hexutil.Big)(big.NewInt(4)), MaxFeePerGas: maxFee, MaxPriorityFeePerGas: fortytwo}, 231 nil, 232 }, 233 } 234 235 ctx := context.Background() 236 for i, test := range tests { 237 if err := b.setFork(test.fork); err != nil { 238 t.Fatalf("failed to set fork: %v", err) 239 } 240 got := test.in 241 err := got.setFeeDefaults(ctx, b, b.CurrentHeader()) 242 if err != nil { 243 if test.err == nil { 244 t.Fatalf("test %d (%s): unexpected error: %s", i, test.name, err) 245 } else if err.Error() != test.err.Error() { 246 t.Fatalf("test %d (%s): unexpected error: (got: %s, want: %s)", i, test.name, err, test.err) 247 } 248 // Matching error. 249 continue 250 } else if test.err != nil { 251 t.Fatalf("test %d (%s): expected error: %s", i, test.name, test.err) 252 } 253 if !reflect.DeepEqual(got, test.want) { 254 t.Fatalf("test %d (%s): did not fill defaults as expected: (got: %v, want: %v)", i, test.name, got, test.want) 255 } 256 } 257 } 258 259 type backendMock struct { 260 current *types.Header 261 config *params.ChainConfig 262 } 263 264 func newBackendMock() *backendMock { 265 var cancunTime uint64 = 600 266 config := ¶ms.ChainConfig{ 267 ChainID: big.NewInt(42), 268 HomesteadBlock: big.NewInt(0), 269 DAOForkBlock: nil, 270 DAOForkSupport: true, 271 EIP150Block: big.NewInt(0), 272 EIP155Block: big.NewInt(0), 273 EIP158Block: big.NewInt(0), 274 ByzantiumBlock: big.NewInt(0), 275 ConstantinopleBlock: big.NewInt(0), 276 PetersburgBlock: big.NewInt(0), 277 IstanbulBlock: big.NewInt(0), 278 MuirGlacierBlock: big.NewInt(0), 279 BerlinBlock: big.NewInt(0), 280 LondonBlock: big.NewInt(1000), 281 CancunTime: &cancunTime, 282 BlobScheduleConfig: params.DefaultBlobSchedule, 283 } 284 return &backendMock{ 285 current: &types.Header{ 286 Difficulty: big.NewInt(10000000000), 287 Number: big.NewInt(1100), 288 GasLimit: 8_000_000, 289 GasUsed: 8_000_000, 290 Time: 555, 291 Extra: make([]byte, 32), 292 BaseFee: big.NewInt(10), 293 }, 294 config: config, 295 } 296 } 297 298 func (b *backendMock) setFork(fork string) error { 299 if fork == "legacy" { 300 b.current.Number = big.NewInt(900) 301 b.current.Time = 555 302 } else if fork == "london" { 303 b.current.Number = big.NewInt(1100) 304 b.current.Time = 555 305 } else if fork == "cancun" { 306 b.current.Number = big.NewInt(1100) 307 b.current.Time = 700 308 // Blob base fee will be 2 309 excess := uint64(2314058) 310 b.current.ExcessBlobGas = &excess 311 } else { 312 return errors.New("invalid fork") 313 } 314 return nil 315 } 316 317 func (b *backendMock) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { 318 return big.NewInt(42), nil 319 } 320 func (b *backendMock) BlobBaseFee(ctx context.Context) *big.Int { return big.NewInt(42) } 321 322 func (b *backendMock) CurrentHeader() *types.Header { return b.current } 323 func (b *backendMock) ChainConfig() *params.ChainConfig { return b.config } 324 325 // Other methods needed to implement Backend interface. 326 func (b *backendMock) SyncProgress(ctx context.Context) ethereum.SyncProgress { 327 return ethereum.SyncProgress{} 328 } 329 func (b *backendMock) FeeHistory(ctx context.Context, blockCount uint64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, []*big.Int, []float64, error) { 330 return nil, nil, nil, nil, nil, nil, nil 331 } 332 func (b *backendMock) ChainDb() ethdb.Database { return nil } 333 func (b *backendMock) AccountManager() *accounts.Manager { return nil } 334 func (b *backendMock) ExtRPCEnabled() bool { return false } 335 func (b *backendMock) RPCGasCap() uint64 { return 0 } 336 func (b *backendMock) RPCEVMTimeout() time.Duration { return time.Second } 337 func (b *backendMock) RPCTxFeeCap() float64 { return 0 } 338 func (b *backendMock) UnprotectedAllowed() bool { return false } 339 func (b *backendMock) SetHead(number uint64) {} 340 func (b *backendMock) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) { 341 return nil, nil 342 } 343 func (b *backendMock) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) { 344 return nil, nil 345 } 346 func (b *backendMock) HeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Header, error) { 347 return nil, nil 348 } 349 func (b *backendMock) CurrentBlock() *types.Header { return nil } 350 func (b *backendMock) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) { 351 return nil, nil 352 } 353 func (b *backendMock) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) { 354 return nil, nil 355 } 356 func (b *backendMock) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error) { 357 return nil, nil 358 } 359 func (b *backendMock) GetBody(ctx context.Context, hash common.Hash, number rpc.BlockNumber) (*types.Body, error) { 360 return nil, nil 361 } 362 func (b *backendMock) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) { 363 return nil, nil, nil 364 } 365 func (b *backendMock) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) { 366 return nil, nil, nil 367 } 368 func (b *backendMock) Pending() (*types.Block, types.Receipts, *state.StateDB) { return nil, nil, nil } 369 func (b *backendMock) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) { 370 return nil, nil 371 } 372 func (b *backendMock) GetCanonicalReceipt(tx *types.Transaction, blockHash common.Hash, blockNumber, blockIndex uint64) (*types.Receipt, error) { 373 return nil, nil 374 } 375 func (b *backendMock) GetLogs(ctx context.Context, blockHash common.Hash, number uint64) ([][]*types.Log, error) { 376 return nil, nil 377 } 378 func (b *backendMock) GetEVM(ctx context.Context, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) *vm.EVM { 379 return nil 380 } 381 func (b *backendMock) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { return nil } 382 func (b *backendMock) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription { 383 return nil 384 } 385 func (b *backendMock) SendTx(ctx context.Context, signedTx *types.Transaction) error { return nil } 386 func (b *backendMock) GetCanonicalTransaction(txHash common.Hash) (bool, *types.Transaction, common.Hash, uint64, uint64) { 387 return false, nil, [32]byte{}, 0, 0 388 } 389 func (b *backendMock) TxIndexDone() bool { return true } 390 func (b *backendMock) GetPoolTransactions() (types.Transactions, error) { return nil, nil } 391 func (b *backendMock) GetPoolTransaction(txHash common.Hash) *types.Transaction { return nil } 392 func (b *backendMock) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) { 393 return 0, nil 394 } 395 func (b *backendMock) Stats() (pending int, queued int) { return 0, 0 } 396 func (b *backendMock) TxPoolContent() (map[common.Address][]*types.Transaction, map[common.Address][]*types.Transaction) { 397 return nil, nil 398 } 399 func (b *backendMock) TxPoolContentFrom(addr common.Address) ([]*types.Transaction, []*types.Transaction) { 400 return nil, nil 401 } 402 func (b *backendMock) SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription { return nil } 403 func (b *backendMock) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription { return nil } 404 func (b *backendMock) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { 405 return nil 406 } 407 408 func (b *backendMock) Engine() consensus.Engine { return nil } 409 410 func (b *backendMock) CurrentView() *filtermaps.ChainView { return nil } 411 func (b *backendMock) NewMatcherBackend() filtermaps.MatcherBackend { return nil } 412 413 func (b *backendMock) HistoryPruningCutoff() uint64 { return 0 }