core/vm: added generic run function

This commit is contained in:
Jeffrey Wilcke 2017-02-03 10:58:46 +01:00
parent 41fc310dd7
commit 9e9e83f666
3 changed files with 31 additions and 12 deletions

View file

@ -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.

View file

@ -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

View file

@ -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