core/vm: don't check code for non-existing accounts

This commit is contained in:
Martin Holst Swende 2018-04-16 09:44:10 +02:00
parent 4394e4dc38
commit c3c07bc755
No known key found for this signature in database
GPG key ID: 683B438C05A5DDF0
2 changed files with 36 additions and 7 deletions

View file

@ -64,6 +64,18 @@ type Contract struct {
DelegateCall bool 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. // NewContract returns a new contract environment for the execution of EVM.
func NewContract(caller ContractRef, object ContractRef, value *big.Int, gas uint64) *Contract { func NewContract(caller ContractRef, object ContractRef, value *big.Int, gas uint64) *Contract {
c := &Contract{CallerAddress: caller.Address(), caller: caller, self: object, Args: nil} c := &Contract{CallerAddress: caller.Address(), caller: caller, self: object, Args: nil}

View file

@ -167,7 +167,8 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
to = AccountRef(addr) to = AccountRef(addr)
snapshot = evm.StateDB.Snapshot() 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 { 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 // Calling a non existing account, don't do antything, but ping the tracer
if evm.vmConfig.Debug && evm.depth == 0 { 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) 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) code := evm.StateDB.GetCode(addr)
codeHash := evm.StateDB.GetCodeHash(addr) codeHash := evm.StateDB.GetCodeHash(addr)
_, isPrecompile := evm.BlockContext.Precompiles[addr]
if !isPrecompile && len(code) == 0 { if !isPrecompile && len(code) == 0 {
// Shortcut execution if there is no code, // 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. // 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. // The contract is a scoped environment for this execution context only.
contract := NewContract(caller, to, value, gas) var contract *Contract
if!isPrecompile {
contract = NewContract(caller, to, value, gas)
contract.SetCallCode(&addr, codeHash, code) contract.SetCallCode(&addr, codeHash, code)
}else{
start := time.Now() contract = NewPrecompiledContract(caller, to, value, gas)
}
// Capture the tracer start/end events in debug mode // Capture the tracer start/end events in debug mode
if evm.vmConfig.Debug && evm.depth == 0 { if evm.vmConfig.Debug && evm.depth == 0 {
start := time.Now()
evm.vmConfig.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value) evm.vmConfig.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value)
defer func() { // Lazy evaluation of the parameters defer func() { // Lazy evaluation of the parameters
evm.vmConfig.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err) 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 // 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 // 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.