diff options
author | Péter Szilágyi <peterke@gmail.com> | 2017-08-16 17:39:31 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-08-16 17:39:31 +0800 |
commit | 76069eef38082089d2eaf99661a80e1a953bf271 (patch) | |
tree | 62f21e54348e436ea7e9f387101266d848b0b36d /core/vm/evm.go | |
parent | 30402430427854b61e9836850d6163554c4c667d (diff) | |
parent | 3df7142b3e2804aa7ccf88cc0c2663861ebfa3b9 (diff) | |
download | dexon-76069eef38082089d2eaf99661a80e1a953bf271.tar dexon-76069eef38082089d2eaf99661a80e1a953bf271.tar.gz dexon-76069eef38082089d2eaf99661a80e1a953bf271.tar.bz2 dexon-76069eef38082089d2eaf99661a80e1a953bf271.tar.lz dexon-76069eef38082089d2eaf99661a80e1a953bf271.tar.xz dexon-76069eef38082089d2eaf99661a80e1a953bf271.tar.zst dexon-76069eef38082089d2eaf99661a80e1a953bf271.zip |
Merge pull request #14978 from karalabe/metropolis-staticcall
core/vm: implement metropolis static call opcode
Diffstat (limited to 'core/vm/evm.go')
-rw-r--r-- | core/vm/evm.go | 80 |
1 files changed, 61 insertions, 19 deletions
diff --git a/core/vm/evm.go b/core/vm/evm.go index b8af9bd15..cc4214a16 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -123,19 +123,20 @@ func (evm *EVM) Cancel() { atomic.StoreInt32(&evm.abort, 1) } -// Call executes the contract associated with the addr with the given input as parameters. It also handles any -// necessary value transfer required and takes the necessary steps to create accounts and reverses the state in -// case of an execution error or failed value transfer. +// Call executes the contract associated with the addr with the given input as +// parameters. It also handles any necessary value transfer required and takes +// the necessary steps to create accounts and reverses the state in case of an +// execution error or failed value transfer. func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) { if evm.vmConfig.NoRecursion && evm.depth > 0 { return nil, gas, nil } - // Depth check execution. Fail if we're trying to execute above the - // limit. + // Fail if we're trying to execute above the call depth limit if evm.depth > int(params.CallCreateDepth) { return nil, gas, ErrDepth } + // Fail if we're trying to transfer more than the available balance if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) { return nil, gas, ErrInsufficientBalance } @@ -173,21 +174,23 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas return ret, contract.Gas, err } -// CallCode executes the contract associated with the addr with the given input as parameters. It also handles any -// necessary value transfer required and takes the necessary steps to create accounts and reverses the state in -// case of an execution error or failed value transfer. +// CallCode executes the contract associated with the addr with the given input +// as parameters. It also handles any necessary value transfer required and takes +// the necessary steps to create accounts and reverses the state in case of an +// execution error or failed value transfer. // -// CallCode differs from Call in the sense that it executes the given address' code with the caller as context. +// CallCode differs from Call in the sense that it executes the given address' +// code with the caller as context. func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) { if evm.vmConfig.NoRecursion && evm.depth > 0 { return nil, gas, nil } - // Depth check execution. Fail if we're trying to execute above the - // limit. + // Fail if we're trying to execute above the call depth limit if evm.depth > int(params.CallCreateDepth) { return nil, gas, ErrDepth } + // Fail if we're trying to transfer more than the available balance if !evm.CanTransfer(evm.StateDB, caller.Address(), value) { return nil, gas, ErrInsufficientBalance } @@ -211,18 +214,16 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, return ret, contract.Gas, err } -// DelegateCall executes the contract associated with the addr with the given input as parameters. -// It reverses the state in case of an execution error. +// DelegateCall executes the contract associated with the addr with the given input +// as parameters. It reverses the state in case of an execution error. // -// DelegateCall differs from CallCode in the sense that it executes the given address' code with the caller as context -// and the caller is set to the caller of the caller. +// DelegateCall differs from CallCode in the sense that it executes the given address' +// code with the caller as context and the caller is set to the caller of the caller. func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) { if evm.vmConfig.NoRecursion && evm.depth > 0 { return nil, gas, nil } - - // Depth check execution. Fail if we're trying to execute above the - // limit. + // Fail if we're trying to execute above the call depth limit if evm.depth > int(params.CallCreateDepth) { return nil, gas, ErrDepth } @@ -232,7 +233,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by to = AccountRef(caller.Address()) ) - // Iinitialise a new contract and make initialise the delegate values + // Initialise a new contract and make initialise the delegate values contract := NewContract(caller, to, nil, gas).AsDelegate() contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) @@ -245,6 +246,47 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by return ret, contract.Gas, err } +// StaticCall executes the contract associated with the addr with the given input +// as parameters while disallowing any modifications to the state during the call. +// Opcodes that attempt to perform such modifications will result in exceptions +// instead of performing the modifications. +func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) { + if evm.vmConfig.NoRecursion && evm.depth > 0 { + return nil, gas, nil + } + // Fail if we're trying to execute above the call depth limit + if evm.depth > int(params.CallCreateDepth) { + return nil, gas, ErrDepth + } + // Make sure the readonly is only set if we aren't in readonly yet + // this makes also sure that the readonly flag isn't removed for + // child calls. + if !evm.interpreter.readonly { + evm.interpreter.readonly = true + defer func() { evm.interpreter.readonly = false }() + } + + var ( + to = AccountRef(addr) + snapshot = evm.StateDB.Snapshot() + ) + // 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, new(big.Int), gas) + contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) + + // 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. + ret, err = run(evm, snapshot, contract, input) + if err != nil { + contract.UseGas(contract.Gas) + evm.StateDB.RevertToSnapshot(snapshot) + } + return ret, contract.Gas, err +} + // Create creates a new contract using code as deployment code. func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { if evm.vmConfig.NoRecursion && evm.depth > 0 { |