diff options
author | Péter Szilágyi <peterke@gmail.com> | 2017-08-15 17:56:09 +0800 |
---|---|---|
committer | Péter Szilágyi <peterke@gmail.com> | 2017-08-15 19:40:12 +0800 |
commit | 3df7142b3e2804aa7ccf88cc0c2663861ebfa3b9 (patch) | |
tree | 0e08d6a956f89b19ff8b85ced853f491dd06bfd2 | |
parent | 3d123bcde67973b57c0a9e7edc219cc2ea589443 (diff) | |
download | dexon-3df7142b3e2804aa7ccf88cc0c2663861ebfa3b9.tar.gz dexon-3df7142b3e2804aa7ccf88cc0c2663861ebfa3b9.tar.zst dexon-3df7142b3e2804aa7ccf88cc0c2663861ebfa3b9.zip |
core/vm: minor polishes, fix STATICCALL for precompiles
* Fix STATICCALL so it is able to call precompiles too
* Fix write detection to use the correct value argument of CALL
* Fix write protection to ignore the value in CALLCODE
-rw-r--r-- | core/vm/evm.go | 63 | ||||
-rw-r--r-- | core/vm/interpreter.go | 7 |
2 files changed, 33 insertions, 37 deletions
diff --git a/core/vm/evm.go b/core/vm/evm.go index 97a9d3105..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,18 +246,19 @@ 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 } - - // 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 } - - // make sure the readonly is only set if we aren't in readonly yet + // 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 { @@ -268,23 +270,18 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte to = AccountRef(addr) snapshot = evm.StateDB.Snapshot() ) - if !evm.StateDB.Exist(addr) { - return nil, gas, nil - } - - // initialise a new contract and set the code that is to be used by the - // EVM. The contract is a scoped evmironment for this execution context + // 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)) - ret, err = evm.interpreter.Run(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. + // 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 diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 32d764b9f..661ada691 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -89,13 +89,12 @@ func NewInterpreter(evm *EVM, cfg Config) *Interpreter { func (in *Interpreter) enforceRestrictions(op OpCode, operation operation, stack *Stack) error { if in.evm.chainRules.IsMetropolis { if in.readonly { - // if the interpreter is operating in readonly mode, make sure no - // state-modifying operation is performed. The 4th stack item + // If the interpreter is operating in readonly mode, make sure no + // state-modifying operation is performed. The 3rd stack item // for a call operation is the value. Transfering value from one // account to the others means the state is modified and should also // return with an error. - if operation.writes || - ((op == CALL || op == CALLCODE) && stack.Back(3).BitLen() > 0) { + if operation.writes || (op == CALL && stack.Back(2).BitLen() > 0) { return errWriteProtection } } |