forked from cerc-io/plugeth
67ac5f0ae7
Here, the core.Message interface turns into a plain struct and types.Message gets removed. This is a breaking change to packages core and core/types. While we do not promise API stability for package core, we do for core/types. An exception can be made for types.Message, since it doesn't have any purpose apart from invoking the state transition in package core. types.Message was also marked deprecated by the same commit it got added in,4dca5d4db7
(November 2016). The core.Message interface was added in December 2014, in commitdb494170dc
, for the purpose of 'testing' state transitions. It's the same change that made transaction struct fields private. Before that, the state transition used *types.Transaction directly. Over time, multiple implementations of the interface accrued across different packages, since constructing a Message is required whenever one wants to invoke the state transition. These implementations all looked very similar, a struct with private fields exposing the fields as accessor methods. By changing Message into a struct with public fields we can remove all these useless interface implementations. It will also hopefully simplify future changes to the type with less updates to apply across all of go-ethereum when a field is added to Message. --------- Co-authored-by: Felix Lange <fjl@twurst.com>
346 lines
12 KiB
Go
346 lines
12 KiB
Go
// 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.Header { 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) GetBody(ctx context.Context, hash common.Hash, number rpc.BlockNumber) (*types.Body, 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) (*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 }
|