aboutsummaryrefslogtreecommitdiffstats
path: root/core/vm/evm.go
diff options
context:
space:
mode:
Diffstat (limited to 'core/vm/evm.go')
-rw-r--r--core/vm/evm.go49
1 files changed, 33 insertions, 16 deletions
diff --git a/core/vm/evm.go b/core/vm/evm.go
index 71efcfa45..9296cc7ca 100644
--- a/core/vm/evm.go
+++ b/core/vm/evm.go
@@ -33,7 +33,20 @@ type (
GetHashFunc func(uint64) common.Hash
)
-// Context provides the EVM with auxiliary information. Once provided it shouldn't be modified.
+// run runs the given contract and takes care of running precompiles with a fallback to the byte code interpreter.
+func run(evm *EVM, snapshot int, contract *Contract, input []byte) ([]byte, error) {
+ if contract.CodeAddr != nil {
+ precompiledContracts := PrecompiledContracts
+ if p := precompiledContracts[*contract.CodeAddr]; p != nil {
+ return RunPrecompiledContract(p, input, contract)
+ }
+ }
+
+ return evm.interpreter.Run(snapshot, 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
// sufficient ether to transfer the value
@@ -55,7 +68,13 @@ type Context struct {
Difficulty *big.Int // Provides information for DIFFICULTY
}
-// EVM provides information about external sources for the EVM
+// 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
+// generated through any of the calls should be considered a
+// revert-state-and-consume-all-gas operation, no checks on
+// specific errors should ever be performed. The interpreter makes
+// sure that any errors generated are to be considered faulty code.
//
// The EVM should never be reused and is not thread safe.
type EVM struct {
@@ -68,6 +87,8 @@ type EVM struct {
// chainConfig contains information about the current chain
chainConfig *params.ChainConfig
+ // chain rules contains the chain rules for the current epoch
+ chainRules params.Rules
// virtual machine configuration options used to initialise the
// evm.
vmConfig Config
@@ -79,21 +100,23 @@ type EVM struct {
abort int32
}
-// NewEVM retutrns a new EVM evmironment.
+// NewEVM retutrns a new EVM evmironment. 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 {
evm := &EVM{
Context: ctx,
StateDB: statedb,
vmConfig: vmConfig,
chainConfig: chainConfig,
+ chainRules: chainConfig.Rules(ctx.BlockNumber),
}
evm.interpreter = NewInterpreter(evm, vmConfig)
return evm
}
-// Cancel cancels any running EVM operation. This may be called concurrently and it's safe to be
-// called multiple times.
+// Cancel cancels any running EVM operation. This may be called concurrently and
+// it's safe to be called multiple times.
func (evm *EVM) Cancel() {
atomic.StoreInt32(&evm.abort, 1)
}
@@ -134,13 +157,12 @@ 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, snapshot, 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.
if err != nil {
contract.UseGas(contract.Gas)
-
evm.StateDB.RevertToSnapshot(snapshot)
}
return ret, contract.Gas, err
@@ -175,10 +197,9 @@ 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, snapshot, contract, input)
if err != nil {
contract.UseGas(contract.Gas)
-
evm.StateDB.RevertToSnapshot(snapshot)
}
@@ -210,10 +231,9 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
contract := NewContract(caller, to, nil, gas).AsDelegate()
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
- ret, err = evm.interpreter.Run(contract, input)
+ ret, err = run(evm, snapshot, contract, input)
if err != nil {
contract.UseGas(contract.Gas)
-
evm.StateDB.RevertToSnapshot(snapshot)
}
@@ -253,8 +273,7 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I
contract := NewContract(caller, AccountRef(contractAddr), value, gas)
contract.SetCallCode(&contractAddr, crypto.Keccak256Hash(code), code)
- ret, err = evm.interpreter.Run(contract, nil)
-
+ ret, err = run(evm, snapshot, 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
@@ -275,10 +294,8 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I
// when we're in homestead this also counts for code storage gas errors.
if maxCodeSizeExceeded ||
(err != nil && (evm.ChainConfig().IsHomestead(evm.BlockNumber) || err != ErrCodeStoreOutOfGas)) {
+ contract.UseGas(contract.Gas)
evm.StateDB.RevertToSnapshot(snapshot)
-
- // Nothing should be returned when an error is thrown.
- return nil, contractAddr, 0, err
}
// If the vm returned with an error the return value should be set to nil.
// This isn't consensus critical but merely to for behaviour reasons such as