aboutsummaryrefslogtreecommitdiffstats
path: root/core/vm/evm/evm.go
diff options
context:
space:
mode:
authorJhih-Ming Huang <jm.huang@cobinhood.com>2019-03-27 18:49:38 +0800
committerJhih-Ming Huang <jm.huang@cobinhood.com>2019-05-06 10:50:26 +0800
commite715414cae9b4654b4784dfb924880a0787d1d55 (patch)
treea0772b2a0ef3be4ac03fc608a21ee0b7ccbd167a /core/vm/evm/evm.go
parent996310cbd484b5ff1ea76068578314d71973770f (diff)
downloaddexon-e715414cae9b4654b4784dfb924880a0787d1d55.tar
dexon-e715414cae9b4654b4784dfb924880a0787d1d55.tar.gz
dexon-e715414cae9b4654b4784dfb924880a0787d1d55.tar.bz2
dexon-e715414cae9b4654b4784dfb924880a0787d1d55.tar.lz
dexon-e715414cae9b4654b4784dfb924880a0787d1d55.tar.xz
dexon-e715414cae9b4654b4784dfb924880a0787d1d55.tar.zst
dexon-e715414cae9b4654b4784dfb924880a0787d1d55.zip
core: vm: refactor vm config and context
To support multiple VMs, there must be a shared execution environment for each VM, so this pull request moved some shared component to vm.Context and implemented the vm.ExecPack to hold the list of VM, list of VM configures, context and some shared resources. The adjustment includes: * Move NoRecursion, Depth, ReadOnly, RandCallIndex, IntPool and CallGasTemp to Context. * Adjust VM enumeration from byte to uint8, and the VMList from map to array. * Register VM constructor in each VM package's init function. * Initialize all VM instance in NewExecPack. * Remove EVMImplement, and modify EVM, such that EVM can do the same functions with EVMImplement.
Diffstat (limited to 'core/vm/evm/evm.go')
-rw-r--r--core/vm/evm/evm.go114
1 files changed, 35 insertions, 79 deletions
diff --git a/core/vm/evm/evm.go b/core/vm/evm/evm.go
index e1c8c02ed..679d70b64 100644
--- a/core/vm/evm/evm.go
+++ b/core/vm/evm/evm.go
@@ -32,54 +32,7 @@ import (
var emptyCodeHash = crypto.Keccak256Hash(nil)
func init() {
- vm.Register(vm.EVM, &EVMImplement{})
-}
-
-type EVMImplement struct{}
-
-func (evmImpl *EVMImplement) Create(caller vm.ContractRef, code []byte, gas uint64,
- value *big.Int, interpreter vm.Interpreter) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
- i := interpreter.(*EVMInterpreter)
- return i.evm.Create(caller, code, gas, value)
-}
-
-func (evmImpl *EVMImplement) Create2(caller vm.ContractRef, code []byte, gas uint64,
- endowment *big.Int, salt *big.Int,
- interpreter vm.Interpreter) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
-
- i := interpreter.(*EVMInterpreter)
- return i.evm.Create2(caller, code, gas, endowment, salt)
-}
-
-func (evmImpl *EVMImplement) Call(caller vm.ContractRef, addr common.Address,
- input []byte, gas uint64, value *big.Int,
- interpreter vm.Interpreter) (ret []byte, leftOverGas uint64, err error) {
- i := interpreter.(*EVMInterpreter)
- return i.evm.Call(caller, addr, input, gas, value)
-
-}
-func (evmImpl *EVMImplement) CallCode(caller vm.ContractRef, addr common.Address,
- input []byte, gas uint64, value *big.Int,
- interpreter vm.Interpreter) (ret []byte, leftOverGas uint64, err error) {
-
- i := interpreter.(*EVMInterpreter)
- return i.evm.CallCode(caller, addr, input, gas, value)
-}
-
-func (evmImpl *EVMImplement) DelegateCall(caller vm.ContractRef, addr common.Address,
- input []byte, gas uint64,
- interpreter vm.Interpreter) (ret []byte, leftOverGas uint64, err error) {
-
- i := interpreter.(*EVMInterpreter)
- return i.evm.DelegateCall(caller, addr, input, gas)
-}
-
-func (evmImpl *EVMImplement) StaticCall(caller vm.ContractRef, addr common.Address,
- input []byte, gas uint64,
- interpreter vm.Interpreter) (ret []byte, leftovergas uint64, err error) {
-
- i := interpreter.(*EVMInterpreter)
- return i.evm.StaticCall(caller, addr, input, gas)
+ vm.Register(vm.EVM, NewEVM)
}
// run runs the given contract and takes care of running precompiles with a fallback to the byte code interpreter.
@@ -123,11 +76,9 @@ func run(evm *EVM, contract *vm.Contract, input []byte, readOnly bool) ([]byte,
// The EVM should never be reused and is not thread safe.
type EVM struct {
// Context provides auxiliary blockchain related information
- vm.Context
+ *vm.Context
// StateDB gives access to the underlying state
StateDB vm.StateDB
- // Depth is the current call stack
- depth int
// chainConfig contains information about the current chain
chainConfig *params.ChainConfig
@@ -143,19 +94,16 @@ type EVM struct {
// abort is used to abort the EVM calling operations
// NOTE: must be set atomically
abort int32
- // callGasTemp holds the gas available for the current call. This is needed because the
- // available gas is calculated in gasCall* according to the 63/64 rule and later
- // applied in opCall*.
- callGasTemp uint64
}
// NewEVM returns a new EVM. The returned EVM is not thread safe and should
// only ever be used *once*.
-func NewEVM(ctx vm.Context, statedb vm.StateDB, chainConfig *params.ChainConfig, vmConfig Config) *EVM {
+func NewEVM(ctx *vm.Context, statedb vm.StateDB, chainConfig *params.ChainConfig, vmConfig interface{}) vm.VM {
+ cfg := vmConfig.(Config)
evm := &EVM{
Context: ctx,
StateDB: statedb,
- vmConfig: vmConfig,
+ vmConfig: cfg,
chainConfig: chainConfig,
chainRules: chainConfig.Rules(ctx.BlockNumber),
interpreters: make([]Interpreter, 0, 1),
@@ -179,7 +127,7 @@ func NewEVM(ctx vm.Context, statedb vm.StateDB, chainConfig *params.ChainConfig,
// 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, cfg))
evm.interpreter = evm.interpreters[0]
return evm
@@ -200,17 +148,17 @@ func (evm *EVM) Interpreter() Interpreter {
// parameters. It also handles any necessary value transfer required and takes
// the necessary steps to create accounts and reverses the state in case of an
// execution error or failed value transfer.
-func (evm *EVM) Call(caller vm.ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) {
- if evm.vmConfig.NoRecursion && evm.depth > 0 {
+func (evm *EVM) Call(caller vm.ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int, pack *vm.ExecPack) (ret []byte, leftOverGas uint64, err error) {
+ if evm.NoRecursion && evm.Depth > 0 {
return nil, gas, nil
}
// Fail if we're trying to execute above the call depth limit
- if evm.depth > int(params.CallCreateDepth) {
+ if evm.Depth > int(params.CallCreateDepth) {
return nil, gas, vm.ErrDepth
}
// Fail if we're trying to transfer more than the available balance
- if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) {
+ if !evm.CanTransfer(evm.StateDB, caller.Address(), value) {
return nil, gas, vm.ErrInsufficientBalance
}
@@ -226,7 +174,7 @@ func (evm *EVM) Call(caller vm.ContractRef, addr common.Address, input []byte, g
if precompiles[addr] == nil && OracleContracts[addr] == nil &&
evm.ChainConfig().IsEIP158(evm.BlockNumber) && value.Sign() == 0 {
// Calling a non existing account, don't do anything, but ping the tracer
- if evm.vmConfig.Debug && evm.depth == 0 {
+ if evm.vmConfig.Debug && evm.Depth == 0 {
evm.vmConfig.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value)
evm.vmConfig.Tracer.CaptureEnd(ret, 0, 0, nil)
}
@@ -248,7 +196,7 @@ func (evm *EVM) Call(caller vm.ContractRef, addr common.Address, input []byte, g
start := time.Now()
// Capture the tracer start/end events in debug mode
- if evm.vmConfig.Debug && evm.depth == 0 {
+ if evm.vmConfig.Debug && evm.Depth == 0 {
evm.vmConfig.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value)
defer func() { // Lazy evaluation of the parameters
@@ -276,13 +224,13 @@ func (evm *EVM) Call(caller vm.ContractRef, addr common.Address, input []byte, g
//
// CallCode differs from Call in the sense that it executes the given address'
// code with the caller as context.
-func (evm *EVM) CallCode(caller vm.ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) {
- if evm.vmConfig.NoRecursion && evm.depth > 0 {
+func (evm *EVM) CallCode(caller vm.ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int, pack *vm.ExecPack) (ret []byte, leftOverGas uint64, err error) {
+ if evm.NoRecursion && evm.Depth > 0 {
return nil, gas, nil
}
// Fail if we're trying to execute above the call depth limit
- if evm.depth > int(params.CallCreateDepth) {
+ if evm.Depth > int(params.CallCreateDepth) {
return nil, gas, vm.ErrDepth
}
// Fail if we're trying to transfer more than the available balance
@@ -320,12 +268,12 @@ func (evm *EVM) CallCode(caller vm.ContractRef, addr common.Address, input []byt
//
// DelegateCall differs from CallCode in the sense that it executes the given address'
// code with the caller as context and the caller is set to the caller of the caller.
-func (evm *EVM) DelegateCall(caller vm.ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) {
- if evm.vmConfig.NoRecursion && evm.depth > 0 {
+func (evm *EVM) DelegateCall(caller vm.ContractRef, addr common.Address, input []byte, gas uint64, pack *vm.ExecPack) (ret []byte, leftOverGas uint64, err error) {
+ if evm.NoRecursion && evm.Depth > 0 {
return nil, gas, nil
}
// Fail if we're trying to execute above the call depth limit
- if evm.depth > int(params.CallCreateDepth) {
+ if evm.Depth > int(params.CallCreateDepth) {
return nil, gas, vm.ErrDepth
}
@@ -357,12 +305,17 @@ func (evm *EVM) DelegateCall(caller vm.ContractRef, addr common.Address, input [
// as parameters while disallowing any modifications to the state during the call.
// Opcodes that attempt to perform such modifications will result in exceptions
// instead of performing the modifications.
-func (evm *EVM) StaticCall(caller vm.ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) {
- if evm.vmConfig.NoRecursion && evm.depth > 0 {
+func (evm *EVM) StaticCall(caller vm.ContractRef, addr common.Address, input []byte, gas uint64, pack *vm.ExecPack) (ret []byte, leftOverGas uint64, err error) {
+ oldReadOnly := pack.Context.ReadOnly
+ pack.Context.ReadOnly = true
+ defer func() {
+ pack.Context.ReadOnly = oldReadOnly
+ }()
+ if evm.NoRecursion && evm.Depth > 0 {
return nil, gas, nil
}
// Fail if we're trying to execute above the call depth limit
- if evm.depth > int(params.CallCreateDepth) {
+ if evm.Depth > int(params.CallCreateDepth) {
return nil, gas, vm.ErrDepth
}
@@ -404,7 +357,7 @@ func (evm *EVM) StaticCall(caller vm.ContractRef, addr common.Address, input []b
func (evm *EVM) create(caller vm.ContractRef, codeAndHash *vm.CodeAndHash, gas uint64, value *big.Int, address common.Address) ([]byte, common.Address, uint64, error) {
// Depth check execution. Fail if we're trying to execute above the
// limit.
- if evm.depth > int(params.CallCreateDepth) {
+ if evm.Depth > int(params.CallCreateDepth) {
return nil, common.Address{}, gas, vm.ErrDepth
}
if !evm.CanTransfer(evm.StateDB, caller.Address(), value) {
@@ -432,11 +385,11 @@ func (evm *EVM) create(caller vm.ContractRef, codeAndHash *vm.CodeAndHash, gas u
contract := vm.NewContract(caller, vm.AccountRef(address), value, gas)
contract.SetCodeOptionalHash(&address, codeAndHash)
- if evm.vmConfig.NoRecursion && evm.depth > 0 {
+ if evm.NoRecursion && evm.Depth > 0 {
return nil, address, gas, nil
}
- if evm.vmConfig.Debug && evm.depth == 0 {
+ if evm.vmConfig.Debug && evm.Depth == 0 {
evm.vmConfig.Tracer.CaptureStart(caller.Address(), address, true, codeAndHash.Code, gas, value)
}
start := time.Now()
@@ -470,7 +423,7 @@ func (evm *EVM) create(caller vm.ContractRef, codeAndHash *vm.CodeAndHash, gas u
if maxCodeSizeExceeded && err == nil {
err = errMaxCodeSizeExceeded
}
- if evm.vmConfig.Debug && evm.depth == 0 {
+ if evm.vmConfig.Debug && evm.Depth == 0 {
evm.vmConfig.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err)
}
return ret, address, contract.Gas, err
@@ -478,7 +431,7 @@ func (evm *EVM) create(caller vm.ContractRef, codeAndHash *vm.CodeAndHash, gas u
}
// Create creates a new contract using code as deployment code.
-func (evm *EVM) Create(caller vm.ContractRef, code []byte, gas uint64, value *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
+func (evm *EVM) Create(caller vm.ContractRef, code []byte, gas uint64, value *big.Int, pack *vm.ExecPack) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
contractAddr = crypto.CreateAddress(caller.Address(), evm.StateDB.GetNonce(caller.Address()))
return evm.create(caller, &vm.CodeAndHash{Code: code}, gas, value, contractAddr)
}
@@ -487,7 +440,7 @@ func (evm *EVM) Create(caller vm.ContractRef, code []byte, gas uint64, value *bi
//
// The different between Create2 with Create is Create2 uses sha3(0xff ++ msg.sender ++ salt ++ sha3(init_code))[12:]
// instead of the usual sender-and-nonce-hash as the address where the contract is initialized at.
-func (evm *EVM) Create2(caller vm.ContractRef, code []byte, gas uint64, endowment *big.Int, salt *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
+func (evm *EVM) Create2(caller vm.ContractRef, code []byte, gas uint64, endowment *big.Int, salt *big.Int, pack *vm.ExecPack) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
codeAndHash := &vm.CodeAndHash{Code: code}
contractAddr = crypto.CreateAddress2(caller.Address(), common.BigToHash(salt), codeAndHash.Hash().Bytes())
return evm.create(caller, codeAndHash, gas, endowment, contractAddr)
@@ -496,5 +449,8 @@ func (evm *EVM) Create2(caller vm.ContractRef, code []byte, gas uint64, endowmen
// ChainConfig returns the environment's chain configuration
func (evm *EVM) ChainConfig() *params.ChainConfig { return evm.chainConfig }
+// VMConfig returns the vm configuration.
+func (evm *EVM) VMConfig() Config { return evm.vmConfig }
+
// IsBlockProposer returns whether or not we are a block proposer.
func (evm *EVM) IsBlockProposer() bool { return evm.vmConfig.IsBlockProposer }