From c3c07bc75552286b9f3b2d11fcd503c7d4f1fc30 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Mon, 16 Apr 2018 09:44:10 +0200 Subject: [PATCH] core/vm: don't check code for non-existing accounts --- core/vm/contract.go | 12 ++++++++++++ core/vm/evm.go | 31 ++++++++++++++++++++++++------- 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/core/vm/contract.go b/core/vm/contract.go index b466681dbd..63c39e4b94 100644 --- a/core/vm/contract.go +++ b/core/vm/contract.go @@ -64,6 +64,18 @@ type Contract struct { DelegateCall bool } +func NewPrecompiledContract( caller ContractRef, object ContractRef,value *big.Int, gas uint64) *Contract{ + + c := &Contract{CallerAddress: caller.Address(), caller: caller, self: object, Args: nil} + // Gas should be a pointer so it can safely be reduced through the run + // This pointer will be off the state transition + c.Gas = gas + // ensures a value is set + c.value = value + return c + +} + // NewContract returns a new contract environment for the execution of EVM. func NewContract(caller ContractRef, object ContractRef, value *big.Int, gas uint64) *Contract { c := &Contract{CallerAddress: caller.Address(), caller: caller, self: object, Args: nil} diff --git a/core/vm/evm.go b/core/vm/evm.go index 988fdccee7..3d1de43fe0 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -167,7 +167,8 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas to = AccountRef(addr) snapshot = evm.StateDB.Snapshot() ) - if !evm.StateDB.Exist(addr) { + exists := evm.StateDB.Exist(addr) + if !exists{ if evm.BlockContext.Precompiles[addr] == nil && evm.ChainConfig().IsEIP158(evm.BlockContext.BlockNumber) && value.Sign() == 0 { // Calling a non existing account, don't do antything, but ping the tracer if evm.vmConfig.Debug && evm.depth == 0 { @@ -180,9 +181,17 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas } evm.Transfer(evm.StateDB, caller.Address(), to.Address(), value) + precompile, isPrecompile := evm.BlockContext.Precompiles[addr] + + if !exists && !isPrecompile{ + // Shortcut execution -- account didn't exist, + // so no need to lookup the code + // but make sure to set returndata to nil + evm.interpreter.returnData = nil + return nil, gas, nil + } code := evm.StateDB.GetCode(addr) codeHash := evm.StateDB.GetCodeHash(addr) - _, isPrecompile := evm.BlockContext.Precompiles[addr] if !isPrecompile && len(code) == 0 { // Shortcut execution if there is no code, @@ -193,21 +202,29 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas // 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.SetCallCode(&addr, codeHash, code) - - start := time.Now() + var contract *Contract + if!isPrecompile { + contract = NewContract(caller, to, value, gas) + contract.SetCallCode(&addr, codeHash, code) + }else{ + contract = NewPrecompiledContract(caller, to, value, gas) + } // Capture the tracer start/end events in debug mode if evm.vmConfig.Debug && evm.depth == 0 { + start := time.Now() evm.vmConfig.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value) defer func() { // Lazy evaluation of the parameters evm.vmConfig.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err) }() } - ret, err = run(evm, contract, input) + if!isPrecompile{ + ret, err = evm.interpreter.Run(contract, input) + }else{ + ret, err = RunPrecompiledContract(precompile, input, contract) + } // 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.