Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

core/vm: remove interface Interpreter #642

Merged
merged 1 commit into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 8 additions & 38 deletions core/vm/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
package vm

import (
"errors"
"math/big"
"sync/atomic"
"time"
Expand Down Expand Up @@ -61,29 +60,6 @@ func (evm *EVM) precompile(addr common.Address) (PrecompiledContract, bool) {
return p, ok
}

// run runs the given contract and takes care of running precompiles with a fallback to the byte code interpreter.
func run(evm *EVM, contract *Contract, input []byte, readOnly bool) ([]byte, error) {
if evm.ChainConfig().IsTIPXDCXCancellationFee(evm.Context.BlockNumber) {
for _, interpreter := range evm.interpreters {
if interpreter.CanRun(contract.Code) {
if evm.interpreter != interpreter {
// Ensure that the interpreter pointer is set back
// to its current value upon return.
defer func(i Interpreter) {
evm.interpreter = i
}(evm.interpreter)
evm.interpreter = interpreter
}
return interpreter.Run(contract, input, readOnly)
}
}
} else {
return evm.interpreter.Run(contract, input, false)
}

return nil, errors.New("no compatible interpreter")
}

// BlockContext provides the EVM with auxiliary information. Once provided
// it shouldn't be modified.
type BlockContext struct {
Expand Down Expand Up @@ -143,8 +119,7 @@ type EVM struct {
Config Config
// global (to this context) ethereum virtual machine
// used throughout the execution of the tx.
interpreters []Interpreter
interpreter Interpreter
interpreter *EVMInterpreter
// abort is used to abort the EVM calling operations
// NOTE: must be set atomically
abort int32
Expand All @@ -165,14 +140,9 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, tradingStat
Config: config,
chainConfig: chainConfig,
chainRules: chainConfig.Rules(blockCtx.BlockNumber),
interpreters: make([]Interpreter, 0, 1),
}

// 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, config))
evm.interpreter = evm.interpreters[0]

evm.interpreter = NewEVMInterpreter(evm, config)
return evm
}

Expand All @@ -195,7 +165,7 @@ func (evm *EVM) Cancelled() bool {
}

// Interpreter returns the current interpreter
func (evm *EVM) Interpreter() Interpreter {
func (evm *EVM) Interpreter() *EVMInterpreter {
return evm.interpreter
}

Expand Down Expand Up @@ -264,7 +234,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
// The depth-check is already done, and precompiles handled above
contract := NewContract(caller, AccountRef(addrCopy), value, gas)
contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), code)
ret, err = run(evm, contract, input, false)
ret, err = evm.interpreter.Run(contract, input, false)
gas = contract.Gas
}
}
Expand Down Expand Up @@ -321,7 +291,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
// The contract is a scoped environment for this execution context only.
contract := NewContract(caller, AccountRef(caller.Address()), value, gas)
contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), evm.StateDB.GetCode(addrCopy))
ret, err = run(evm, contract, input, false)
ret, err = evm.interpreter.Run(contract, input, false)
gas = contract.Gas
}
if err != nil {
Expand Down Expand Up @@ -361,7 +331,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
// Initialise a new contract and make initialise the delegate values
contract := NewContract(caller, AccountRef(caller.Address()), nil, gas).AsDelegate()
contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), evm.StateDB.GetCode(addrCopy))
ret, err = run(evm, contract, input, false)
ret, err = evm.interpreter.Run(contract, input, false)
gas = contract.Gas
}
if err != nil {
Expand Down Expand Up @@ -418,7 +388,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
// above we revert to the snapshot and consume any gas remaining. Additionally
// when we're in Homestead this also counts for code storage gas errors.
readOnly := evm.ChainConfig().IsTIPXDCXCancellationFee(evm.Context.BlockNumber)
ret, err = run(evm, contract, input, readOnly)
ret, err = evm.interpreter.Run(contract, input, readOnly)
gas = contract.Gas
}
if err != nil {
Expand Down Expand Up @@ -489,7 +459,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
}
start := time.Now()

ret, err := run(evm, contract, nil, false)
ret, err := evm.interpreter.Run(contract, nil, false)

// Check whether the max code size has been exceeded, assign err if the case.
if err == nil && evm.chainRules.IsEIP158 && len(ret) > params.MaxCodeSize {
Expand Down
4 changes: 2 additions & 2 deletions core/vm/instructions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ func testTwoOperandOp(t *testing.T, tests []TwoOperandTestcase, opFn executionFu
env = NewEVM(BlockContext{}, TxContext{}, nil, nil, params.TestChainConfig, Config{})
stack = newstack()
pc = uint64(0)
evmInterpreter = env.interpreter.(*EVMInterpreter)
evmInterpreter = env.interpreter
)

for i, test := range tests {
Expand Down Expand Up @@ -249,7 +249,7 @@ func TestWriteExpectedValues(t *testing.T) {
env = NewEVM(BlockContext{}, TxContext{}, nil, nil, params.TestChainConfig, Config{})
stack = newstack()
pc = uint64(0)
interpreter = env.interpreter.(*EVMInterpreter)
interpreter = env.interpreter
)
result := make([]TwoOperandTestcase, len(args))
for i, param := range args {
Expand Down
31 changes: 0 additions & 31 deletions core/vm/interpreter.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,34 +32,9 @@ type Config struct {

JumpTable *JumpTable // EVM instruction table, automatically populated if unset

EWASMInterpreter string // External EWASM interpreter options
EVMInterpreter string // External EVM interpreter options

ExtraEips []int // Additional EIPS that are to be enabled
}

// Interpreter is used to run Ethereum based contracts and will utilise the
// passed environment to query external sources for state information.
// The Interpreter will run the byte code VM based on the passed
// configuration.
type Interpreter interface {
// Run loops and evaluates the contract's code with the given input data and returns
// the return byte-slice and an error if one occurred.
Run(contract *Contract, input []byte, static bool) ([]byte, error)
// CanRun tells if the contract, passed as an argument, can be
// run by the current interpreter. This is meant so that the
// caller can do something like:
//
// ```golang
// for _, interpreter := range interpreters {
// if interpreter.CanRun(contract.code) {
// interpreter.Run(contract.code, input)
// }
// }
// ```
CanRun([]byte) bool
}

// ScopeContext contains the things that are per-call, such as stack and memory,
// but not transients like pc and gas
type ScopeContext struct {
Expand Down Expand Up @@ -274,9 +249,3 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (

return res, err
}

// CanRun tells if the contract, passed as an argument, can be
// run by the current interpreter.
func (in *EVMInterpreter) CanRun(code []byte) bool {
return true
}
10 changes: 7 additions & 3 deletions tests/state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,17 +74,21 @@ func TestState(t *testing.T) {
const traceErrorLimit = 400000

func withTrace(t *testing.T, gasLimit uint64, test func(vm.Config) error) {
err := test(vm.Config{})
// Use config from command line arguments.
config := vm.Config{}
err := test(config)
if err == nil {
return
}
t.Error(err)

// Test failed, re-run with tracing enabled.
if gasLimit > traceErrorLimit {
t.Log("gas limit too high for EVM trace")
return
}
tracer := vm.NewStructLogger(nil)
err2 := test(vm.Config{Debug: true, Tracer: tracer})
config.Debug, config.Tracer = true, tracer
err2 := test(config)
if !reflect.DeepEqual(err, err2) {
t.Errorf("different error for second run: %v", err2)
}
Expand Down