|
|
|
@ -17,7 +17,6 @@ |
|
|
|
|
package vm |
|
|
|
|
|
|
|
|
|
import ( |
|
|
|
|
"errors" |
|
|
|
|
"math/big" |
|
|
|
|
"sync/atomic" |
|
|
|
|
"time" |
|
|
|
@ -58,24 +57,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) { |
|
|
|
|
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) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return nil, errors.New("no compatible interpreter") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// BlockContext provides the EVM with auxiliary information. Once provided
|
|
|
|
|
// it shouldn't be modified.
|
|
|
|
|
type BlockContext struct { |
|
|
|
@ -131,8 +112,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 |
|
|
|
@ -146,36 +126,14 @@ type EVM struct { |
|
|
|
|
// only ever be used *once*.
|
|
|
|
|
func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig *params.ChainConfig, config Config) *EVM { |
|
|
|
|
evm := &EVM{ |
|
|
|
|
Context: blockCtx, |
|
|
|
|
TxContext: txCtx, |
|
|
|
|
StateDB: statedb, |
|
|
|
|
Config: config, |
|
|
|
|
chainConfig: chainConfig, |
|
|
|
|
chainRules: chainConfig.Rules(blockCtx.BlockNumber), |
|
|
|
|
interpreters: make([]Interpreter, 0, 1), |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if chainConfig.IsEWASM(blockCtx.BlockNumber) { |
|
|
|
|
// to be implemented by EVM-C and Wagon PRs.
|
|
|
|
|
// if vmConfig.EWASMInterpreter != "" {
|
|
|
|
|
// extIntOpts := strings.Split(vmConfig.EWASMInterpreter, ":")
|
|
|
|
|
// path := extIntOpts[0]
|
|
|
|
|
// options := []string{}
|
|
|
|
|
// if len(extIntOpts) > 1 {
|
|
|
|
|
// options = extIntOpts[1..]
|
|
|
|
|
// }
|
|
|
|
|
// evm.interpreters = append(evm.interpreters, NewEVMVCInterpreter(evm, vmConfig, options))
|
|
|
|
|
// } else {
|
|
|
|
|
// evm.interpreters = append(evm.interpreters, NewEWASMInterpreter(evm, vmConfig))
|
|
|
|
|
// }
|
|
|
|
|
panic("No supported ewasm interpreter yet.") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 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] |
|
|
|
|
|
|
|
|
|
Context: blockCtx, |
|
|
|
|
TxContext: txCtx, |
|
|
|
|
StateDB: statedb, |
|
|
|
|
Config: config, |
|
|
|
|
chainConfig: chainConfig, |
|
|
|
|
chainRules: chainConfig.Rules(blockCtx.BlockNumber), |
|
|
|
|
} |
|
|
|
|
evm.interpreter = NewEVMInterpreter(evm, config) |
|
|
|
|
return evm |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -198,7 +156,7 @@ func (evm *EVM) Cancelled() bool { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Interpreter returns the current interpreter
|
|
|
|
|
func (evm *EVM) Interpreter() Interpreter { |
|
|
|
|
func (evm *EVM) Interpreter() *EVMInterpreter { |
|
|
|
|
return evm.interpreter |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -256,7 +214,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 |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -308,7 +266,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 { |
|
|
|
@ -343,7 +301,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 { |
|
|
|
@ -394,7 +352,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte |
|
|
|
|
// When an error was returned by the EVM or when setting the creation code
|
|
|
|
|
// 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.
|
|
|
|
|
ret, err = run(evm, contract, input, true) |
|
|
|
|
ret, err = evm.interpreter.Run(contract, input, true) |
|
|
|
|
gas = contract.Gas |
|
|
|
|
} |
|
|
|
|
if err != nil { |
|
|
|
@ -462,7 +420,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 { |
|
|
|
|