From 6708e64850d1db306f941e94d995f49343a23141 Mon Sep 17 00:00:00 2001 From: devopsbo3 <69951731+devopsbo3@users.noreply.github.com> Date: Fri, 10 Nov 2023 12:27:53 -0600 Subject: [PATCH] Revert "internal/ethapi: add block overrides to eth_call (#26414)" This reverts commit 1c66a6b59dc149188870ac3a2eae0db50ef68d67. --- eth/api_backend.go | 9 +- eth/tracers/api.go | 26 +- ethclient/gethclient/gethclient.go | 71 ---- ethclient/gethclient/gethclient_test.go | 75 ---- graphql/graphql.go | 4 +- internal/ethapi/api.go | 49 +-- internal/ethapi/api_test.go | 467 ----------------------- internal/ethapi/backend.go | 2 +- internal/ethapi/transaction_args_test.go | 2 +- internal/web3ext/web3ext.go | 4 +- les/api_backend.go | 5 +- 11 files changed, 40 insertions(+), 674 deletions(-) diff --git a/eth/api_backend.go b/eth/api_backend.go index 959568d2948a5..0e4521173bf17 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -246,17 +246,12 @@ func (b *EthAPIBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int { return nil } -func (b *EthAPIBackend) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) (*vm.EVM, func() error, error) { +func (b *EthAPIBackend) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) { if vmConfig == nil { vmConfig = b.eth.blockchain.GetVMConfig() } txContext := core.NewEVMTxContext(msg) - var context vm.BlockContext - if blockCtx != nil { - context = *blockCtx - } else { - context = core.NewEVMBlockContext(header, b.eth.BlockChain(), nil) - } + context := core.NewEVMBlockContext(header, b.eth.BlockChain(), nil) return vm.NewEVM(context, txContext, state, b.eth.blockchain.Config(), *vmConfig), state.Error, nil } diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 34f4199a83648..2bb00f0d2cc18 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -100,10 +100,34 @@ func NewAPI(backend Backend) *API { return &API{backend: backend} } +type chainContext struct { + api *API + ctx context.Context +} + +func (context *chainContext) Engine() consensus.Engine { + return context.api.backend.Engine() +} + +func (context *chainContext) GetHeader(hash common.Hash, number uint64) *types.Header { + header, err := context.api.backend.HeaderByNumber(context.ctx, rpc.BlockNumber(number)) + if err != nil { + return nil + } + if header.Hash() == hash { + return header + } + header, err = context.api.backend.HeaderByHash(context.ctx, hash) + if err != nil { + return nil + } + return header +} + // chainContext constructs the context reader which is used by the evm for reading // the necessary chain context. func (api *API) chainContext(ctx context.Context) core.ChainContext { - return ethapi.NewChainContext(ctx, api.backend) + return &chainContext{api: api, ctx: ctx} } // blockByNumber is the wrapper of the chain access function offered by the backend. diff --git a/ethclient/gethclient/gethclient.go b/ethclient/gethclient/gethclient.go index 718cdfea426a6..fdcfb9a0ac406 100644 --- a/ethclient/gethclient/gethclient.go +++ b/ethclient/gethclient/gethclient.go @@ -143,28 +143,6 @@ func (ec *Client) CallContract(ctx context.Context, msg ethereum.CallMsg, blockN return hex, err } -// CallContractWithBlockOverrides executes a message call transaction, which is directly executed -// in the VM of the node, but never mined into the blockchain. -// -// blockNumber selects the block height at which the call runs. It can be nil, in which -// case the code is taken from the latest known block. Note that state from very old -// blocks might not be available. -// -// overrides specifies a map of contract states that should be overwritten before executing -// the message call. -// -// blockOverrides specifies block fields exposed to the EVM that can be overridden for the call. -// -// Please use ethclient.CallContract instead if you don't need the override functionality. -func (ec *Client) CallContractWithBlockOverrides(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int, overrides *map[common.Address]OverrideAccount, blockOverrides BlockOverrides) ([]byte, error) { - var hex hexutil.Bytes - err := ec.c.CallContext( - ctx, &hex, "eth_call", toCallArg(msg), - toBlockNumArg(blockNumber), overrides, blockOverrides, - ) - return hex, err -} - // GCStats retrieves the current garbage collection stats from a geth node. func (ec *Client) GCStats(ctx context.Context) (*debug.GCStats, error) { var result debug.GCStats @@ -287,52 +265,3 @@ func (a OverrideAccount) MarshalJSON() ([]byte, error) { } return json.Marshal(output) } - -// BlockOverrides specifies the set of header fields to override. -type BlockOverrides struct { - // Number overrides the block number. - Number *big.Int - // Difficulty overrides the block difficulty. - Difficulty *big.Int - // Time overrides the block timestamp. Time is applied only when - // it is non-zero. - Time uint64 - // GasLimit overrides the block gas limit. GasLimit is applied only when - // it is non-zero. - GasLimit uint64 - // Coinbase overrides the block coinbase. Coinbase is applied only when - // it is different from the zero address. - Coinbase common.Address - // Random overrides the block extra data which feeds into the RANDOM opcode. - // Random is applied only when it is a non-zero hash. - Random common.Hash - // BaseFee overrides the block base fee. - BaseFee *big.Int -} - -func (o BlockOverrides) MarshalJSON() ([]byte, error) { - type override struct { - Number *hexutil.Big `json:"number,omitempty"` - Difficulty *hexutil.Big `json:"difficulty,omitempty"` - Time hexutil.Uint64 `json:"time,omitempty"` - GasLimit hexutil.Uint64 `json:"gasLimit,omitempty"` - Coinbase *common.Address `json:"coinbase,omitempty"` - Random *common.Hash `json:"random,omitempty"` - BaseFee *hexutil.Big `json:"baseFee,omitempty"` - } - - output := override{ - Number: (*hexutil.Big)(o.Number), - Difficulty: (*hexutil.Big)(o.Difficulty), - Time: hexutil.Uint64(o.Time), - GasLimit: hexutil.Uint64(o.GasLimit), - BaseFee: (*hexutil.Big)(o.BaseFee), - } - if o.Coinbase != (common.Address{}) { - output.Coinbase = &o.Coinbase - } - if o.Random != (common.Hash{}) { - output.Random = &o.Random - } - return json.Marshal(output) -} diff --git a/ethclient/gethclient/gethclient_test.go b/ethclient/gethclient/gethclient_test.go index 87456fd64c64e..a9637d182f1f9 100644 --- a/ethclient/gethclient/gethclient_test.go +++ b/ethclient/gethclient/gethclient_test.go @@ -127,9 +127,6 @@ func TestGethClient(t *testing.T) { }, { "TestCallContract", func(t *testing.T) { testCallContract(t, client) }, - }, { - "TestCallContractWithBlockOverrides", - func(t *testing.T) { testCallContractWithBlockOverrides(t, client) }, }, // The testaccesslist is a bit time-sensitive: the newTestBackend imports // one block. The `testAcessList` fails if the miner has not yet created a @@ -416,75 +413,3 @@ func TestOverrideAccountMarshal(t *testing.T) { t.Error("want:", expected) } } - -func TestBlockOverridesMarshal(t *testing.T) { - for i, tt := range []struct { - bo BlockOverrides - want string - }{ - { - bo: BlockOverrides{}, - want: `{}`, - }, - { - bo: BlockOverrides{ - Coinbase: common.HexToAddress("0x1111111111111111111111111111111111111111"), - }, - want: `{"coinbase":"0x1111111111111111111111111111111111111111"}`, - }, - { - bo: BlockOverrides{ - Number: big.NewInt(1), - Difficulty: big.NewInt(2), - Time: 3, - GasLimit: 4, - BaseFee: big.NewInt(5), - }, - want: `{"number":"0x1","difficulty":"0x2","time":"0x3","gasLimit":"0x4","baseFee":"0x5"}`, - }, - } { - marshalled, err := json.Marshal(&tt.bo) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - if string(marshalled) != tt.want { - t.Errorf("Testcase #%d failed. expected\n%s\ngot\n%s", i, tt.want, string(marshalled)) - } - } -} - -func testCallContractWithBlockOverrides(t *testing.T, client *rpc.Client) { - ec := New(client) - msg := ethereum.CallMsg{ - From: testAddr, - To: &common.Address{}, - Gas: 50000, - GasPrice: big.NewInt(1000000000), - Value: big.NewInt(1), - } - override := OverrideAccount{ - // Returns coinbase address. - Code: common.FromHex("0x41806000526014600cf3"), - } - mapAcc := make(map[common.Address]OverrideAccount) - mapAcc[common.Address{}] = override - res, err := ec.CallContract(context.Background(), msg, big.NewInt(0), &mapAcc) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - if !bytes.Equal(res, common.FromHex("0x0000000000000000000000000000000000000000")) { - t.Fatalf("unexpected result: %x", res) - } - - // Now test with block overrides - bo := BlockOverrides{ - Coinbase: common.HexToAddress("0x1111111111111111111111111111111111111111"), - } - res, err = ec.CallContractWithBlockOverrides(context.Background(), msg, big.NewInt(0), &mapAcc, bo) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - if !bytes.Equal(res, common.FromHex("0x1111111111111111111111111111111111111111")) { - t.Fatalf("unexpected result: %x", res) - } -} diff --git a/graphql/graphql.go b/graphql/graphql.go index 35ea8643ad9c7..ce3ca171cf56f 100644 --- a/graphql/graphql.go +++ b/graphql/graphql.go @@ -1068,7 +1068,7 @@ func (c *CallResult) Status() hexutil.Uint64 { func (b *Block) Call(ctx context.Context, args struct { Data ethapi.TransactionArgs }) (*CallResult, error) { - result, err := ethapi.DoCall(ctx, b.r.backend, args.Data, *b.numberOrHash, nil, nil, b.r.backend.RPCEVMTimeout(), b.r.backend.RPCGasCap()) + result, err := ethapi.DoCall(ctx, b.r.backend, args.Data, *b.numberOrHash, nil, b.r.backend.RPCEVMTimeout(), b.r.backend.RPCGasCap()) if err != nil { return nil, err } @@ -1131,7 +1131,7 @@ func (p *Pending) Call(ctx context.Context, args struct { Data ethapi.TransactionArgs }) (*CallResult, error) { pendingBlockNr := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber) - result, err := ethapi.DoCall(ctx, p.r.backend, args.Data, pendingBlockNr, nil, nil, p.r.backend.RPCEVMTimeout(), p.r.backend.RPCGasCap()) + result, err := ethapi.DoCall(ctx, p.r.backend, args.Data, pendingBlockNr, nil, p.r.backend.RPCEVMTimeout(), p.r.backend.RPCGasCap()) if err != nil { return nil, err } diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 82ca894609b2a..f1041d6a50eb7 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -33,7 +33,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/math" - "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/core" @@ -956,39 +955,7 @@ func (diff *BlockOverrides) Apply(blockCtx *vm.BlockContext) { } } -// ChainContextBackend provides methods required to implement ChainContext. -type ChainContextBackend interface { - Engine() consensus.Engine - HeaderByNumber(context.Context, rpc.BlockNumber) (*types.Header, error) -} - -// ChainContext is an implementation of core.ChainContext. It's main use-case -// is instantiating a vm.BlockContext without having access to the BlockChain object. -type ChainContext struct { - b ChainContextBackend - ctx context.Context -} - -// NewChainContext creates a new ChainContext object. -func NewChainContext(ctx context.Context, backend ChainContextBackend) *ChainContext { - return &ChainContext{ctx: ctx, b: backend} -} - -func (context *ChainContext) Engine() consensus.Engine { - return context.b.Engine() -} - -func (context *ChainContext) GetHeader(hash common.Hash, number uint64) *types.Header { - // This method is called to get the hash for a block number when executing the BLOCKHASH - // opcode. Hence no need to search for non-canonical blocks. - header, err := context.b.HeaderByNumber(context.ctx, rpc.BlockNumber(number)) - if err != nil || header.Hash() != hash { - return nil - } - return header -} - -func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride, blockOverrides *BlockOverrides, timeout time.Duration, globalGasCap uint64) (*core.ExecutionResult, error) { +func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride, timeout time.Duration, globalGasCap uint64) (*core.ExecutionResult, error) { defer func(start time.Time) { log.Debug("Executing EVM call finished", "runtime", time.Since(start)) }(time.Now()) state, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) @@ -1015,11 +982,7 @@ func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash if err != nil { return nil, err } - blockCtx := core.NewEVMBlockContext(header, NewChainContext(ctx, b), nil) - if blockOverrides != nil { - blockOverrides.Apply(&blockCtx) - } - evm, vmError, err := b.GetEVM(ctx, msg, state, header, &vm.Config{NoBaseFee: true}, &blockCtx) + evm, vmError, err := b.GetEVM(ctx, msg, state, header, &vm.Config{NoBaseFee: true}) if err != nil { return nil, err } @@ -1083,8 +1046,8 @@ func (e *revertError) ErrorData() interface{} { // // Note, this function doesn't make and changes in the state/blockchain and is // useful to execute and retrieve values. -func (s *BlockChainAPI) Call(ctx context.Context, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride, blockOverrides *BlockOverrides) (hexutil.Bytes, error) { - result, err := DoCall(ctx, s.b, args, blockNrOrHash, overrides, blockOverrides, s.b.RPCEVMTimeout(), s.b.RPCGasCap()) +func (s *BlockChainAPI) Call(ctx context.Context, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride) (hexutil.Bytes, error) { + result, err := DoCall(ctx, s.b, args, blockNrOrHash, overrides, s.b.RPCEVMTimeout(), s.b.RPCGasCap()) if err != nil { return nil, err } @@ -1169,7 +1132,7 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr executable := func(gas uint64) (bool, *core.ExecutionResult, error) { args.Gas = (*hexutil.Uint64)(&gas) - result, err := DoCall(ctx, b, args, blockNrOrHash, nil, nil, 0, gasCap) + result, err := DoCall(ctx, b, args, blockNrOrHash, nil, 0, gasCap) if err != nil { if errors.Is(err, core.ErrIntrinsicGas) { return true, nil, nil // Special case, raise gas limit @@ -1515,7 +1478,7 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH // Apply the transaction with the access list tracer tracer := logger.NewAccessListTracer(accessList, args.from(), to, precompiles) config := vm.Config{Tracer: tracer, NoBaseFee: true} - vmenv, _, err := b.GetEVM(ctx, msg, statedb, header, &config, nil) + vmenv, _, err := b.GetEVM(ctx, msg, statedb, header, &config) if err != nil { return nil, 0, nil, err } diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index 39f912a349d0f..205e23e8474cb 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -17,34 +17,14 @@ package ethapi import ( - "bytes" - "context" - "crypto/ecdsa" "encoding/json" - "errors" "math/big" - "reflect" - "sort" "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/consensus/ethash" - "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/bloombits" - "github.com/ethereum/go-ethereum/core/rawdb" - "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/crypto" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/params" - "github.com/ethereum/go-ethereum/rpc" ) func TestTransaction_RoundTripRpcJSON(t *testing.T) { @@ -177,450 +157,3 @@ func allTransactionTypes(addr common.Address, config *params.ChainConfig) []type }, } } - -type testBackend struct { - db ethdb.Database - chain *core.BlockChain -} - -func newTestBackend(t *testing.T, n int, gspec *core.Genesis, generator func(i int, b *core.BlockGen)) *testBackend { - var ( - engine = ethash.NewFaker() - backend = &testBackend{ - db: rawdb.NewMemoryDatabase(), - } - cacheConfig = &core.CacheConfig{ - TrieCleanLimit: 256, - TrieDirtyLimit: 256, - TrieTimeLimit: 5 * time.Minute, - SnapshotLimit: 0, - TrieDirtyDisabled: true, // Archive mode - } - ) - // Generate blocks for testing - _, blocks, _ := core.GenerateChainWithGenesis(gspec, engine, n, generator) - chain, err := core.NewBlockChain(backend.db, cacheConfig, gspec, nil, engine, vm.Config{}, nil, nil) - if err != nil { - t.Fatalf("failed to create tester chain: %v", err) - } - if n, err := chain.InsertChain(blocks); err != nil { - t.Fatalf("block %d: failed to insert into chain: %v", n, err) - } - backend.chain = chain - return backend -} - -func (b testBackend) SyncProgress() ethereum.SyncProgress { return ethereum.SyncProgress{} } -func (b testBackend) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { - return big.NewInt(0), nil -} -func (b testBackend) FeeHistory(ctx context.Context, blockCount uint64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, error) { - return nil, nil, nil, nil, nil -} -func (b testBackend) ChainDb() ethdb.Database { return b.db } -func (b testBackend) AccountManager() *accounts.Manager { return nil } -func (b testBackend) ExtRPCEnabled() bool { return false } -func (b testBackend) RPCGasCap() uint64 { return 10000000 } -func (b testBackend) RPCEVMTimeout() time.Duration { return time.Second } -func (b testBackend) RPCTxFeeCap() float64 { return 0 } -func (b testBackend) UnprotectedAllowed() bool { return false } -func (b testBackend) SetHead(number uint64) {} -func (b testBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) { - if number == rpc.LatestBlockNumber { - return b.chain.CurrentBlock(), nil - } - return b.chain.GetHeaderByNumber(uint64(number)), nil -} -func (b testBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) { - panic("implement me") -} -func (b testBackend) HeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Header, error) { - panic("implement me") -} -func (b testBackend) CurrentHeader() *types.Header { panic("implement me") } -func (b testBackend) CurrentBlock() *types.Header { panic("implement me") } -func (b testBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) { - if number == rpc.LatestBlockNumber { - head := b.chain.CurrentBlock() - return b.chain.GetBlock(head.Hash(), head.Number.Uint64()), nil - } - return b.chain.GetBlockByNumber(uint64(number)), nil -} -func (b testBackend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) { - panic("implement me") -} -func (b testBackend) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error) { - if blockNr, ok := blockNrOrHash.Number(); ok { - return b.BlockByNumber(ctx, blockNr) - } - panic("implement me") -} -func (b testBackend) GetBody(ctx context.Context, hash common.Hash, number rpc.BlockNumber) (*types.Body, error) { - return b.chain.GetBlock(hash, uint64(number.Int64())).Body(), nil -} -func (b testBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) { - if number == rpc.PendingBlockNumber { - panic("pending state not implemented") - } - header, err := b.HeaderByNumber(ctx, number) - if err != nil { - return nil, nil, err - } - if header == nil { - return nil, nil, errors.New("header not found") - } - stateDb, err := b.chain.StateAt(header.Root) - return stateDb, header, err -} -func (b testBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) { - if blockNr, ok := blockNrOrHash.Number(); ok { - return b.StateAndHeaderByNumber(ctx, blockNr) - } - panic("only implemented for number") -} -func (b testBackend) PendingBlockAndReceipts() (*types.Block, types.Receipts) { panic("implement me") } -func (b testBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) { - panic("implement me") -} -func (b testBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int { panic("implement me") } -func (b testBackend) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockContext *vm.BlockContext) (*vm.EVM, func() error, error) { - vmError := func() error { return nil } - if vmConfig == nil { - vmConfig = b.chain.GetVMConfig() - } - txContext := core.NewEVMTxContext(msg) - context := core.NewEVMBlockContext(header, b.chain, nil) - if blockContext != nil { - context = *blockContext - } - return vm.NewEVM(context, txContext, state, b.chain.Config(), *vmConfig), vmError, nil -} -func (b testBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { - panic("implement me") -} -func (b testBackend) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription { - panic("implement me") -} -func (b testBackend) SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription { - panic("implement me") -} -func (b testBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error { - panic("implement me") -} -func (b testBackend) GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) { - panic("implement me") -} -func (b testBackend) GetPoolTransactions() (types.Transactions, error) { panic("implement me") } -func (b testBackend) GetPoolTransaction(txHash common.Hash) *types.Transaction { panic("implement me") } -func (b testBackend) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) { - panic("implement me") -} -func (b testBackend) Stats() (pending int, queued int) { panic("implement me") } -func (b testBackend) TxPoolContent() (map[common.Address]types.Transactions, map[common.Address]types.Transactions) { - panic("implement me") -} -func (b testBackend) TxPoolContentFrom(addr common.Address) (types.Transactions, types.Transactions) { - panic("implement me") -} -func (b testBackend) SubscribeNewTxsEvent(events chan<- core.NewTxsEvent) event.Subscription { - panic("implement me") -} -func (b testBackend) ChainConfig() *params.ChainConfig { return b.chain.Config() } -func (b testBackend) Engine() consensus.Engine { return b.chain.Engine() } -func (b testBackend) GetLogs(ctx context.Context, blockHash common.Hash, number uint64) ([][]*types.Log, error) { - panic("implement me") -} -func (b testBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { - panic("implement me") -} -func (b testBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription { - panic("implement me") -} -func (b testBackend) SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription { - panic("implement me") -} -func (b testBackend) BloomStatus() (uint64, uint64) { panic("implement me") } -func (b testBackend) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) { - panic("implement me") -} - -func TestEstimateGas(t *testing.T) { - t.Parallel() - // Initialize test accounts - var ( - accounts = newAccounts(2) - genesis = &core.Genesis{ - Config: params.TestChainConfig, - Alloc: core.GenesisAlloc{ - accounts[0].addr: {Balance: big.NewInt(params.Ether)}, - accounts[1].addr: {Balance: big.NewInt(params.Ether)}, - }, - } - genBlocks = 10 - signer = types.HomesteadSigner{} - randomAccounts = newAccounts(2) - ) - api := NewBlockChainAPI(newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) { - // Transfer from account[0] to account[1] - // value: 1000 wei - // fee: 0 wei - tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{Nonce: uint64(i), To: &accounts[1].addr, Value: big.NewInt(1000), Gas: params.TxGas, GasPrice: b.BaseFee(), Data: nil}), signer, accounts[0].key) - b.AddTx(tx) - })) - var testSuite = []struct { - blockNumber rpc.BlockNumber - call TransactionArgs - expectErr error - want uint64 - }{ - // simple transfer on latest block - { - blockNumber: rpc.LatestBlockNumber, - call: TransactionArgs{ - From: &accounts[0].addr, - To: &accounts[1].addr, - Value: (*hexutil.Big)(big.NewInt(1000)), - }, - expectErr: nil, - want: 21000, - }, - // simple transfer with insufficient funds on latest block - { - blockNumber: rpc.LatestBlockNumber, - call: TransactionArgs{ - From: &randomAccounts[0].addr, - To: &accounts[1].addr, - Value: (*hexutil.Big)(big.NewInt(1000)), - }, - expectErr: core.ErrInsufficientFunds, - want: 21000, - }, - // empty create - { - blockNumber: rpc.LatestBlockNumber, - call: TransactionArgs{}, - expectErr: nil, - want: 53000, - }, - } - for i, tc := range testSuite { - result, err := api.EstimateGas(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}) - if tc.expectErr != nil { - if err == nil { - t.Errorf("test %d: want error %v, have nothing", i, tc.expectErr) - continue - } - if !errors.Is(err, tc.expectErr) { - t.Errorf("test %d: error mismatch, want %v, have %v", i, tc.expectErr, err) - } - continue - } - if err != nil { - t.Errorf("test %d: want no error, have %v", i, err) - continue - } - if uint64(result) != tc.want { - t.Errorf("test %d, result mismatch, have\n%v\n, want\n%v\n", i, uint64(result), tc.want) - } - } -} - -func TestCall(t *testing.T) { - t.Parallel() - // Initialize test accounts - var ( - accounts = newAccounts(3) - genesis = &core.Genesis{ - Config: params.TestChainConfig, - Alloc: core.GenesisAlloc{ - accounts[0].addr: {Balance: big.NewInt(params.Ether)}, - accounts[1].addr: {Balance: big.NewInt(params.Ether)}, - accounts[2].addr: {Balance: big.NewInt(params.Ether)}, - }, - } - genBlocks = 10 - signer = types.HomesteadSigner{} - ) - api := NewBlockChainAPI(newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) { - // Transfer from account[0] to account[1] - // value: 1000 wei - // fee: 0 wei - tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{Nonce: uint64(i), To: &accounts[1].addr, Value: big.NewInt(1000), Gas: params.TxGas, GasPrice: b.BaseFee(), Data: nil}), signer, accounts[0].key) - b.AddTx(tx) - })) - randomAccounts := newAccounts(3) - var testSuite = []struct { - blockNumber rpc.BlockNumber - overrides StateOverride - call TransactionArgs - blockOverrides BlockOverrides - expectErr error - want string - }{ - // transfer on genesis - { - blockNumber: rpc.BlockNumber(0), - call: TransactionArgs{ - From: &accounts[0].addr, - To: &accounts[1].addr, - Value: (*hexutil.Big)(big.NewInt(1000)), - }, - expectErr: nil, - want: "0x", - }, - // transfer on the head - { - blockNumber: rpc.BlockNumber(genBlocks), - call: TransactionArgs{ - From: &accounts[0].addr, - To: &accounts[1].addr, - Value: (*hexutil.Big)(big.NewInt(1000)), - }, - expectErr: nil, - want: "0x", - }, - // transfer on a non-existent block, error expects - { - blockNumber: rpc.BlockNumber(genBlocks + 1), - call: TransactionArgs{ - From: &accounts[0].addr, - To: &accounts[1].addr, - Value: (*hexutil.Big)(big.NewInt(1000)), - }, - expectErr: errors.New("header not found"), - }, - // transfer on the latest block - { - blockNumber: rpc.LatestBlockNumber, - call: TransactionArgs{ - From: &accounts[0].addr, - To: &accounts[1].addr, - Value: (*hexutil.Big)(big.NewInt(1000)), - }, - expectErr: nil, - want: "0x", - }, - // Call which can only succeed if state is state overridden - { - blockNumber: rpc.LatestBlockNumber, - call: TransactionArgs{ - From: &randomAccounts[0].addr, - To: &randomAccounts[1].addr, - Value: (*hexutil.Big)(big.NewInt(1000)), - }, - overrides: StateOverride{ - randomAccounts[0].addr: OverrideAccount{Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether)))}, - }, - want: "0x", - }, - // Invalid call without state overriding - { - blockNumber: rpc.LatestBlockNumber, - call: TransactionArgs{ - From: &randomAccounts[0].addr, - To: &randomAccounts[1].addr, - Value: (*hexutil.Big)(big.NewInt(1000)), - }, - expectErr: core.ErrInsufficientFunds, - }, - // Successful simple contract call - // - // // SPDX-License-Identifier: GPL-3.0 - // - // pragma solidity >=0.7.0 <0.8.0; - // - // /** - // * @title Storage - // * @dev Store & retrieve value in a variable - // */ - // contract Storage { - // uint256 public number; - // constructor() { - // number = block.number; - // } - // } - { - blockNumber: rpc.LatestBlockNumber, - call: TransactionArgs{ - From: &randomAccounts[0].addr, - To: &randomAccounts[2].addr, - Data: hex2Bytes("8381f58a"), // call number() - }, - overrides: StateOverride{ - randomAccounts[2].addr: OverrideAccount{ - Code: hex2Bytes("6080604052348015600f57600080fd5b506004361060285760003560e01c80638381f58a14602d575b600080fd5b60336049565b6040518082815260200191505060405180910390f35b6000548156fea2646970667358221220eab35ffa6ab2adfe380772a48b8ba78e82a1b820a18fcb6f59aa4efb20a5f60064736f6c63430007040033"), - StateDiff: &map[common.Hash]common.Hash{common.Hash{}: common.BigToHash(big.NewInt(123))}, - }, - }, - want: "0x000000000000000000000000000000000000000000000000000000000000007b", - }, - // Block overrides should work - { - blockNumber: rpc.LatestBlockNumber, - call: TransactionArgs{ - From: &accounts[1].addr, - Input: &hexutil.Bytes{ - 0x43, // NUMBER - 0x60, 0x00, 0x52, // MSTORE offset 0 - 0x60, 0x20, 0x60, 0x00, 0xf3, - }, - }, - blockOverrides: BlockOverrides{Number: (*hexutil.Big)(big.NewInt(11))}, - want: "0x000000000000000000000000000000000000000000000000000000000000000b", - }, - } - for i, tc := range testSuite { - result, err := api.Call(context.Background(), tc.call, rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, &tc.overrides, &tc.blockOverrides) - if tc.expectErr != nil { - if err == nil { - t.Errorf("test %d: want error %v, have nothing", i, tc.expectErr) - continue - } - if !errors.Is(err, tc.expectErr) { - // Second try - if !reflect.DeepEqual(err, tc.expectErr) { - t.Errorf("test %d: error mismatch, want %v, have %v", i, tc.expectErr, err) - } - } - continue - } - if err != nil { - t.Errorf("test %d: want no error, have %v", i, err) - continue - } - if !reflect.DeepEqual(result.String(), tc.want) { - t.Errorf("test %d, result mismatch, have\n%v\n, want\n%v\n", i, result.String(), tc.want) - } - } -} - -type Account struct { - key *ecdsa.PrivateKey - addr common.Address -} - -type Accounts []Account - -func (a Accounts) Len() int { return len(a) } -func (a Accounts) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -func (a Accounts) Less(i, j int) bool { return bytes.Compare(a[i].addr.Bytes(), a[j].addr.Bytes()) < 0 } - -func newAccounts(n int) (accounts Accounts) { - for i := 0; i < n; i++ { - key, _ := crypto.GenerateKey() - addr := crypto.PubkeyToAddress(key.PublicKey) - accounts = append(accounts, Account{key: key, addr: addr}) - } - sort.Sort(accounts) - return accounts -} - -func newRPCBalance(balance *big.Int) **hexutil.Big { - rpcBalance := (*hexutil.Big)(balance) - return &rpcBalance -} - -func hex2Bytes(str string) *hexutil.Bytes { - rpcBytes := hexutil.Bytes(common.Hex2Bytes(str)) - return &rpcBytes -} diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index 3e4ee505f3892..0249c8664d3c1 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -68,7 +68,7 @@ type Backend interface { PendingBlockAndReceipts() (*types.Block, types.Receipts) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) GetTd(ctx context.Context, hash common.Hash) *big.Int - GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) (*vm.EVM, func() error, error) + GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription diff --git a/internal/ethapi/transaction_args_test.go b/internal/ethapi/transaction_args_test.go index 124f2164cf0a7..24c15b7775601 100644 --- a/internal/ethapi/transaction_args_test.go +++ b/internal/ethapi/transaction_args_test.go @@ -305,7 +305,7 @@ func (b *backendMock) GetLogs(ctx context.Context, blockHash common.Hash, number 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, blockCtx *vm.BlockContext) (*vm.EVM, func() error, error) { +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 } diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index 336632964321d..388eed8a2fa6f 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -608,8 +608,8 @@ web3._extend({ new web3._extend.Method({ name: 'call', call: 'eth_call', - params: 4, - inputFormatter: [web3._extend.formatters.inputCallFormatter, web3._extend.formatters.inputDefaultBlockNumberFormatter, null, null], + params: 3, + inputFormatter: [web3._extend.formatters.inputCallFormatter, web3._extend.formatters.inputDefaultBlockNumberFormatter, null], }), ], properties: [ diff --git a/les/api_backend.go b/les/api_backend.go index 86da26da65f53..2d1fccd9ad43f 100644 --- a/les/api_backend.go +++ b/les/api_backend.go @@ -184,15 +184,12 @@ func (b *LesApiBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int { return nil } -func (b *LesApiBackend) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) (*vm.EVM, func() error, error) { +func (b *LesApiBackend) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) { if vmConfig == nil { vmConfig = new(vm.Config) } txContext := core.NewEVMTxContext(msg) context := core.NewEVMBlockContext(header, b.eth.blockchain, nil) - if blockCtx != nil { - context = *blockCtx - } return vm.NewEVM(context, txContext, state, b.eth.chainConfig, *vmConfig), state.Error, nil }