mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-19 21:31:37 +00:00
core, internal: support various eth_call invocations post 1559 (#23027)
This commit is contained in:
parent
ef1dbd0772
commit
18bc355e89
9 changed files with 73 additions and 61 deletions
|
|
@ -223,23 +223,26 @@ func (st *StateTransition) preCheck() error {
|
|||
}
|
||||
// Make sure that transaction gasFeeCap is greater than the baseFee (post london)
|
||||
if st.evm.ChainConfig().IsEIP1559(st.evm.Context.BlockNumber) {
|
||||
if l := st.gasFeeCap.BitLen(); l > 256 {
|
||||
return fmt.Errorf("%w: address %v, maxFeePerGas bit length: %d", ErrFeeCapVeryHigh,
|
||||
msg.From().Hex(), l)
|
||||
}
|
||||
if l := st.gasTipCap.BitLen(); l > 256 {
|
||||
return fmt.Errorf("%w: address %v, maxPriorityFeePerGas bit length: %d", ErrTipVeryHigh,
|
||||
msg.From().Hex(), l)
|
||||
}
|
||||
if st.gasFeeCap.Cmp(st.gasTipCap) < 0 {
|
||||
return fmt.Errorf("%w: address %v, maxPriorityFeePerGas: %s, maxFeePerGas: %s", ErrTipAboveFeeCap,
|
||||
msg.From().Hex(), st.gasTipCap, st.gasFeeCap)
|
||||
}
|
||||
// This will panic if baseFee is nil, but basefee presence is verified
|
||||
// as part of header validation.
|
||||
if st.gasFeeCap.Cmp(st.evm.Context.BaseFee) < 0 {
|
||||
return fmt.Errorf("%w: address %v, maxFeePerGas: %s baseFee: %s", ErrFeeCapTooLow,
|
||||
msg.From().Hex(), st.gasFeeCap, st.evm.Context.BaseFee)
|
||||
// Skip the checks if gas fields are zero and baseFee was explicitly disabled (eth_call)
|
||||
if !st.evm.Config.NoBaseFee || st.gasFeeCap.BitLen() > 0 || st.gasTipCap.BitLen() > 0 {
|
||||
if l := st.gasFeeCap.BitLen(); l > 256 {
|
||||
return fmt.Errorf("%w: address %v, maxFeePerGas bit length: %d", ErrFeeCapVeryHigh,
|
||||
msg.From().Hex(), l)
|
||||
}
|
||||
if l := st.gasTipCap.BitLen(); l > 256 {
|
||||
return fmt.Errorf("%w: address %v, maxPriorityFeePerGas bit length: %d", ErrTipVeryHigh,
|
||||
msg.From().Hex(), l)
|
||||
}
|
||||
if st.gasFeeCap.Cmp(st.gasTipCap) < 0 {
|
||||
return fmt.Errorf("%w: address %v, maxPriorityFeePerGas: %s, maxFeePerGas: %s", ErrTipAboveFeeCap,
|
||||
msg.From().Hex(), st.gasTipCap, st.gasFeeCap)
|
||||
}
|
||||
// This will panic if baseFee is nil, but basefee presence is verified
|
||||
// as part of header validation.
|
||||
if st.gasFeeCap.Cmp(st.evm.Context.BaseFee) < 0 {
|
||||
return fmt.Errorf("%w: address %v, maxFeePerGas: %s baseFee: %s", ErrFeeCapTooLow,
|
||||
msg.From().Hex(), st.gasFeeCap, st.evm.Context.BaseFee)
|
||||
}
|
||||
}
|
||||
}
|
||||
return st.buyGas()
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ type EVM struct {
|
|||
chainRules params.Rules
|
||||
// virtual machine configuration options used to initialise the
|
||||
// evm.
|
||||
vmConfig Config
|
||||
Config Config
|
||||
// global (to this context) ethereum virtual machine
|
||||
// used throughout the execution of the tx.
|
||||
interpreters []Interpreter
|
||||
|
|
@ -156,13 +156,13 @@ type EVM struct {
|
|||
|
||||
// NewEVM returns a new EVM. The returned EVM is not thread safe and should
|
||||
// only ever be used *once*.
|
||||
func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, tradingStateDB *tradingstate.TradingStateDB, chainConfig *params.ChainConfig, vmConfig Config) *EVM {
|
||||
func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, tradingStateDB *tradingstate.TradingStateDB, chainConfig *params.ChainConfig, config Config) *EVM {
|
||||
evm := &EVM{
|
||||
Context: blockCtx,
|
||||
TxContext: txCtx,
|
||||
StateDB: statedb,
|
||||
tradingStateDB: tradingStateDB,
|
||||
vmConfig: vmConfig,
|
||||
Config: config,
|
||||
chainConfig: chainConfig,
|
||||
chainRules: chainConfig.Rules(blockCtx.BlockNumber),
|
||||
interpreters: make([]Interpreter, 0, 1),
|
||||
|
|
@ -170,7 +170,7 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, tradingStat
|
|||
|
||||
// vmConfig.EVMInterpreter will be used by EVM-C, it won't be checked here
|
||||
// as we always want to have the built-in EVM as the failover option.
|
||||
evm.interpreters = append(evm.interpreters, NewEVMInterpreter(evm, vmConfig))
|
||||
evm.interpreters = append(evm.interpreters, NewEVMInterpreter(evm, config))
|
||||
evm.interpreter = evm.interpreters[0]
|
||||
|
||||
return evm
|
||||
|
|
@ -218,13 +218,13 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
|
|||
if !evm.StateDB.Exist(addr) {
|
||||
if !isPrecompile && evm.chainRules.IsEIP158 && value.Sign() == 0 {
|
||||
// Calling a non existing account, don't do anything, but ping the tracer
|
||||
if evm.vmConfig.Debug {
|
||||
if evm.Config.Debug {
|
||||
if evm.depth == 0 {
|
||||
evm.vmConfig.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value)
|
||||
evm.vmConfig.Tracer.CaptureEnd(ret, 0, 0, nil)
|
||||
evm.Config.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value)
|
||||
evm.Config.Tracer.CaptureEnd(ret, 0, 0, nil)
|
||||
} else {
|
||||
evm.vmConfig.Tracer.CaptureEnter(CALL, caller.Address(), addr, input, gas, value)
|
||||
evm.vmConfig.Tracer.CaptureExit(ret, 0, nil)
|
||||
evm.Config.Tracer.CaptureEnter(CALL, caller.Address(), addr, input, gas, value)
|
||||
evm.Config.Tracer.CaptureExit(ret, 0, nil)
|
||||
}
|
||||
}
|
||||
return nil, gas, nil
|
||||
|
|
@ -234,18 +234,18 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
|
|||
evm.Context.Transfer(evm.StateDB, caller.Address(), addr, value)
|
||||
|
||||
// Capture the tracer start/end events in debug mode
|
||||
if evm.vmConfig.Debug {
|
||||
if evm.Config.Debug {
|
||||
if evm.depth == 0 {
|
||||
evm.vmConfig.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value)
|
||||
evm.Config.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value)
|
||||
|
||||
defer func(startGas uint64, startTime time.Time) { // Lazy evaluation of the parameters
|
||||
evm.vmConfig.Tracer.CaptureEnd(ret, startGas-gas, time.Since(startTime), err)
|
||||
evm.Config.Tracer.CaptureEnd(ret, startGas-gas, time.Since(startTime), err)
|
||||
}(gas, time.Now())
|
||||
} else {
|
||||
// Handle tracer events for entering and exiting a call frame
|
||||
evm.vmConfig.Tracer.CaptureEnter(CALL, caller.Address(), addr, input, gas, value)
|
||||
evm.Config.Tracer.CaptureEnter(CALL, caller.Address(), addr, input, gas, value)
|
||||
defer func(startGas uint64) {
|
||||
evm.vmConfig.Tracer.CaptureExit(ret, startGas-gas, err)
|
||||
evm.Config.Tracer.CaptureExit(ret, startGas-gas, err)
|
||||
}(gas)
|
||||
}
|
||||
}
|
||||
|
|
@ -305,10 +305,10 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
|
|||
var snapshot = evm.StateDB.Snapshot()
|
||||
|
||||
// Invoke tracer hooks that signal entering/exiting a call frame
|
||||
if evm.vmConfig.Debug {
|
||||
evm.vmConfig.Tracer.CaptureEnter(CALLCODE, caller.Address(), addr, input, gas, value)
|
||||
if evm.Config.Debug {
|
||||
evm.Config.Tracer.CaptureEnter(CALLCODE, caller.Address(), addr, input, gas, value)
|
||||
defer func(startGas uint64) {
|
||||
evm.vmConfig.Tracer.CaptureExit(ret, startGas-gas, err)
|
||||
evm.Config.Tracer.CaptureExit(ret, startGas-gas, err)
|
||||
}(gas)
|
||||
}
|
||||
|
||||
|
|
@ -346,10 +346,10 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
|
|||
var snapshot = evm.StateDB.Snapshot()
|
||||
|
||||
// Invoke tracer hooks that signal entering/exiting a call frame
|
||||
if evm.vmConfig.Debug {
|
||||
evm.vmConfig.Tracer.CaptureEnter(DELEGATECALL, caller.Address(), addr, input, gas, nil)
|
||||
if evm.Config.Debug {
|
||||
evm.Config.Tracer.CaptureEnter(DELEGATECALL, caller.Address(), addr, input, gas, nil)
|
||||
defer func(startGas uint64) {
|
||||
evm.vmConfig.Tracer.CaptureExit(ret, startGas-gas, err)
|
||||
evm.Config.Tracer.CaptureExit(ret, startGas-gas, err)
|
||||
}(gas)
|
||||
}
|
||||
|
||||
|
|
@ -396,10 +396,10 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
|
|||
evm.StateDB.AddBalance(addr, big0)
|
||||
|
||||
// Invoke tracer hooks that signal entering/exiting a call frame
|
||||
if evm.vmConfig.Debug {
|
||||
evm.vmConfig.Tracer.CaptureEnter(STATICCALL, caller.Address(), addr, input, gas, nil)
|
||||
if evm.Config.Debug {
|
||||
evm.Config.Tracer.CaptureEnter(STATICCALL, caller.Address(), addr, input, gas, nil)
|
||||
defer func(startGas uint64) {
|
||||
evm.vmConfig.Tracer.CaptureExit(ret, startGas-gas, err)
|
||||
evm.Config.Tracer.CaptureExit(ret, startGas-gas, err)
|
||||
}(gas)
|
||||
}
|
||||
|
||||
|
|
@ -480,11 +480,11 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
|
|||
contract := NewContract(caller, AccountRef(address), value, gas)
|
||||
contract.SetCodeOptionalHash(&address, codeAndHash)
|
||||
|
||||
if evm.vmConfig.Debug {
|
||||
if evm.Config.Debug {
|
||||
if evm.depth == 0 {
|
||||
evm.vmConfig.Tracer.CaptureStart(evm, caller.Address(), address, true, codeAndHash.code, gas, value)
|
||||
evm.Config.Tracer.CaptureStart(evm, caller.Address(), address, true, codeAndHash.code, gas, value)
|
||||
} else {
|
||||
evm.vmConfig.Tracer.CaptureEnter(typ, caller.Address(), address, codeAndHash.code, gas, value)
|
||||
evm.Config.Tracer.CaptureEnter(typ, caller.Address(), address, codeAndHash.code, gas, value)
|
||||
}
|
||||
}
|
||||
start := time.Now()
|
||||
|
|
@ -524,11 +524,11 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
|
|||
}
|
||||
}
|
||||
|
||||
if evm.vmConfig.Debug {
|
||||
if evm.Config.Debug {
|
||||
if evm.depth == 0 {
|
||||
evm.vmConfig.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err)
|
||||
evm.Config.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err)
|
||||
} else {
|
||||
evm.vmConfig.Tracer.CaptureExit(ret, gas-contract.Gas, err)
|
||||
evm.Config.Tracer.CaptureExit(ret, gas-contract.Gas, err)
|
||||
}
|
||||
}
|
||||
return ret, address, contract.Gas, err
|
||||
|
|
|
|||
|
|
@ -246,7 +246,7 @@ func opKeccak256(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) (
|
|||
interpreter.hasher.Read(interpreter.hasherBuf[:])
|
||||
|
||||
evm := interpreter.evm
|
||||
if evm.vmConfig.EnablePreimageRecording {
|
||||
if evm.Config.EnablePreimageRecording {
|
||||
evm.StateDB.AddPreimage(interpreter.hasherBuf, data)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -194,7 +194,7 @@ func TestAddMod(t *testing.T) {
|
|||
var (
|
||||
env = NewEVM(BlockContext{}, TxContext{}, nil, nil, params.TestChainConfig, Config{})
|
||||
stack = newstack()
|
||||
evmInterpreter = NewEVMInterpreter(env, env.vmConfig)
|
||||
evmInterpreter = NewEVMInterpreter(env, env.Config)
|
||||
pc = uint64(0)
|
||||
)
|
||||
tests := []struct {
|
||||
|
|
@ -290,7 +290,7 @@ func opBenchmark(bench *testing.B, op executionFunc, args ...string) {
|
|||
env = NewEVM(BlockContext{}, TxContext{}, nil, nil, params.TestChainConfig, Config{})
|
||||
stack = newstack()
|
||||
scope = &ScopeContext{nil, stack, nil}
|
||||
evmInterpreter = NewEVMInterpreter(env, env.vmConfig)
|
||||
evmInterpreter = NewEVMInterpreter(env, env.Config)
|
||||
)
|
||||
|
||||
env.interpreter = evmInterpreter
|
||||
|
|
@ -531,7 +531,7 @@ func TestOpMstore(t *testing.T) {
|
|||
env = NewEVM(BlockContext{}, TxContext{}, nil, nil, params.TestChainConfig, Config{})
|
||||
stack = newstack()
|
||||
mem = NewMemory()
|
||||
evmInterpreter = NewEVMInterpreter(env, env.vmConfig)
|
||||
evmInterpreter = NewEVMInterpreter(env, env.Config)
|
||||
)
|
||||
|
||||
env.interpreter = evmInterpreter
|
||||
|
|
@ -557,7 +557,7 @@ func BenchmarkOpMstore(bench *testing.B) {
|
|||
env = NewEVM(BlockContext{}, TxContext{}, nil, nil, params.TestChainConfig, Config{})
|
||||
stack = newstack()
|
||||
mem = NewMemory()
|
||||
evmInterpreter = NewEVMInterpreter(env, env.vmConfig)
|
||||
evmInterpreter = NewEVMInterpreter(env, env.Config)
|
||||
)
|
||||
|
||||
env.interpreter = evmInterpreter
|
||||
|
|
@ -579,7 +579,7 @@ func BenchmarkOpKeccak256(bench *testing.B) {
|
|||
env = NewEVM(BlockContext{}, TxContext{}, nil, nil, params.TestChainConfig, Config{})
|
||||
stack = newstack()
|
||||
mem = NewMemory()
|
||||
evmInterpreter = NewEVMInterpreter(env, env.vmConfig)
|
||||
evmInterpreter = NewEVMInterpreter(env, env.Config)
|
||||
)
|
||||
env.interpreter = evmInterpreter
|
||||
mem.Resize(32)
|
||||
|
|
@ -683,7 +683,7 @@ func TestRandom(t *testing.T) {
|
|||
env = NewEVM(BlockContext{Random: &tt.random}, TxContext{}, nil, nil, params.TestChainConfig, Config{})
|
||||
stack = newstack()
|
||||
pc = uint64(0)
|
||||
evmInterpreter = NewEVMInterpreter(env, env.vmConfig)
|
||||
evmInterpreter = NewEVMInterpreter(env, env.Config)
|
||||
)
|
||||
opRandom(&pc, evmInterpreter, &ScopeContext{nil, stack, nil})
|
||||
if len(stack.data) != 1 {
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import (
|
|||
type Config struct {
|
||||
Debug bool // Enables debugging
|
||||
Tracer EVMLogger // Opcode logger
|
||||
NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls)
|
||||
EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages
|
||||
|
||||
JumpTable *JumpTable // EVM instruction table, automatically populated if unset
|
||||
|
|
|
|||
|
|
@ -1263,7 +1263,7 @@ func (s *PublicBlockChainAPI) getCandidatesFromSmartContract() ([]utils.Masterno
|
|||
return candidatesWithStakeInfo, nil
|
||||
}
|
||||
|
||||
func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride, vmCfg vm.Config, timeout time.Duration, globalGasCap uint64) ([]byte, uint64, bool, error, error) {
|
||||
func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride, timeout time.Duration, globalGasCap uint64) ([]byte, uint64, bool, error, error) {
|
||||
defer func(start time.Time) { log.Debug("Executing EVM call finished", "runtime", time.Since(start)) }(time.Now())
|
||||
|
||||
statedb, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
||||
|
|
@ -1312,7 +1312,7 @@ func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash
|
|||
}
|
||||
|
||||
// Get a new instance of the EVM.
|
||||
evm, vmError, err := b.GetEVM(ctx, msg, statedb, XDCxState, header, &vmCfg)
|
||||
evm, vmError, err := b.GetEVM(ctx, msg, statedb, XDCxState, header, &vm.Config{NoBaseFee: true})
|
||||
if err != nil {
|
||||
return nil, 0, false, err, nil
|
||||
}
|
||||
|
|
@ -1382,7 +1382,7 @@ func (s *PublicBlockChainAPI) Call(ctx context.Context, args TransactionArgs, bl
|
|||
if args.To != nil && *args.To == common.MasternodeVotingSMCBinary {
|
||||
timeout = 0
|
||||
}
|
||||
result, _, failed, err, vmErr := DoCall(ctx, s.b, args, *blockNrOrHash, overrides, vm.Config{}, timeout, s.b.RPCGasCap())
|
||||
result, _, failed, err, vmErr := DoCall(ctx, s.b, args, *blockNrOrHash, overrides, timeout, s.b.RPCGasCap())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -1438,7 +1438,7 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr
|
|||
executable := func(gas uint64) (bool, []byte, error, error) {
|
||||
args.Gas = (*hexutil.Uint64)(&gas)
|
||||
|
||||
res, _, failed, err, vmErr := DoCall(ctx, b, args, blockNrOrHash, nil, vm.Config{}, 0, gasCap)
|
||||
res, _, failed, err, vmErr := DoCall(ctx, b, args, blockNrOrHash, nil, 0, gasCap)
|
||||
if err != nil {
|
||||
if errors.Is(err, vm.ErrOutOfGas) || errors.Is(err, core.ErrIntrinsicGas) {
|
||||
return false, nil, nil, nil // Special case, raise gas limit
|
||||
|
|
|
|||
|
|
@ -159,7 +159,9 @@ func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ToMessage converts TransactionArgs to the Message type used by the core evm
|
||||
// ToMessage converts th transaction arguments to the Message type used by the
|
||||
// core evm. This method is used in calls and traces that do not require a real
|
||||
// live transaction.
|
||||
func (args *TransactionArgs) ToMessage(b Backend, number *big.Int, globalGasCap uint64, baseFee *big.Int) (types.Message, error) {
|
||||
// Reject invalid combinations of pre- and post-1559 fee styles
|
||||
if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) {
|
||||
|
|
@ -207,9 +209,11 @@ func (args *TransactionArgs) ToMessage(b Backend, number *big.Int, globalGasCap
|
|||
} else {
|
||||
// A basefee is provided, necessitating 1559-type execution
|
||||
if args.GasPrice != nil {
|
||||
// User specified the legacy gas field, convert to 1559 gas typing
|
||||
gasPrice = args.GasPrice.ToInt()
|
||||
gasFeeCap, gasTipCap = gasPrice, gasPrice
|
||||
} else {
|
||||
// User specified 1559 gas feilds (or none), use those
|
||||
gasFeeCap = new(big.Int)
|
||||
if args.MaxFeePerGas != nil {
|
||||
gasFeeCap = args.MaxFeePerGas.ToInt()
|
||||
|
|
@ -218,7 +222,11 @@ func (args *TransactionArgs) ToMessage(b Backend, number *big.Int, globalGasCap
|
|||
if args.MaxPriorityFeePerGas != nil {
|
||||
gasTipCap = args.MaxPriorityFeePerGas.ToInt()
|
||||
}
|
||||
gasPrice = math.BigMin(new(big.Int).Add(gasTipCap, baseFee), gasFeeCap)
|
||||
// Backfill the legacy gasPrice for EVM execution, unless we're all zeroes
|
||||
gasPrice = new(big.Int)
|
||||
if gasFeeCap.BitLen() > 0 || gasTipCap.BitLen() > 0 {
|
||||
gasPrice = math.BigMin(new(big.Int).Add(gasTipCap, baseFee), gasFeeCap)
|
||||
}
|
||||
}
|
||||
}
|
||||
value := new(big.Int)
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -3741,7 +3741,7 @@ var inputCallFormatter = function (options){
|
|||
options.to = inputAddressFormatter(options.to);
|
||||
}
|
||||
|
||||
['gasPrice', 'gas', 'value', 'nonce'].filter(function (key) {
|
||||
['maxFeePerGas', 'maxPriorityFeePerGas', 'gasPrice', 'gas', 'value', 'nonce'].filter(function (key) {
|
||||
return options[key] !== undefined;
|
||||
}).forEach(function(key){
|
||||
options[key] = utils.fromDecimal(options[key]);
|
||||
|
|
|
|||
Loading…
Reference in a new issue