| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342 |
- // Copyright 2022 The go-ethereum Authors
- // This file is part of the go-ethereum library.
- //
- // The go-ethereum library is free software: you can redistribute it and/or modify
- // it under the terms of the GNU Lesser General Public License as published by
- // the Free Software Foundation, either version 3 of the License, or
- // (at your option) any later version.
- //
- // The go-ethereum library is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU Lesser General Public License for more details.
- //
- // You should have received a copy of the GNU Lesser General Public License
- // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
- package ethapi
- import (
- "context"
- "fmt"
- "math/big"
- "reflect"
- "testing"
- "time"
- "github.com/ethereum/go-ethereum"
- "github.com/ethereum/go-ethereum/accounts"
- "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/common/hexutil"
- "github.com/ethereum/go-ethereum/consensus"
- "github.com/ethereum/go-ethereum/core"
- "github.com/ethereum/go-ethereum/core/bloombits"
- "github.com/ethereum/go-ethereum/core/state"
- "github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/core/vm"
- "github.com/ethereum/go-ethereum/ethdb"
- "github.com/ethereum/go-ethereum/event"
- "github.com/ethereum/go-ethereum/params"
- "github.com/ethereum/go-ethereum/rpc"
- )
- // TestSetFeeDefaults tests the logic for filling in default fee values works as expected.
- func TestSetFeeDefaults(t *testing.T) {
- type test struct {
- name string
- isLondon bool
- in *TransactionArgs
- want *TransactionArgs
- err error
- }
- var (
- b = newBackendMock()
- fortytwo = (*hexutil.Big)(big.NewInt(42))
- maxFee = (*hexutil.Big)(new(big.Int).Add(new(big.Int).Mul(b.current.BaseFee, big.NewInt(2)), fortytwo.ToInt()))
- al = &types.AccessList{types.AccessTuple{Address: common.Address{0xaa}, StorageKeys: []common.Hash{{0x01}}}}
- )
- tests := []test{
- // Legacy txs
- {
- "legacy tx pre-London",
- false,
- &TransactionArgs{},
- &TransactionArgs{GasPrice: fortytwo},
- nil,
- },
- {
- "legacy tx post-London, explicit gas price",
- true,
- &TransactionArgs{GasPrice: fortytwo},
- &TransactionArgs{GasPrice: fortytwo},
- nil,
- },
- // Access list txs
- {
- "access list tx pre-London",
- false,
- &TransactionArgs{AccessList: al},
- &TransactionArgs{AccessList: al, GasPrice: fortytwo},
- nil,
- },
- {
- "access list tx post-London, explicit gas price",
- false,
- &TransactionArgs{AccessList: al, GasPrice: fortytwo},
- &TransactionArgs{AccessList: al, GasPrice: fortytwo},
- nil,
- },
- {
- "access list tx post-London",
- true,
- &TransactionArgs{AccessList: al},
- &TransactionArgs{AccessList: al, MaxFeePerGas: maxFee, MaxPriorityFeePerGas: fortytwo},
- nil,
- },
- {
- "access list tx post-London, only max fee",
- true,
- &TransactionArgs{AccessList: al, MaxFeePerGas: maxFee},
- &TransactionArgs{AccessList: al, MaxFeePerGas: maxFee, MaxPriorityFeePerGas: fortytwo},
- nil,
- },
- {
- "access list tx post-London, only priority fee",
- true,
- &TransactionArgs{AccessList: al, MaxFeePerGas: maxFee},
- &TransactionArgs{AccessList: al, MaxFeePerGas: maxFee, MaxPriorityFeePerGas: fortytwo},
- nil,
- },
- // Dynamic fee txs
- {
- "dynamic tx post-London",
- true,
- &TransactionArgs{},
- &TransactionArgs{MaxFeePerGas: maxFee, MaxPriorityFeePerGas: fortytwo},
- nil,
- },
- {
- "dynamic tx post-London, only max fee",
- true,
- &TransactionArgs{MaxFeePerGas: maxFee},
- &TransactionArgs{MaxFeePerGas: maxFee, MaxPriorityFeePerGas: fortytwo},
- nil,
- },
- {
- "dynamic tx post-London, only priority fee",
- true,
- &TransactionArgs{MaxFeePerGas: maxFee},
- &TransactionArgs{MaxFeePerGas: maxFee, MaxPriorityFeePerGas: fortytwo},
- nil,
- },
- {
- "dynamic fee tx pre-London, maxFee set",
- false,
- &TransactionArgs{MaxFeePerGas: maxFee},
- nil,
- fmt.Errorf("maxFeePerGas and maxPriorityFeePerGas are not valid before London is active"),
- },
- {
- "dynamic fee tx pre-London, priorityFee set",
- false,
- &TransactionArgs{MaxPriorityFeePerGas: fortytwo},
- nil,
- fmt.Errorf("maxFeePerGas and maxPriorityFeePerGas are not valid before London is active"),
- },
- {
- "dynamic fee tx, maxFee < priorityFee",
- true,
- &TransactionArgs{MaxFeePerGas: maxFee, MaxPriorityFeePerGas: (*hexutil.Big)(big.NewInt(1000))},
- nil,
- fmt.Errorf("maxFeePerGas (0x3e) < maxPriorityFeePerGas (0x3e8)"),
- },
- {
- "dynamic fee tx, maxFee < priorityFee while setting default",
- true,
- &TransactionArgs{MaxFeePerGas: (*hexutil.Big)(big.NewInt(7))},
- nil,
- fmt.Errorf("maxFeePerGas (0x7) < maxPriorityFeePerGas (0x2a)"),
- },
- // Misc
- {
- "set all fee parameters",
- false,
- &TransactionArgs{GasPrice: fortytwo, MaxFeePerGas: maxFee, MaxPriorityFeePerGas: fortytwo},
- nil,
- fmt.Errorf("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified"),
- },
- {
- "set gas price and maxPriorityFee",
- false,
- &TransactionArgs{GasPrice: fortytwo, MaxPriorityFeePerGas: fortytwo},
- nil,
- fmt.Errorf("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified"),
- },
- {
- "set gas price and maxFee",
- true,
- &TransactionArgs{GasPrice: fortytwo, MaxFeePerGas: maxFee},
- nil,
- fmt.Errorf("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified"),
- },
- }
- ctx := context.Background()
- for i, test := range tests {
- if test.isLondon {
- b.activateLondon()
- } else {
- b.deactivateLondon()
- }
- got := test.in
- err := got.setFeeDefaults(ctx, b)
- if err != nil && err.Error() == test.err.Error() {
- // Test threw expected error.
- continue
- } else if err != nil {
- t.Fatalf("test %d (%s): unexpected error: %s", i, test.name, err)
- }
- if !reflect.DeepEqual(got, test.want) {
- t.Fatalf("test %d (%s): did not fill defaults as expected: (got: %v, want: %v)", i, test.name, got, test.want)
- }
- }
- }
- type backendMock struct {
- current *types.Header
- config *params.ChainConfig
- }
- func newBackendMock() *backendMock {
- config := ¶ms.ChainConfig{
- ChainID: big.NewInt(42),
- HomesteadBlock: big.NewInt(0),
- DAOForkBlock: nil,
- DAOForkSupport: true,
- EIP150Block: big.NewInt(0),
- EIP155Block: big.NewInt(0),
- EIP158Block: big.NewInt(0),
- ByzantiumBlock: big.NewInt(0),
- ConstantinopleBlock: big.NewInt(0),
- PetersburgBlock: big.NewInt(0),
- IstanbulBlock: big.NewInt(0),
- MuirGlacierBlock: big.NewInt(0),
- BerlinBlock: big.NewInt(0),
- LondonBlock: big.NewInt(1000),
- }
- return &backendMock{
- current: &types.Header{
- Difficulty: big.NewInt(10000000000),
- Number: big.NewInt(1100),
- GasLimit: 8_000_000,
- GasUsed: 8_000_000,
- Time: 555,
- Extra: make([]byte, 32),
- BaseFee: big.NewInt(10),
- },
- config: config,
- }
- }
- func (b *backendMock) activateLondon() {
- b.current.Number = big.NewInt(1100)
- }
- func (b *backendMock) deactivateLondon() {
- b.current.Number = big.NewInt(900)
- }
- func (b *backendMock) SuggestGasTipCap(ctx context.Context) (*big.Int, error) {
- return big.NewInt(42), nil
- }
- func (b *backendMock) CurrentHeader() *types.Header { return b.current }
- func (b *backendMock) ChainConfig() *params.ChainConfig { return b.config }
- // Other methods needed to implement Backend interface.
- func (b *backendMock) SyncProgress() ethereum.SyncProgress { return ethereum.SyncProgress{} }
- func (b *backendMock) FeeHistory(ctx context.Context, blockCount int, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, error) {
- return nil, nil, nil, nil, nil
- }
- func (b *backendMock) ChainDb() ethdb.Database { return nil }
- func (b *backendMock) AccountManager() *accounts.Manager { return nil }
- func (b *backendMock) ExtRPCEnabled() bool { return false }
- func (b *backendMock) RPCGasCap() uint64 { return 0 }
- func (b *backendMock) RPCEVMTimeout() time.Duration { return time.Second }
- func (b *backendMock) RPCTxFeeCap() float64 { return 0 }
- func (b *backendMock) UnprotectedAllowed() bool { return false }
- func (b *backendMock) SetHead(number uint64) {}
- func (b *backendMock) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) {
- return nil, nil
- }
- func (b *backendMock) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) {
- return nil, nil
- }
- func (b *backendMock) HeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Header, error) {
- return nil, nil
- }
- func (b *backendMock) CurrentBlock() *types.Block { return nil }
- func (b *backendMock) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) {
- return nil, nil
- }
- func (b *backendMock) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) {
- return nil, nil
- }
- func (b *backendMock) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error) {
- return nil, nil
- }
- func (b *backendMock) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) {
- return nil, nil, nil
- }
- func (b *backendMock) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) {
- return nil, nil, nil
- }
- func (b *backendMock) PendingBlockAndReceipts() (*types.Block, types.Receipts) { return nil, nil }
- func (b *backendMock) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) {
- return nil, nil
- }
- func (b *backendMock) GetLogs(ctx context.Context, blockHash common.Hash, number uint64) ([][]*types.Log, error) {
- return nil, nil
- }
- func (b *backendMock) GetTd(ctx context.Context, hash common.Hash) *big.Int { return nil }
- func (b *backendMock) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockContext *vm.BlockContext) (*vm.EVM, func() error, error) {
- return nil, nil, nil
- }
- func (b *backendMock) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { return nil }
- func (b *backendMock) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription {
- return nil
- }
- func (b *backendMock) SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription {
- return nil
- }
- func (b *backendMock) SendTx(ctx context.Context, signedTx *types.Transaction) error { return nil }
- func (b *backendMock) GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) {
- return nil, [32]byte{}, 0, 0, nil
- }
- func (b *backendMock) GetPoolTransactions() (types.Transactions, error) { return nil, nil }
- func (b *backendMock) GetPoolTransaction(txHash common.Hash) *types.Transaction { return nil }
- func (b *backendMock) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) {
- return 0, nil
- }
- func (b *backendMock) Stats() (pending int, queued int) { return 0, 0 }
- func (b *backendMock) TxPoolContent() (map[common.Address]types.Transactions, map[common.Address]types.Transactions) {
- return nil, nil
- }
- func (b *backendMock) TxPoolContentFrom(addr common.Address) (types.Transactions, types.Transactions) {
- return nil, nil
- }
- func (b *backendMock) SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription { return nil }
- func (b *backendMock) BloomStatus() (uint64, uint64) { return 0, 0 }
- func (b *backendMock) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) {}
- func (b *backendMock) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription { return nil }
- func (b *backendMock) SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription {
- return nil
- }
- func (b *backendMock) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription {
- return nil
- }
- func (b *backendMock) Engine() consensus.Engine { return nil }
|