From 9e9e83f666117702126003e75924580457c427c7 Mon Sep 17 00:00:00 2001 From: Jeffrey Wilcke Date: Fri, 3 Feb 2017 10:58:46 +0100 Subject: [PATCH] core/vm: added generic run function --- core/vm/contracts.go | 12 +++++++++++- core/vm/evm.go | 25 ++++++++++++++++++++----- core/vm/interpreter.go | 6 ------ 3 files changed, 31 insertions(+), 12 deletions(-) diff --git a/core/vm/contracts.go b/core/vm/contracts.go index c8ea5c4b63..487c838218 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -34,12 +34,21 @@ type PrecompiledContract interface { Run(input []byte) []byte // Run runs the precompiled contract } -// Precompiled contains the default set of ethereum contracts +// PrecompiledContracts contains the default set of ethereum contracts var PrecompiledContracts = map[common.Address]PrecompiledContract{ common.BytesToAddress([]byte{1}): &ecrecover{}, common.BytesToAddress([]byte{2}): &sha256{}, common.BytesToAddress([]byte{3}): &ripemd160{}, common.BytesToAddress([]byte{4}): &dataCopy{}, +} + +// PrecompiledContractsEIP198 contains the default set of ethereum contracts +// for EIP198. +var PrecompiledContractsEIP198 = map[common.Address]PrecompiledContract{ + common.BytesToAddress([]byte{1}): &ecrecover{}, + common.BytesToAddress([]byte{2}): &sha256{}, + common.BytesToAddress([]byte{3}): &ripemd160{}, + common.BytesToAddress([]byte{4}): &dataCopy{}, common.BytesToAddress([]byte{5}): &bigModexp{}, } @@ -132,6 +141,7 @@ func (c *dataCopy) Run(in []byte) []byte { return in } +// bigModexp implements a native big integer exponential modular operation. type bigModexp struct{} // RequiredGas returns the gas required to execute the pre-compiled contract. diff --git a/core/vm/evm.go b/core/vm/evm.go index 0c5d998c29..6e1aefcce5 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -33,6 +33,22 @@ type ( GetHashFunc func(uint64) common.Hash ) +// 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) ([]byte, error) { + if contract.CodeAddr != nil { + precompiledContracts := PrecompiledContracts + if evm.ChainConfig().IsEIP198(evm.BlockNumber) { + precompiledContracts = PrecompiledContractsEIP198 + } + + if p := precompiledContracts[*contract.CodeAddr]; p != nil { + return RunPrecompiledContract(p, input, contract) + } + } + + return evm.interpreter.Run(contract, input) +} + // Context provides the EVM with auxiliary information. Once provided it shouldn't be modified. type Context struct { // CanTransfer returns whether the account contains @@ -136,7 +152,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas contract := NewContract(caller, to, value, gas) contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) - ret, err = evm.interpreter.Run(contract, input) + ret, err = run(evm, contract, input) // 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. @@ -177,7 +193,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, contract := NewContract(caller, to, value, gas) contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) - ret, err = evm.interpreter.Run(contract, input) + ret, err = run(evm, contract, input) if err != nil { contract.UseGas(contract.Gas) @@ -212,7 +228,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by contract := NewContract(caller, to, caller.Value(), gas).AsDelegate() contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) - ret, err = evm.interpreter.Run(contract, input) + ret, err = run(evm, contract, input) if err != nil { contract.UseGas(contract.Gas) @@ -255,8 +271,7 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I contract := NewContract(caller, to, value, gas) contract.SetCallCode(&contractAddr, crypto.Keccak256Hash(code), code) - ret, err = evm.interpreter.Run(contract, nil) - + ret, err = run(evm, contract, nil) // check whether the max code size has been exceeded maxCodeSizeExceeded := len(ret) > params.MaxCodeSize // if the contract creation ran successfully and no errors were returned diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index ad41e36022..21f44c4691 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -86,12 +86,6 @@ func (evm *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err e evm.env.depth++ defer func() { evm.env.depth-- }() - if contract.CodeAddr != nil { - if p := PrecompiledContracts[*contract.CodeAddr]; p != nil { - return RunPrecompiledContract(p, input, contract) - } - } - // Don't bother with the execution if there's no code. if len(contract.Code) == 0 { return nil, nil