internal/ethapi: add block overrides to eth_call (#26414)
Adds an optional config parameter to eth_call which allows users to override block context fields (same functionality that was added to traceCall in #24871) --------- Co-authored-by: Martin Holst Swende <martin@swende.se>
This commit is contained in:
co-authored by
Martin Holst Swende
parent
52c246fac3
commit
ae66009640
+43
-6
@@ -33,6 +33,7 @@ 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"
|
||||
@@ -955,7 +956,39 @@ func (diff *BlockOverrides) Apply(blockCtx *vm.BlockContext) {
|
||||
}
|
||||
}
|
||||
|
||||
func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride, timeout time.Duration, globalGasCap uint64) (*core.ExecutionResult, error) {
|
||||
// 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) {
|
||||
defer func(start time.Time) { log.Debug("Executing EVM call finished", "runtime", time.Since(start)) }(time.Now())
|
||||
|
||||
state, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
||||
@@ -982,7 +1015,11 @@ func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
evm, vmError, err := b.GetEVM(ctx, msg, state, header, &vm.Config{NoBaseFee: true})
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1046,8 +1083,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) (hexutil.Bytes, error) {
|
||||
result, err := DoCall(ctx, s.b, args, blockNrOrHash, overrides, s.b.RPCEVMTimeout(), s.b.RPCGasCap())
|
||||
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())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1132,7 +1169,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, 0, gasCap)
|
||||
result, err := DoCall(ctx, b, args, blockNrOrHash, nil, nil, 0, gasCap)
|
||||
if err != nil {
|
||||
if errors.Is(err, core.ErrIntrinsicGas) {
|
||||
return true, nil, nil // Special case, raise gas limit
|
||||
@@ -1478,7 +1515,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)
|
||||
vmenv, _, err := b.GetEVM(ctx, msg, statedb, header, &config, nil)
|
||||
if err != nil {
|
||||
return nil, 0, nil, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user