diff options
Diffstat (limited to 'core/vm/evm/evm.go')
-rw-r--r-- | core/vm/evm/evm.go | 113 |
1 files changed, 28 insertions, 85 deletions
diff --git a/core/vm/evm/evm.go b/core/vm/evm/evm.go index f34413727..45b821e94 100644 --- a/core/vm/evm/evm.go +++ b/core/vm/evm/evm.go @@ -22,7 +22,6 @@ import ( "time" "github.com/dexon-foundation/dexon/common" - "github.com/dexon-foundation/dexon/core/state" "github.com/dexon-foundation/dexon/core/vm" "github.com/dexon-foundation/dexon/crypto" "github.com/dexon-foundation/dexon/params" @@ -32,32 +31,18 @@ import ( // deployed contract addresses (relevant after the account abstraction). var emptyCodeHash = crypto.Keccak256Hash(nil) -type ( - // CanTransferFunc is the signature of a transfer guard function - CanTransferFunc func(StateDB, common.Address, *big.Int) bool - // TransferFunc is the signature of a transfer function - TransferFunc func(StateDB, common.Address, common.Address, *big.Int) - // GetHashFunc returns the nth block hash in the blockchain - // and is used by the BLOCKHASH EVM op code. - GetHashFunc func(uint64) common.Hash - // StateAtFunc returns the statedb given a root hash. - StateAtNumberFunc func(uint64) (*state.StateDB, error) - // GetRoundHeightFunc returns the round height. - GetRoundHeightFunc func(uint64) (uint64, bool) -) - // 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) { +func run(evm *EVM, contract *vm.Contract, input []byte, readOnly bool) ([]byte, error) { if contract.CodeAddr != nil { if o := OracleContracts[*contract.CodeAddr]; o != nil { return RunOracleContract(o, evm, input, contract) } - precompiles := PrecompiledContractsHomestead + precompiles := vm.PrecompiledContractsHomestead if evm.ChainConfig().IsByzantium(evm.BlockNumber) { - precompiles = PrecompiledContractsByzantium + precompiles = vm.PrecompiledContractsByzantium } if p := precompiles[*contract.CodeAddr]; p != nil { - return RunPrecompiledContract(p, input, contract) + return vm.RunPrecompiledContract(p, input, contract) } } for _, interpreter := range evm.interpreters { @@ -76,36 +61,6 @@ func run(evm *EVM, contract *Contract, input []byte, readOnly bool) ([]byte, err return nil, vm.ErrNoCompatibleInterpreter } -// Context provides the EVM with auxiliary information. Once provided -// it shouldn't be modified. -type Context struct { - // CanTransfer returns whether the account contains - // sufficient ether to transfer the value - CanTransfer CanTransferFunc - // Transfer transfers ether from one account to the other - Transfer TransferFunc - // GetHash returns the hash corresponding to n - GetHash GetHashFunc - // StateAtNumber returns the statedb given a root hash. - StateAtNumber StateAtNumberFunc - // GetRoundHeight returns the round height. - GetRoundHeight GetRoundHeightFunc - - // Message information - Origin common.Address // Provides information for ORIGIN - GasPrice *big.Int // Provides information for GASPRICE - - // Block information - Coinbase common.Address // Provides information for COINBASE - GasLimit uint64 // Provides information for GASLIMIT - BlockNumber *big.Int // Provides information for NUMBER - Time *big.Int // Provides information for TIME - Randomness []byte // Provides information for RAND - Difficulty *big.Int // Provides information for DIFFICULTY - - RandCallIndex uint64 // Number of times opRand is called -} - // EVM is the Ethereum Virtual Machine base object and provides // the necessary tools to run a contract on the given state with // the provided context. It should be noted that any error @@ -117,9 +72,9 @@ type Context struct { // The EVM should never be reused and is not thread safe. type EVM struct { // Context provides auxiliary blockchain related information - Context + vm.Context // StateDB gives access to the underlying state - StateDB StateDB + StateDB vm.StateDB // Depth is the current call stack depth int @@ -145,7 +100,7 @@ type EVM struct { // NewEVM returns a new EVM. The returned EVM is not thread safe and should // only ever be used *once*. -func NewEVM(ctx Context, statedb StateDB, chainConfig *params.ChainConfig, vmConfig Config) *EVM { +func NewEVM(ctx vm.Context, statedb vm.StateDB, chainConfig *params.ChainConfig, vmConfig Config) *EVM { evm := &EVM{ Context: ctx, StateDB: statedb, @@ -194,7 +149,7 @@ 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 ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) { +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 { return nil, gas, nil } @@ -209,13 +164,13 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas } var ( - to = AccountRef(addr) + to = vm.AccountRef(addr) snapshot = evm.StateDB.Snapshot() ) if !evm.StateDB.Exist(addr) { - precompiles := PrecompiledContractsHomestead + precompiles := vm.PrecompiledContractsHomestead if evm.ChainConfig().IsByzantium(evm.BlockNumber) { - precompiles = PrecompiledContractsByzantium + precompiles = vm.PrecompiledContractsByzantium } if precompiles[addr] == nil && OracleContracts[addr] == nil && evm.ChainConfig().IsEIP158(evm.BlockNumber) && value.Sign() == 0 { @@ -231,7 +186,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas evm.Transfer(evm.StateDB, caller.Address(), to.Address(), value) // Initialise a new contract and set the code that is to be used by the EVM. // The contract is a scoped environment for this execution context only. - contract := NewContract(caller, to, value, gas) + contract := vm.NewContract(caller, to, value, gas) contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) // Even if the account has no code, we need to continue because it might be a precompile @@ -266,7 +221,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas // // CallCode differs from Call in the sense that it executes the given address' // code with the caller as context. -func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) { +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 { return nil, gas, nil } @@ -282,12 +237,12 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, var ( snapshot = evm.StateDB.Snapshot() - to = AccountRef(caller.Address()) + to = vm.AccountRef(caller.Address()) ) // initialise a new contract and set the code that is to be used by the // EVM. The contract is a scoped environment for this execution context // only. - contract := NewContract(caller, to, value, gas) + contract := vm.NewContract(caller, to, value, gas) contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) ret, err = run(evm, contract, input, false) @@ -305,7 +260,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, // // 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 ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) { +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 { return nil, gas, nil } @@ -316,11 +271,11 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by var ( snapshot = evm.StateDB.Snapshot() - to = AccountRef(caller.Address()) + to = vm.AccountRef(caller.Address()) ) // Initialise a new contract and make initialise the delegate values - contract := NewContract(caller, to, nil, gas).AsDelegate() + contract := vm.NewContract(caller, to, nil, gas).AsDelegate() contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) ret, err = run(evm, contract, input, false) @@ -337,7 +292,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by // 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 ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) { +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 { return nil, gas, nil } @@ -347,13 +302,13 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte } var ( - to = AccountRef(addr) + to = vm.AccountRef(addr) snapshot = evm.StateDB.Snapshot() ) // Initialise a new contract and set the code that is to be used by the // EVM. The contract is a scoped environment for this execution context // only. - contract := NewContract(caller, to, new(big.Int), gas) + contract := vm.NewContract(caller, to, new(big.Int), gas) contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) // We do an AddBalance of zero here, just in order to trigger a touch. @@ -375,20 +330,8 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte return ret, contract.Gas, err } -type codeAndHash struct { - code []byte - hash common.Hash -} - -func (c *codeAndHash) Hash() common.Hash { - if c.hash == (common.Hash{}) { - c.hash = crypto.Keccak256Hash(c.code) - } - return c.hash -} - // create creates a new contract using code as deployment code. -func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, value *big.Int, address common.Address) ([]byte, common.Address, uint64, error) { +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) { @@ -416,7 +359,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, // initialise a new contract and set the code that is to be used by the // EVM. The contract is a scoped environment for this execution context // only. - contract := NewContract(caller, AccountRef(address), value, gas) + contract := vm.NewContract(caller, vm.AccountRef(address), value, gas) contract.SetCodeOptionalHash(&address, codeAndHash) if evm.vmConfig.NoRecursion && evm.depth > 0 { @@ -424,7 +367,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, } if evm.vmConfig.Debug && evm.depth == 0 { - evm.vmConfig.Tracer.CaptureStart(caller.Address(), address, true, codeAndHash.code, gas, value) + evm.vmConfig.Tracer.CaptureStart(caller.Address(), address, true, codeAndHash.Code, gas, value) } start := time.Now() @@ -466,17 +409,17 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, } // Create creates a new contract using code as deployment code. -func (evm *EVM) Create(caller 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) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { contractAddr = crypto.CreateAddress(caller.Address(), evm.StateDB.GetNonce(caller.Address())) - return evm.create(caller, &codeAndHash{code: code}, gas, value, contractAddr) + return evm.create(caller, &vm.CodeAndHash{Code: code}, gas, value, contractAddr) } // Create2 creates a new contract using code as deployment code. // // 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 ContractRef, code []byte, gas uint64, endowment *big.Int, salt *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { - codeAndHash := &codeAndHash{code: code} +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) { + codeAndHash := &vm.CodeAndHash{Code: code} contractAddr = crypto.CreateAddress2(caller.Address(), common.BigToHash(salt), codeAndHash.Hash().Bytes()) return evm.create(caller, codeAndHash, gas, endowment, contractAddr) } |