core/vm: remove function call for stack validation from evm runloop

This commit is contained in:
Martin Holst Swende 2019-03-03 20:47:30 +01:00
parent f9aa1cd21f
commit 4caa9dec46
No known key found for this signature in database
GPG key ID: 683B438C05A5DDF0
3 changed files with 778 additions and 641 deletions

View file

@ -118,22 +118,6 @@ func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter {
}
}
func (in *EVMInterpreter) enforceRestrictions(op OpCode, operation operation, stack *Stack) error {
if in.evm.chainRules.IsByzantium {
if in.readOnly {
// 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. Transferring value from one
// account to the others means the state is modified and should also
// return with an error.
if operation.writes || (op == CALL && stack.Back(2).BitLen() > 0) {
return errWriteProtection
}
}
}
return nil
}
// Run loops and evaluates the contract's code with the given input data and returns
// the return byte-slice and an error if one occurred.
//
@ -217,12 +201,24 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
if !operation.valid {
return nil, fmt.Errorf("invalid opcode 0x%x", int(op))
}
if err = operation.validateStack(stack); err != nil {
return nil, err
// Validate stack
if sLen := stack.len(); sLen < operation.minStack{
return nil, fmt.Errorf("stack underflow (%d <=> %d)", sLen, operation.minStack)
}else{
if sLen > operation.maxStack{
return nil, fmt.Errorf("stack limit reached %d (%d)", sLen, operation.maxStack)
}
}
// If the operation is valid, enforce and write restrictions
if err = in.enforceRestrictions(op, operation, stack); err != nil {
return nil, err
if in.readOnly && in.evm.chainRules.IsByzantium {
// 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. Transferring value from one
// account to the others means the state is modified and should also
// return with an error.
if operation.writes || (op == CALL && stack.Back(2).BitLen() > 0) {
return nil, errWriteProtection
}
}
var memorySize uint64

File diff suppressed because it is too large Load diff

View file

@ -17,28 +17,26 @@
package vm
import (
"fmt"
"github.com/ethereum/go-ethereum/params"
)
func makeStackFunc(pop, push int) stackValidationFunc {
return func(stack *Stack) error {
if err := stack.require(pop); err != nil {
return err
func minSwapStack(n int) int {
return minStack(n, n)
}
func maxSwapStack(n int) int {
return maxStack(n, n)
}
if stack.len()+push-pop > int(params.StackLimit) {
return fmt.Errorf("stack limit reached %d (%d)", stack.len(), params.StackLimit)
}
return nil
func minDupStack(n int) int {
return minStack(n, n+1)
}
func maxDupStack(n int) int {
return maxStack(n, n+1)
}
func makeDupStackFunc(n int) stackValidationFunc {
return makeStackFunc(n, n+1)
func maxStack(pop, push int) int {
return int(params.StackLimit) + pop - push
}
func makeSwapStackFunc(n int) stackValidationFunc {
return makeStackFunc(n, n)
func minStack(pops, push int) int {
return pops
}