mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-18 10:50:44 +00:00
Merge pull request #642 from gzliudan/rm-ewasm
core/vm: remove interface Interpreter
This commit is contained in:
commit
d7e72f3e71
4 changed files with 17 additions and 74 deletions
|
|
@ -17,7 +17,6 @@
|
||||||
package vm
|
package vm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -61,29 +60,6 @@ func (evm *EVM) precompile(addr common.Address) (PrecompiledContract, bool) {
|
||||||
return p, ok
|
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
|
// BlockContext provides the EVM with auxiliary information. Once provided
|
||||||
// it shouldn't be modified.
|
// it shouldn't be modified.
|
||||||
type BlockContext struct {
|
type BlockContext struct {
|
||||||
|
|
@ -143,8 +119,7 @@ type EVM struct {
|
||||||
Config Config
|
Config Config
|
||||||
// global (to this context) ethereum virtual machine
|
// global (to this context) ethereum virtual machine
|
||||||
// used throughout the execution of the tx.
|
// used throughout the execution of the tx.
|
||||||
interpreters []Interpreter
|
interpreter *EVMInterpreter
|
||||||
interpreter Interpreter
|
|
||||||
// abort is used to abort the EVM calling operations
|
// abort is used to abort the EVM calling operations
|
||||||
// NOTE: must be set atomically
|
// NOTE: must be set atomically
|
||||||
abort int32
|
abort int32
|
||||||
|
|
@ -165,14 +140,9 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, tradingStat
|
||||||
Config: config,
|
Config: config,
|
||||||
chainConfig: chainConfig,
|
chainConfig: chainConfig,
|
||||||
chainRules: chainConfig.Rules(blockCtx.BlockNumber),
|
chainRules: chainConfig.Rules(blockCtx.BlockNumber),
|
||||||
interpreters: make([]Interpreter, 0, 1),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// vmConfig.EVMInterpreter will be used by EVM-C, it won't be checked here
|
evm.interpreter = NewEVMInterpreter(evm, config)
|
||||||
// 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]
|
|
||||||
|
|
||||||
return evm
|
return evm
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -195,7 +165,7 @@ func (evm *EVM) Cancelled() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interpreter returns the current interpreter
|
// Interpreter returns the current interpreter
|
||||||
func (evm *EVM) Interpreter() Interpreter {
|
func (evm *EVM) Interpreter() *EVMInterpreter {
|
||||||
return evm.interpreter
|
return evm.interpreter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -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
|
// The depth-check is already done, and precompiles handled above
|
||||||
contract := NewContract(caller, AccountRef(addrCopy), value, gas)
|
contract := NewContract(caller, AccountRef(addrCopy), value, gas)
|
||||||
contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), code)
|
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
|
gas = contract.Gas
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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.
|
// The contract is a scoped environment for this execution context only.
|
||||||
contract := NewContract(caller, AccountRef(caller.Address()), value, gas)
|
contract := NewContract(caller, AccountRef(caller.Address()), value, gas)
|
||||||
contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), evm.StateDB.GetCode(addrCopy))
|
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
|
gas = contract.Gas
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -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
|
// Initialise a new contract and make initialise the delegate values
|
||||||
contract := NewContract(caller, AccountRef(caller.Address()), nil, gas).AsDelegate()
|
contract := NewContract(caller, AccountRef(caller.Address()), nil, gas).AsDelegate()
|
||||||
contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), evm.StateDB.GetCode(addrCopy))
|
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
|
gas = contract.Gas
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -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
|
// 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.
|
// when we're in Homestead this also counts for code storage gas errors.
|
||||||
readOnly := evm.ChainConfig().IsTIPXDCXCancellationFee(evm.Context.BlockNumber)
|
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
|
gas = contract.Gas
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -489,7 +459,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
|
||||||
}
|
}
|
||||||
start := time.Now()
|
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.
|
// Check whether the max code size has been exceeded, assign err if the case.
|
||||||
if err == nil && evm.chainRules.IsEIP158 && len(ret) > params.MaxCodeSize {
|
if err == nil && evm.chainRules.IsEIP158 && len(ret) > params.MaxCodeSize {
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,7 @@ func testTwoOperandOp(t *testing.T, tests []TwoOperandTestcase, opFn executionFu
|
||||||
env = NewEVM(BlockContext{}, TxContext{}, nil, nil, params.TestChainConfig, Config{})
|
env = NewEVM(BlockContext{}, TxContext{}, nil, nil, params.TestChainConfig, Config{})
|
||||||
stack = newstack()
|
stack = newstack()
|
||||||
pc = uint64(0)
|
pc = uint64(0)
|
||||||
evmInterpreter = env.interpreter.(*EVMInterpreter)
|
evmInterpreter = env.interpreter
|
||||||
)
|
)
|
||||||
|
|
||||||
for i, test := range tests {
|
for i, test := range tests {
|
||||||
|
|
@ -249,7 +249,7 @@ func TestWriteExpectedValues(t *testing.T) {
|
||||||
env = NewEVM(BlockContext{}, TxContext{}, nil, nil, params.TestChainConfig, Config{})
|
env = NewEVM(BlockContext{}, TxContext{}, nil, nil, params.TestChainConfig, Config{})
|
||||||
stack = newstack()
|
stack = newstack()
|
||||||
pc = uint64(0)
|
pc = uint64(0)
|
||||||
interpreter = env.interpreter.(*EVMInterpreter)
|
interpreter = env.interpreter
|
||||||
)
|
)
|
||||||
result := make([]TwoOperandTestcase, len(args))
|
result := make([]TwoOperandTestcase, len(args))
|
||||||
for i, param := range args {
|
for i, param := range args {
|
||||||
|
|
|
||||||
|
|
@ -32,34 +32,9 @@ type Config struct {
|
||||||
|
|
||||||
JumpTable *JumpTable // EVM instruction table, automatically populated if unset
|
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
|
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,
|
// ScopeContext contains the things that are per-call, such as stack and memory,
|
||||||
// but not transients like pc and gas
|
// but not transients like pc and gas
|
||||||
type ScopeContext struct {
|
type ScopeContext struct {
|
||||||
|
|
@ -274,9 +249,3 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
|
||||||
|
|
||||||
return res, err
|
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
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -74,17 +74,21 @@ func TestState(t *testing.T) {
|
||||||
const traceErrorLimit = 400000
|
const traceErrorLimit = 400000
|
||||||
|
|
||||||
func withTrace(t *testing.T, gasLimit uint64, test func(vm.Config) error) {
|
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 {
|
if err == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
t.Error(err)
|
|
||||||
|
// Test failed, re-run with tracing enabled.
|
||||||
if gasLimit > traceErrorLimit {
|
if gasLimit > traceErrorLimit {
|
||||||
t.Log("gas limit too high for EVM trace")
|
t.Log("gas limit too high for EVM trace")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
tracer := vm.NewStructLogger(nil)
|
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) {
|
if !reflect.DeepEqual(err, err2) {
|
||||||
t.Errorf("different error for second run: %v", err2)
|
t.Errorf("different error for second run: %v", err2)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue