Sfoglia il codice sorgente

core/vm: 64 bit memory and gas calculations (#19210)

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

* core/vm: separate gas  calc into static + dynamic

* core/vm: optimize push1

* core/vm: reuse pooled bigints for ADDRESS, ORIGIN and CALLER

* core/vm: use generic error message for jump/jumpi, to avoid string interpolation

* testdata: fix tests for new error message

* core/vm: use 64-bit memory calculations

* core/vm: fix error in memory calculation

* core/vm: address review concerns

* core/vm: avoid unnecessary use of big.Int:BitLen()
Martin Holst Swende 6 anni fa
parent
commit
7504dbd6eb

+ 0 - 3
common/types.go

@@ -202,9 +202,6 @@ func IsHexAddress(s string) bool {
 // Bytes gets the string representation of the underlying address.
 func (a Address) Bytes() []byte { return a[:] }
 
-// Big converts an address to a big integer.
-func (a Address) Big() *big.Int { return new(big.Int).SetBytes(a[:]) }
-
 // Hash converts an address to a hash by left-padding it with zeros.
 func (a Address) Hash() Hash { return BytesToHash(a[:]) }
 

+ 2 - 2
common/types_test.go

@@ -114,8 +114,8 @@ func TestAddressUnmarshalJSON(t *testing.T) {
 			if test.ShouldErr {
 				t.Errorf("test #%d: expected error, got none", i)
 			}
-			if v.Big().Cmp(test.Output) != 0 {
-				t.Errorf("test #%d: address mismatch: have %v, want %v", i, v.Big(), test.Output)
+			if got := new(big.Int).SetBytes(v.Bytes()); got.Cmp(test.Output) != 0 {
+				t.Errorf("test #%d: address mismatch: have %v, want %v", i, got, test.Output)
 			}
 		}
 	}

+ 2 - 1
core/mkalloc.go

@@ -52,7 +52,8 @@ func makelist(g *core.Genesis) allocList {
 		if len(account.Storage) > 0 || len(account.Code) > 0 || account.Nonce != 0 {
 			panic(fmt.Sprintf("can't encode account %x", addr))
 		}
-		a = append(a, allocItem{addr.Big(), account.Balance})
+		bigAddr := new(big.Int).SetBytes(addr.Bytes())
+		a = append(a, allocItem{bigAddr, account.Balance})
 	}
 	sort.Sort(a)
 	return a

+ 24 - 6
core/vm/common.go

@@ -23,13 +23,31 @@ import (
 	"github.com/ethereum/go-ethereum/common/math"
 )
 
-// calculates the memory size required for a step
-func calcMemSize(off, l *big.Int) *big.Int {
-	if l.Sign() == 0 {
-		return common.Big0
+// calcMemSize64 calculates the required memory size, and returns
+// the size and whether the result overflowed uint64
+func calcMemSize64(off, l *big.Int) (uint64, bool) {
+	if !l.IsUint64() {
+		return 0, true
 	}
+	return calcMemSize64WithUint(off, l.Uint64())
+}
 
-	return new(big.Int).Add(off, l)
+// calcMemSize64WithUint calculates the required memory size, and returns
+// the size and whether the result overflowed uint64
+// Identical to calcMemSize64, but length is a uint64
+func calcMemSize64WithUint(off *big.Int, length64 uint64) (uint64, bool) {
+	// if length is zero, memsize is always zero, regardless of offset
+	if length64 == 0 {
+		return 0, false
+	}
+	// Check that offset doesn't overflow
+	if !off.IsUint64() {
+		return 0, true
+	}
+	offset64 := off.Uint64()
+	val := offset64 + length64
+	// if value < either of it's parts, then it overflowed
+	return val, val < offset64
 }
 
 // getData returns a slice from the data based on the start and size and pads
@@ -59,7 +77,7 @@ func getDataBig(data []byte, start *big.Int, size *big.Int) []byte {
 // bigUint64 returns the integer casted to a uint64 and returns whether it
 // overflowed in the process.
 func bigUint64(v *big.Int) (uint64, bool) {
-	return v.Uint64(), v.BitLen() > 64
+	return v.Uint64(), !v.IsUint64()
 }
 
 // toWordSize returns the ceiled word size required for memory expansion.

+ 2 - 2
core/vm/gas.go

@@ -43,11 +43,11 @@ func callGas(gasTable params.GasTable, availableGas, base uint64, callCost *big.
 		// If the bit length exceeds 64 bit we know that the newly calculated "gas" for EIP150
 		// is smaller than the requested amount. Therefor we return the new gas instead
 		// of returning an error.
-		if callCost.BitLen() > 64 || gas < callCost.Uint64() {
+		if !callCost.IsUint64() || gas < callCost.Uint64() {
 			return gas, nil
 		}
 	}
-	if callCost.BitLen() > 64 {
+	if !callCost.IsUint64() {
 		return 0, errGasUintOverflow
 	}
 

+ 0 - 18
core/vm/gas_table.go

@@ -57,12 +57,6 @@ func memoryGasCost(mem *Memory, newMemSize uint64) (uint64, error) {
 	return 0, nil
 }
 
-func constGasFunc(gas uint64) gasFunc {
-	return func(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
-		return gas, nil
-	}
-}
-
 func gasCallDataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
 	gas, err := memoryGasCost(mem, memorySize)
 	if err != nil {
@@ -521,15 +515,3 @@ func gasStaticCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stac
 	}
 	return gas, nil
 }
-
-func gasPush(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
-	return GasFastestStep, nil
-}
-
-func gasSwap(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
-	return GasFastestStep, nil
-}
-
-func gasDup(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
-	return GasFastestStep, nil
-}

+ 25 - 12
core/vm/instructions.go

@@ -18,7 +18,6 @@ package vm
 
 import (
 	"errors"
-	"fmt"
 	"math/big"
 
 	"github.com/ethereum/go-ethereum/common"
@@ -35,6 +34,7 @@ var (
 	errReturnDataOutOfBounds = errors.New("evm: return data out of bounds")
 	errExecutionReverted     = errors.New("evm: execution reverted")
 	errMaxCodeSizeExceeded   = errors.New("evm: max code size exceeded")
+	errInvalidJump           = errors.New("evm: invalid jump destination")
 )
 
 func opAdd(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
@@ -405,7 +405,7 @@ func opSha3(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory
 }
 
 func opAddress(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
-	stack.push(contract.Address().Big())
+	stack.push(interpreter.intPool.get().SetBytes(contract.Address().Bytes()))
 	return nil, nil
 }
 
@@ -416,12 +416,12 @@ func opBalance(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memo
 }
 
 func opOrigin(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
-	stack.push(interpreter.evm.Origin.Big())
+	stack.push(interpreter.intPool.get().SetBytes(interpreter.evm.Origin.Bytes()))
 	return nil, nil
 }
 
 func opCaller(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
-	stack.push(contract.Caller().Big())
+	stack.push(interpreter.intPool.get().SetBytes(contract.Caller().Bytes()))
 	return nil, nil
 }
 
@@ -467,7 +467,7 @@ func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contrac
 	)
 	defer interpreter.intPool.put(memOffset, dataOffset, length, end)
 
-	if end.BitLen() > 64 || uint64(len(interpreter.returnData)) < end.Uint64() {
+	if !end.IsUint64() || uint64(len(interpreter.returnData)) < end.Uint64() {
 		return nil, errReturnDataOutOfBounds
 	}
 	memory.Set(memOffset.Uint64(), length.Uint64(), interpreter.returnData[dataOffset.Uint64():end.Uint64()])
@@ -572,7 +572,7 @@ func opBlockhash(pc *uint64, interpreter *EVMInterpreter, contract *Contract, me
 }
 
 func opCoinbase(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
-	stack.push(interpreter.evm.Coinbase.Big())
+	stack.push(interpreter.intPool.get().SetBytes(interpreter.evm.Coinbase.Bytes()))
 	return nil, nil
 }
 
@@ -645,8 +645,7 @@ func opSstore(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor
 func opJump(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	pos := stack.pop()
 	if !contract.validJumpdest(pos) {
-		nop := contract.GetOp(pos.Uint64())
-		return nil, fmt.Errorf("invalid jump destination (%v) %v", nop, pos)
+		return nil, errInvalidJump
 	}
 	*pc = pos.Uint64()
 
@@ -658,8 +657,7 @@ func opJumpi(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory
 	pos, cond := stack.pop(), stack.pop()
 	if cond.Sign() != 0 {
 		if !contract.validJumpdest(pos) {
-			nop := contract.GetOp(pos.Uint64())
-			return nil, fmt.Errorf("invalid jump destination (%v) %v", nop, pos)
+			return nil, errInvalidJump
 		}
 		*pc = pos.Uint64()
 	} else {
@@ -711,7 +709,7 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor
 	} else if suberr != nil && suberr != ErrCodeStoreOutOfGas {
 		stack.push(interpreter.intPool.getZero())
 	} else {
-		stack.push(addr.Big())
+		stack.push(interpreter.intPool.get().SetBytes(addr.Bytes()))
 	}
 	contract.Gas += returnGas
 	interpreter.intPool.put(value, offset, size)
@@ -739,7 +737,7 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memo
 	if suberr != nil {
 		stack.push(interpreter.intPool.getZero())
 	} else {
-		stack.push(addr.Big())
+		stack.push(interpreter.intPool.get().SetBytes(addr.Bytes()))
 	}
 	contract.Gas += returnGas
 	interpreter.intPool.put(endowment, offset, size, salt)
@@ -912,6 +910,21 @@ func makeLog(size int) executionFunc {
 	}
 }
 
+// opPush1 is a specialized version of pushN
+func opPush1(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+	var (
+		codeLen = uint64(len(contract.Code))
+		integer = interpreter.intPool.get()
+	)
+	*pc += 1
+	if *pc < codeLen {
+		stack.push(integer.SetUint64(uint64(contract.Code[*pc])))
+	} else {
+		stack.push(integer.SetUint64(0))
+	}
+	return nil, nil
+}
+
 // make push instruction function
 func makePush(size uint64, pushByteSize int) executionFunc {
 	return func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {

+ 27 - 24
core/vm/interpreter.go

@@ -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,19 +201,35 @@ 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).Sign() != 0) {
+				return nil, errWriteProtection
+			}
+		}
+		// Static portion of gas
+		if !contract.UseGas(operation.constantGas) {
+			return nil, ErrOutOfGas
 		}
 
 		var memorySize uint64
 		// calculate the new memory size and expand the memory to fit
 		// the operation
+		// Memory check needs to be done prior to evaluating the dynamic gas portion,
+		// to detect calculation overflows
 		if operation.memorySize != nil {
-			memSize, overflow := bigUint64(operation.memorySize(stack))
+			memSize, overflow := operation.memorySize(stack)
 			if overflow {
 				return nil, errGasUintOverflow
 			}
@@ -239,11 +239,14 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
 				return nil, errGasUintOverflow
 			}
 		}
+		// Dynamic portion of gas
 		// consume the gas and return an error if not enough gas is available.
 		// cost is explicitly set so that the capture state defer method can get the proper cost
-		cost, err = operation.gasCost(in.gasTable, in.evm, contract, stack, mem, memorySize)
-		if err != nil || !contract.UseGas(cost) {
-			return nil, ErrOutOfGas
+		if operation.dynamicGas != nil {
+			cost, err = operation.dynamicGas(in.gasTable, in.evm, contract, stack, mem, memorySize)
+			if err != nil || !contract.UseGas(cost) {
+				return nil, ErrOutOfGas
+			}
 		}
 		if memorySize > 0 {
 			mem.Resize(memorySize)

+ 750 - 608
core/vm/jump_table.go

@@ -18,27 +18,30 @@ package vm
 
 import (
 	"errors"
-	"math/big"
 
 	"github.com/ethereum/go-ethereum/params"
 )
 
 type (
-	executionFunc       func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error)
-	gasFunc             func(params.GasTable, *EVM, *Contract, *Stack, *Memory, uint64) (uint64, error) // last parameter is the requested memory size as a uint64
-	stackValidationFunc func(*Stack) error
-	memorySizeFunc      func(*Stack) *big.Int
+	executionFunc func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error)
+	gasFunc       func(params.GasTable, *EVM, *Contract, *Stack, *Memory, uint64) (uint64, error) // last parameter is the requested memory size as a uint64
+	// memorySizeFunc returns the required size, and whether the operation overflowed a uint64
+	memorySizeFunc func(*Stack) (size uint64, overflow bool)
 )
 
 var errGasUintOverflow = errors.New("gas uint64 overflow")
 
 type operation struct {
 	// execute is the operation function
-	execute executionFunc
-	// gasCost is the gas function and returns the gas required for execution
-	gasCost gasFunc
-	// validateStack validates the stack (size) for the operation
-	validateStack stackValidationFunc
+	execute     executionFunc
+	constantGas uint64
+	dynamicGas  gasFunc
+	// minStack tells how many stack items are required
+	minStack int
+	// maxStack specifies the max length the stack can have for this operation
+	// to not overflow the stack.
+	maxStack int
+
 	// memorySize returns the memory size required for the operation
 	memorySize memorySizeFunc
 
@@ -63,37 +66,42 @@ func newConstantinopleInstructionSet() [256]operation {
 	// instructions that can be executed during the byzantium phase.
 	instructionSet := newByzantiumInstructionSet()
 	instructionSet[SHL] = operation{
-		execute:       opSHL,
-		gasCost:       constGasFunc(GasFastestStep),
-		validateStack: makeStackFunc(2, 1),
-		valid:         true,
+		execute:     opSHL,
+		constantGas: GasFastestStep,
+		minStack:    minStack(2, 1),
+		maxStack:    maxStack(2, 1),
+		valid:       true,
 	}
 	instructionSet[SHR] = operation{
-		execute:       opSHR,
-		gasCost:       constGasFunc(GasFastestStep),
-		validateStack: makeStackFunc(2, 1),
-		valid:         true,
+		execute:     opSHR,
+		constantGas: GasFastestStep,
+		minStack:    minStack(2, 1),
+		maxStack:    maxStack(2, 1),
+		valid:       true,
 	}
 	instructionSet[SAR] = operation{
-		execute:       opSAR,
-		gasCost:       constGasFunc(GasFastestStep),
-		validateStack: makeStackFunc(2, 1),
-		valid:         true,
+		execute:     opSAR,
+		constantGas: GasFastestStep,
+		minStack:    minStack(2, 1),
+		maxStack:    maxStack(2, 1),
+		valid:       true,
 	}
 	instructionSet[EXTCODEHASH] = operation{
-		execute:       opExtCodeHash,
-		gasCost:       gasExtCodeHash,
-		validateStack: makeStackFunc(1, 1),
-		valid:         true,
+		execute:    opExtCodeHash,
+		dynamicGas: gasExtCodeHash,
+		minStack:   minStack(1, 1),
+		maxStack:   maxStack(1, 1),
+		valid:      true,
 	}
 	instructionSet[CREATE2] = operation{
-		execute:       opCreate2,
-		gasCost:       gasCreate2,
-		validateStack: makeStackFunc(4, 1),
-		memorySize:    memoryCreate2,
-		valid:         true,
-		writes:        true,
-		returns:       true,
+		execute:    opCreate2,
+		dynamicGas: gasCreate2,
+		minStack:   minStack(4, 1),
+		maxStack:   maxStack(4, 1),
+		memorySize: memoryCreate2,
+		valid:      true,
+		writes:     true,
+		returns:    true,
 	}
 	return instructionSet
 }
@@ -104,34 +112,38 @@ func newByzantiumInstructionSet() [256]operation {
 	// instructions that can be executed during the homestead phase.
 	instructionSet := newHomesteadInstructionSet()
 	instructionSet[STATICCALL] = operation{
-		execute:       opStaticCall,
-		gasCost:       gasStaticCall,
-		validateStack: makeStackFunc(6, 1),
-		memorySize:    memoryStaticCall,
-		valid:         true,
-		returns:       true,
+		execute:    opStaticCall,
+		dynamicGas: gasStaticCall,
+		minStack:   minStack(6, 1),
+		maxStack:   maxStack(6, 1),
+		memorySize: memoryStaticCall,
+		valid:      true,
+		returns:    true,
 	}
 	instructionSet[RETURNDATASIZE] = operation{
-		execute:       opReturnDataSize,
-		gasCost:       constGasFunc(GasQuickStep),
-		validateStack: makeStackFunc(0, 1),
-		valid:         true,
+		execute:     opReturnDataSize,
+		constantGas: GasQuickStep,
+		minStack:    minStack(0, 1),
+		maxStack:    maxStack(0, 1),
+		valid:       true,
 	}
 	instructionSet[RETURNDATACOPY] = operation{
-		execute:       opReturnDataCopy,
-		gasCost:       gasReturnDataCopy,
-		validateStack: makeStackFunc(3, 0),
-		memorySize:    memoryReturnDataCopy,
-		valid:         true,
+		execute:    opReturnDataCopy,
+		dynamicGas: gasReturnDataCopy,
+		minStack:   minStack(3, 0),
+		maxStack:   maxStack(3, 0),
+		memorySize: memoryReturnDataCopy,
+		valid:      true,
 	}
 	instructionSet[REVERT] = operation{
-		execute:       opRevert,
-		gasCost:       gasRevert,
-		validateStack: makeStackFunc(2, 0),
-		memorySize:    memoryRevert,
-		valid:         true,
-		reverts:       true,
-		returns:       true,
+		execute:    opRevert,
+		dynamicGas: gasRevert,
+		minStack:   minStack(2, 0),
+		maxStack:   maxStack(2, 0),
+		memorySize: memoryRevert,
+		valid:      true,
+		reverts:    true,
+		returns:    true,
 	}
 	return instructionSet
 }
@@ -141,12 +153,13 @@ func newByzantiumInstructionSet() [256]operation {
 func newHomesteadInstructionSet() [256]operation {
 	instructionSet := newFrontierInstructionSet()
 	instructionSet[DELEGATECALL] = operation{
-		execute:       opDelegateCall,
-		gasCost:       gasDelegateCall,
-		validateStack: makeStackFunc(6, 1),
-		memorySize:    memoryDelegateCall,
-		valid:         true,
-		returns:       true,
+		execute:    opDelegateCall,
+		dynamicGas: gasDelegateCall,
+		minStack:   minStack(6, 1),
+		maxStack:   maxStack(6, 1),
+		memorySize: memoryDelegateCall,
+		valid:      true,
+		returns:    true,
 	}
 	return instructionSet
 }
@@ -156,811 +169,940 @@ func newHomesteadInstructionSet() [256]operation {
 func newFrontierInstructionSet() [256]operation {
 	return [256]operation{
 		STOP: {
-			execute:       opStop,
-			gasCost:       constGasFunc(0),
-			validateStack: makeStackFunc(0, 0),
-			halts:         true,
-			valid:         true,
+			execute:     opStop,
+			constantGas: 0,
+			minStack:    minStack(0, 0),
+			maxStack:    maxStack(0, 0),
+			halts:       true,
+			valid:       true,
 		},
 		ADD: {
-			execute:       opAdd,
-			gasCost:       constGasFunc(GasFastestStep),
-			validateStack: makeStackFunc(2, 1),
-			valid:         true,
+			execute:     opAdd,
+			constantGas: GasFastestStep,
+			minStack:    minStack(2, 1),
+			maxStack:    maxStack(2, 1),
+			valid:       true,
 		},
 		MUL: {
-			execute:       opMul,
-			gasCost:       constGasFunc(GasFastStep),
-			validateStack: makeStackFunc(2, 1),
-			valid:         true,
+			execute:     opMul,
+			constantGas: GasFastStep,
+			minStack:    minStack(2, 1),
+			maxStack:    maxStack(2, 1),
+			valid:       true,
 		},
 		SUB: {
-			execute:       opSub,
-			gasCost:       constGasFunc(GasFastestStep),
-			validateStack: makeStackFunc(2, 1),
-			valid:         true,
+			execute:     opSub,
+			constantGas: GasFastestStep,
+			minStack:    minStack(2, 1),
+			maxStack:    maxStack(2, 1),
+			valid:       true,
 		},
 		DIV: {
-			execute:       opDiv,
-			gasCost:       constGasFunc(GasFastStep),
-			validateStack: makeStackFunc(2, 1),
-			valid:         true,
+			execute:     opDiv,
+			constantGas: GasFastStep,
+			minStack:    minStack(2, 1),
+			maxStack:    maxStack(2, 1),
+			valid:       true,
 		},
 		SDIV: {
-			execute:       opSdiv,
-			gasCost:       constGasFunc(GasFastStep),
-			validateStack: makeStackFunc(2, 1),
-			valid:         true,
+			execute:     opSdiv,
+			constantGas: GasFastStep,
+			minStack:    minStack(2, 1),
+			maxStack:    maxStack(2, 1),
+			valid:       true,
 		},
 		MOD: {
-			execute:       opMod,
-			gasCost:       constGasFunc(GasFastStep),
-			validateStack: makeStackFunc(2, 1),
-			valid:         true,
+			execute:     opMod,
+			constantGas: GasFastStep,
+			minStack:    minStack(2, 1),
+			maxStack:    maxStack(2, 1),
+			valid:       true,
 		},
 		SMOD: {
-			execute:       opSmod,
-			gasCost:       constGasFunc(GasFastStep),
-			validateStack: makeStackFunc(2, 1),
-			valid:         true,
+			execute:     opSmod,
+			constantGas: GasFastStep,
+			minStack:    minStack(2, 1),
+			maxStack:    maxStack(2, 1),
+			valid:       true,
 		},
 		ADDMOD: {
-			execute:       opAddmod,
-			gasCost:       constGasFunc(GasMidStep),
-			validateStack: makeStackFunc(3, 1),
-			valid:         true,
+			execute:     opAddmod,
+			constantGas: GasMidStep,
+			minStack:    minStack(3, 1),
+			maxStack:    maxStack(3, 1),
+			valid:       true,
 		},
 		MULMOD: {
-			execute:       opMulmod,
-			gasCost:       constGasFunc(GasMidStep),
-			validateStack: makeStackFunc(3, 1),
-			valid:         true,
+			execute:     opMulmod,
+			constantGas: GasMidStep,
+			minStack:    minStack(3, 1),
+			maxStack:    maxStack(3, 1),
+			valid:       true,
 		},
 		EXP: {
-			execute:       opExp,
-			gasCost:       gasExp,
-			validateStack: makeStackFunc(2, 1),
-			valid:         true,
+			execute:    opExp,
+			dynamicGas: gasExp,
+			minStack:   minStack(2, 1),
+			maxStack:   maxStack(2, 1),
+			valid:      true,
 		},
 		SIGNEXTEND: {
-			execute:       opSignExtend,
-			gasCost:       constGasFunc(GasFastStep),
-			validateStack: makeStackFunc(2, 1),
-			valid:         true,
+			execute:     opSignExtend,
+			constantGas: GasFastStep,
+			minStack:    minStack(2, 1),
+			maxStack:    maxStack(2, 1),
+			valid:       true,
 		},
 		LT: {
-			execute:       opLt,
-			gasCost:       constGasFunc(GasFastestStep),
-			validateStack: makeStackFunc(2, 1),
-			valid:         true,
+			execute:     opLt,
+			constantGas: GasFastestStep,
+			minStack:    minStack(2, 1),
+			maxStack:    maxStack(2, 1),
+			valid:       true,
 		},
 		GT: {
-			execute:       opGt,
-			gasCost:       constGasFunc(GasFastestStep),
-			validateStack: makeStackFunc(2, 1),
-			valid:         true,
+			execute:     opGt,
+			constantGas: GasFastestStep,
+			minStack:    minStack(2, 1),
+			maxStack:    maxStack(2, 1),
+			valid:       true,
 		},
 		SLT: {
-			execute:       opSlt,
-			gasCost:       constGasFunc(GasFastestStep),
-			validateStack: makeStackFunc(2, 1),
-			valid:         true,
+			execute:     opSlt,
+			constantGas: GasFastestStep,
+			minStack:    minStack(2, 1),
+			maxStack:    maxStack(2, 1),
+			valid:       true,
 		},
 		SGT: {
-			execute:       opSgt,
-			gasCost:       constGasFunc(GasFastestStep),
-			validateStack: makeStackFunc(2, 1),
-			valid:         true,
+			execute:     opSgt,
+			constantGas: GasFastestStep,
+			minStack:    minStack(2, 1),
+			maxStack:    maxStack(2, 1),
+			valid:       true,
 		},
 		EQ: {
-			execute:       opEq,
-			gasCost:       constGasFunc(GasFastestStep),
-			validateStack: makeStackFunc(2, 1),
-			valid:         true,
+			execute:     opEq,
+			constantGas: GasFastestStep,
+			minStack:    minStack(2, 1),
+			maxStack:    maxStack(2, 1),
+			valid:       true,
 		},
 		ISZERO: {
-			execute:       opIszero,
-			gasCost:       constGasFunc(GasFastestStep),
-			validateStack: makeStackFunc(1, 1),
-			valid:         true,
+			execute:     opIszero,
+			constantGas: GasFastestStep,
+			minStack:    minStack(1, 1),
+			maxStack:    maxStack(1, 1),
+			valid:       true,
 		},
 		AND: {
-			execute:       opAnd,
-			gasCost:       constGasFunc(GasFastestStep),
-			validateStack: makeStackFunc(2, 1),
-			valid:         true,
+			execute:     opAnd,
+			constantGas: GasFastestStep,
+			minStack:    minStack(2, 1),
+			maxStack:    maxStack(2, 1),
+			valid:       true,
 		},
 		XOR: {
-			execute:       opXor,
-			gasCost:       constGasFunc(GasFastestStep),
-			validateStack: makeStackFunc(2, 1),
-			valid:         true,
+			execute:     opXor,
+			constantGas: GasFastestStep,
+			minStack:    minStack(2, 1),
+			maxStack:    maxStack(2, 1),
+			valid:       true,
 		},
 		OR: {
-			execute:       opOr,
-			gasCost:       constGasFunc(GasFastestStep),
-			validateStack: makeStackFunc(2, 1),
-			valid:         true,
+			execute:     opOr,
+			constantGas: GasFastestStep,
+			minStack:    minStack(2, 1),
+			maxStack:    maxStack(2, 1),
+			valid:       true,
 		},
 		NOT: {
-			execute:       opNot,
-			gasCost:       constGasFunc(GasFastestStep),
-			validateStack: makeStackFunc(1, 1),
-			valid:         true,
+			execute:     opNot,
+			constantGas: GasFastestStep,
+			minStack:    minStack(1, 1),
+			maxStack:    maxStack(1, 1),
+			valid:       true,
 		},
 		BYTE: {
-			execute:       opByte,
-			gasCost:       constGasFunc(GasFastestStep),
-			validateStack: makeStackFunc(2, 1),
-			valid:         true,
+			execute:     opByte,
+			constantGas: GasFastestStep,
+			minStack:    minStack(2, 1),
+			maxStack:    maxStack(2, 1),
+			valid:       true,
 		},
 		SHA3: {
-			execute:       opSha3,
-			gasCost:       gasSha3,
-			validateStack: makeStackFunc(2, 1),
-			memorySize:    memorySha3,
-			valid:         true,
+			execute:    opSha3,
+			dynamicGas: gasSha3,
+			minStack:   minStack(2, 1),
+			maxStack:   maxStack(2, 1),
+			memorySize: memorySha3,
+			valid:      true,
 		},
 		ADDRESS: {
-			execute:       opAddress,
-			gasCost:       constGasFunc(GasQuickStep),
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     opAddress,
+			constantGas: GasQuickStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		BALANCE: {
-			execute:       opBalance,
-			gasCost:       gasBalance,
-			validateStack: makeStackFunc(1, 1),
-			valid:         true,
+			execute:    opBalance,
+			dynamicGas: gasBalance,
+			minStack:   minStack(1, 1),
+			maxStack:   maxStack(1, 1),
+			valid:      true,
 		},
 		ORIGIN: {
-			execute:       opOrigin,
-			gasCost:       constGasFunc(GasQuickStep),
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     opOrigin,
+			constantGas: GasQuickStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		CALLER: {
-			execute:       opCaller,
-			gasCost:       constGasFunc(GasQuickStep),
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     opCaller,
+			constantGas: GasQuickStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		CALLVALUE: {
-			execute:       opCallValue,
-			gasCost:       constGasFunc(GasQuickStep),
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     opCallValue,
+			constantGas: GasQuickStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		CALLDATALOAD: {
-			execute:       opCallDataLoad,
-			gasCost:       constGasFunc(GasFastestStep),
-			validateStack: makeStackFunc(1, 1),
-			valid:         true,
+			execute:     opCallDataLoad,
+			constantGas: GasFastestStep,
+			minStack:    minStack(1, 1),
+			maxStack:    maxStack(1, 1),
+			valid:       true,
 		},
 		CALLDATASIZE: {
-			execute:       opCallDataSize,
-			gasCost:       constGasFunc(GasQuickStep),
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     opCallDataSize,
+			constantGas: GasQuickStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		CALLDATACOPY: {
-			execute:       opCallDataCopy,
-			gasCost:       gasCallDataCopy,
-			validateStack: makeStackFunc(3, 0),
-			memorySize:    memoryCallDataCopy,
-			valid:         true,
+			execute:    opCallDataCopy,
+			dynamicGas: gasCallDataCopy,
+			minStack:   minStack(3, 0),
+			maxStack:   maxStack(3, 0),
+			memorySize: memoryCallDataCopy,
+			valid:      true,
 		},
 		CODESIZE: {
-			execute:       opCodeSize,
-			gasCost:       constGasFunc(GasQuickStep),
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     opCodeSize,
+			constantGas: GasQuickStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		CODECOPY: {
-			execute:       opCodeCopy,
-			gasCost:       gasCodeCopy,
-			validateStack: makeStackFunc(3, 0),
-			memorySize:    memoryCodeCopy,
-			valid:         true,
+			execute:    opCodeCopy,
+			dynamicGas: gasCodeCopy,
+			minStack:   minStack(3, 0),
+			maxStack:   maxStack(3, 0),
+			memorySize: memoryCodeCopy,
+			valid:      true,
 		},
 		GASPRICE: {
-			execute:       opGasprice,
-			gasCost:       constGasFunc(GasQuickStep),
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     opGasprice,
+			constantGas: GasQuickStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		EXTCODESIZE: {
-			execute:       opExtCodeSize,
-			gasCost:       gasExtCodeSize,
-			validateStack: makeStackFunc(1, 1),
-			valid:         true,
+			execute:    opExtCodeSize,
+			dynamicGas: gasExtCodeSize,
+			minStack:   minStack(1, 1),
+			maxStack:   maxStack(1, 1),
+			valid:      true,
 		},
 		EXTCODECOPY: {
-			execute:       opExtCodeCopy,
-			gasCost:       gasExtCodeCopy,
-			validateStack: makeStackFunc(4, 0),
-			memorySize:    memoryExtCodeCopy,
-			valid:         true,
+			execute:    opExtCodeCopy,
+			dynamicGas: gasExtCodeCopy,
+			minStack:   minStack(4, 0),
+			maxStack:   maxStack(4, 0),
+			memorySize: memoryExtCodeCopy,
+			valid:      true,
 		},
 		BLOCKHASH: {
-			execute:       opBlockhash,
-			gasCost:       constGasFunc(GasExtStep),
-			validateStack: makeStackFunc(1, 1),
-			valid:         true,
+			execute:     opBlockhash,
+			constantGas: GasExtStep,
+			minStack:    minStack(1, 1),
+			maxStack:    maxStack(1, 1),
+			valid:       true,
 		},
 		COINBASE: {
-			execute:       opCoinbase,
-			gasCost:       constGasFunc(GasQuickStep),
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     opCoinbase,
+			constantGas: GasQuickStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		TIMESTAMP: {
-			execute:       opTimestamp,
-			gasCost:       constGasFunc(GasQuickStep),
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     opTimestamp,
+			constantGas: GasQuickStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		NUMBER: {
-			execute:       opNumber,
-			gasCost:       constGasFunc(GasQuickStep),
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     opNumber,
+			constantGas: GasQuickStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		DIFFICULTY: {
-			execute:       opDifficulty,
-			gasCost:       constGasFunc(GasQuickStep),
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     opDifficulty,
+			constantGas: GasQuickStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		GASLIMIT: {
-			execute:       opGasLimit,
-			gasCost:       constGasFunc(GasQuickStep),
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     opGasLimit,
+			constantGas: GasQuickStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		POP: {
-			execute:       opPop,
-			gasCost:       constGasFunc(GasQuickStep),
-			validateStack: makeStackFunc(1, 0),
-			valid:         true,
+			execute:     opPop,
+			constantGas: GasQuickStep,
+			minStack:    minStack(1, 0),
+			maxStack:    maxStack(1, 0),
+			valid:       true,
 		},
 		MLOAD: {
-			execute:       opMload,
-			gasCost:       gasMLoad,
-			validateStack: makeStackFunc(1, 1),
-			memorySize:    memoryMLoad,
-			valid:         true,
+			execute:    opMload,
+			dynamicGas: gasMLoad,
+			minStack:   minStack(1, 1),
+			maxStack:   maxStack(1, 1),
+			memorySize: memoryMLoad,
+			valid:      true,
 		},
 		MSTORE: {
-			execute:       opMstore,
-			gasCost:       gasMStore,
-			validateStack: makeStackFunc(2, 0),
-			memorySize:    memoryMStore,
-			valid:         true,
+			execute:    opMstore,
+			dynamicGas: gasMStore,
+			minStack:   minStack(2, 0),
+			maxStack:   maxStack(2, 0),
+			memorySize: memoryMStore,
+			valid:      true,
 		},
 		MSTORE8: {
-			execute:       opMstore8,
-			gasCost:       gasMStore8,
-			memorySize:    memoryMStore8,
-			validateStack: makeStackFunc(2, 0),
+			execute:    opMstore8,
+			dynamicGas: gasMStore8,
+			memorySize: memoryMStore8,
+			minStack:   minStack(2, 0),
+			maxStack:   maxStack(2, 0),
 
 			valid: true,
 		},
 		SLOAD: {
-			execute:       opSload,
-			gasCost:       gasSLoad,
-			validateStack: makeStackFunc(1, 1),
-			valid:         true,
+			execute:    opSload,
+			dynamicGas: gasSLoad,
+			minStack:   minStack(1, 1),
+			maxStack:   maxStack(1, 1),
+			valid:      true,
 		},
 		SSTORE: {
-			execute:       opSstore,
-			gasCost:       gasSStore,
-			validateStack: makeStackFunc(2, 0),
-			valid:         true,
-			writes:        true,
+			execute:    opSstore,
+			dynamicGas: gasSStore,
+			minStack:   minStack(2, 0),
+			maxStack:   maxStack(2, 0),
+			valid:      true,
+			writes:     true,
 		},
 		JUMP: {
-			execute:       opJump,
-			gasCost:       constGasFunc(GasMidStep),
-			validateStack: makeStackFunc(1, 0),
-			jumps:         true,
-			valid:         true,
+			execute:     opJump,
+			constantGas: GasMidStep,
+			minStack:    minStack(1, 0),
+			maxStack:    maxStack(1, 0),
+			jumps:       true,
+			valid:       true,
 		},
 		JUMPI: {
-			execute:       opJumpi,
-			gasCost:       constGasFunc(GasSlowStep),
-			validateStack: makeStackFunc(2, 0),
-			jumps:         true,
-			valid:         true,
+			execute:     opJumpi,
+			constantGas: GasSlowStep,
+			minStack:    minStack(2, 0),
+			maxStack:    maxStack(2, 0),
+			jumps:       true,
+			valid:       true,
 		},
 		PC: {
-			execute:       opPc,
-			gasCost:       constGasFunc(GasQuickStep),
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     opPc,
+			constantGas: GasQuickStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		MSIZE: {
-			execute:       opMsize,
-			gasCost:       constGasFunc(GasQuickStep),
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     opMsize,
+			constantGas: GasQuickStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		GAS: {
-			execute:       opGas,
-			gasCost:       constGasFunc(GasQuickStep),
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     opGas,
+			constantGas: GasQuickStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		JUMPDEST: {
-			execute:       opJumpdest,
-			gasCost:       constGasFunc(params.JumpdestGas),
-			validateStack: makeStackFunc(0, 0),
-			valid:         true,
+			execute:     opJumpdest,
+			constantGas: params.JumpdestGas,
+			minStack:    minStack(0, 0),
+			maxStack:    maxStack(0, 0),
+			valid:       true,
 		},
 		PUSH1: {
-			execute:       makePush(1, 1),
-			gasCost:       gasPush,
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     opPush1,
+			constantGas: GasFastestStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		PUSH2: {
-			execute:       makePush(2, 2),
-			gasCost:       gasPush,
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     makePush(2, 2),
+			constantGas: GasFastestStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		PUSH3: {
-			execute:       makePush(3, 3),
-			gasCost:       gasPush,
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     makePush(3, 3),
+			constantGas: GasFastestStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		PUSH4: {
-			execute:       makePush(4, 4),
-			gasCost:       gasPush,
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     makePush(4, 4),
+			constantGas: GasFastestStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		PUSH5: {
-			execute:       makePush(5, 5),
-			gasCost:       gasPush,
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     makePush(5, 5),
+			constantGas: GasFastestStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		PUSH6: {
-			execute:       makePush(6, 6),
-			gasCost:       gasPush,
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     makePush(6, 6),
+			constantGas: GasFastestStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		PUSH7: {
-			execute:       makePush(7, 7),
-			gasCost:       gasPush,
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     makePush(7, 7),
+			constantGas: GasFastestStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		PUSH8: {
-			execute:       makePush(8, 8),
-			gasCost:       gasPush,
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     makePush(8, 8),
+			constantGas: GasFastestStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		PUSH9: {
-			execute:       makePush(9, 9),
-			gasCost:       gasPush,
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     makePush(9, 9),
+			constantGas: GasFastestStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		PUSH10: {
-			execute:       makePush(10, 10),
-			gasCost:       gasPush,
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     makePush(10, 10),
+			constantGas: GasFastestStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		PUSH11: {
-			execute:       makePush(11, 11),
-			gasCost:       gasPush,
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     makePush(11, 11),
+			constantGas: GasFastestStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		PUSH12: {
-			execute:       makePush(12, 12),
-			gasCost:       gasPush,
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     makePush(12, 12),
+			constantGas: GasFastestStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		PUSH13: {
-			execute:       makePush(13, 13),
-			gasCost:       gasPush,
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     makePush(13, 13),
+			constantGas: GasFastestStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		PUSH14: {
-			execute:       makePush(14, 14),
-			gasCost:       gasPush,
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     makePush(14, 14),
+			constantGas: GasFastestStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		PUSH15: {
-			execute:       makePush(15, 15),
-			gasCost:       gasPush,
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     makePush(15, 15),
+			constantGas: GasFastestStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		PUSH16: {
-			execute:       makePush(16, 16),
-			gasCost:       gasPush,
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     makePush(16, 16),
+			constantGas: GasFastestStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		PUSH17: {
-			execute:       makePush(17, 17),
-			gasCost:       gasPush,
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     makePush(17, 17),
+			constantGas: GasFastestStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		PUSH18: {
-			execute:       makePush(18, 18),
-			gasCost:       gasPush,
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     makePush(18, 18),
+			constantGas: GasFastestStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		PUSH19: {
-			execute:       makePush(19, 19),
-			gasCost:       gasPush,
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     makePush(19, 19),
+			constantGas: GasFastestStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		PUSH20: {
-			execute:       makePush(20, 20),
-			gasCost:       gasPush,
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     makePush(20, 20),
+			constantGas: GasFastestStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		PUSH21: {
-			execute:       makePush(21, 21),
-			gasCost:       gasPush,
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     makePush(21, 21),
+			constantGas: GasFastestStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		PUSH22: {
-			execute:       makePush(22, 22),
-			gasCost:       gasPush,
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     makePush(22, 22),
+			constantGas: GasFastestStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		PUSH23: {
-			execute:       makePush(23, 23),
-			gasCost:       gasPush,
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     makePush(23, 23),
+			constantGas: GasFastestStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		PUSH24: {
-			execute:       makePush(24, 24),
-			gasCost:       gasPush,
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     makePush(24, 24),
+			constantGas: GasFastestStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		PUSH25: {
-			execute:       makePush(25, 25),
-			gasCost:       gasPush,
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     makePush(25, 25),
+			constantGas: GasFastestStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		PUSH26: {
-			execute:       makePush(26, 26),
-			gasCost:       gasPush,
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     makePush(26, 26),
+			constantGas: GasFastestStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		PUSH27: {
-			execute:       makePush(27, 27),
-			gasCost:       gasPush,
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     makePush(27, 27),
+			constantGas: GasFastestStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		PUSH28: {
-			execute:       makePush(28, 28),
-			gasCost:       gasPush,
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     makePush(28, 28),
+			constantGas: GasFastestStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		PUSH29: {
-			execute:       makePush(29, 29),
-			gasCost:       gasPush,
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     makePush(29, 29),
+			constantGas: GasFastestStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		PUSH30: {
-			execute:       makePush(30, 30),
-			gasCost:       gasPush,
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     makePush(30, 30),
+			constantGas: GasFastestStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		PUSH31: {
-			execute:       makePush(31, 31),
-			gasCost:       gasPush,
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     makePush(31, 31),
+			constantGas: GasFastestStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		PUSH32: {
-			execute:       makePush(32, 32),
-			gasCost:       gasPush,
-			validateStack: makeStackFunc(0, 1),
-			valid:         true,
+			execute:     makePush(32, 32),
+			constantGas: GasFastestStep,
+			minStack:    minStack(0, 1),
+			maxStack:    maxStack(0, 1),
+			valid:       true,
 		},
 		DUP1: {
-			execute:       makeDup(1),
-			gasCost:       gasDup,
-			validateStack: makeDupStackFunc(1),
-			valid:         true,
+			execute:     makeDup(1),
+			constantGas: GasFastestStep,
+			minStack:    minDupStack(1),
+			maxStack:    maxDupStack(1),
+			valid:       true,
 		},
 		DUP2: {
-			execute:       makeDup(2),
-			gasCost:       gasDup,
-			validateStack: makeDupStackFunc(2),
-			valid:         true,
+			execute:     makeDup(2),
+			constantGas: GasFastestStep,
+			minStack:    minDupStack(2),
+			maxStack:    maxDupStack(2),
+			valid:       true,
 		},
 		DUP3: {
-			execute:       makeDup(3),
-			gasCost:       gasDup,
-			validateStack: makeDupStackFunc(3),
-			valid:         true,
+			execute:     makeDup(3),
+			constantGas: GasFastestStep,
+			minStack:    minDupStack(3),
+			maxStack:    maxDupStack(3),
+			valid:       true,
 		},
 		DUP4: {
-			execute:       makeDup(4),
-			gasCost:       gasDup,
-			validateStack: makeDupStackFunc(4),
-			valid:         true,
+			execute:     makeDup(4),
+			constantGas: GasFastestStep,
+			minStack:    minDupStack(4),
+			maxStack:    maxDupStack(4),
+			valid:       true,
 		},
 		DUP5: {
-			execute:       makeDup(5),
-			gasCost:       gasDup,
-			validateStack: makeDupStackFunc(5),
-			valid:         true,
+			execute:     makeDup(5),
+			constantGas: GasFastestStep,
+			minStack:    minDupStack(5),
+			maxStack:    maxDupStack(5),
+			valid:       true,
 		},
 		DUP6: {
-			execute:       makeDup(6),
-			gasCost:       gasDup,
-			validateStack: makeDupStackFunc(6),
-			valid:         true,
+			execute:     makeDup(6),
+			constantGas: GasFastestStep,
+			minStack:    minDupStack(6),
+			maxStack:    maxDupStack(6),
+			valid:       true,
 		},
 		DUP7: {
-			execute:       makeDup(7),
-			gasCost:       gasDup,
-			validateStack: makeDupStackFunc(7),
-			valid:         true,
+			execute:     makeDup(7),
+			constantGas: GasFastestStep,
+			minStack:    minDupStack(7),
+			maxStack:    maxDupStack(7),
+			valid:       true,
 		},
 		DUP8: {
-			execute:       makeDup(8),
-			gasCost:       gasDup,
-			validateStack: makeDupStackFunc(8),
-			valid:         true,
+			execute:     makeDup(8),
+			constantGas: GasFastestStep,
+			minStack:    minDupStack(8),
+			maxStack:    maxDupStack(8),
+			valid:       true,
 		},
 		DUP9: {
-			execute:       makeDup(9),
-			gasCost:       gasDup,
-			validateStack: makeDupStackFunc(9),
-			valid:         true,
+			execute:     makeDup(9),
+			constantGas: GasFastestStep,
+			minStack:    minDupStack(9),
+			maxStack:    maxDupStack(9),
+			valid:       true,
 		},
 		DUP10: {
-			execute:       makeDup(10),
-			gasCost:       gasDup,
-			validateStack: makeDupStackFunc(10),
-			valid:         true,
+			execute:     makeDup(10),
+			constantGas: GasFastestStep,
+			minStack:    minDupStack(10),
+			maxStack:    maxDupStack(10),
+			valid:       true,
 		},
 		DUP11: {
-			execute:       makeDup(11),
-			gasCost:       gasDup,
-			validateStack: makeDupStackFunc(11),
-			valid:         true,
+			execute:     makeDup(11),
+			constantGas: GasFastestStep,
+			minStack:    minDupStack(11),
+			maxStack:    maxDupStack(11),
+			valid:       true,
 		},
 		DUP12: {
-			execute:       makeDup(12),
-			gasCost:       gasDup,
-			validateStack: makeDupStackFunc(12),
-			valid:         true,
+			execute:     makeDup(12),
+			constantGas: GasFastestStep,
+			minStack:    minDupStack(12),
+			maxStack:    maxDupStack(12),
+			valid:       true,
 		},
 		DUP13: {
-			execute:       makeDup(13),
-			gasCost:       gasDup,
-			validateStack: makeDupStackFunc(13),
-			valid:         true,
+			execute:     makeDup(13),
+			constantGas: GasFastestStep,
+			minStack:    minDupStack(13),
+			maxStack:    maxDupStack(13),
+			valid:       true,
 		},
 		DUP14: {
-			execute:       makeDup(14),
-			gasCost:       gasDup,
-			validateStack: makeDupStackFunc(14),
-			valid:         true,
+			execute:     makeDup(14),
+			constantGas: GasFastestStep,
+			minStack:    minDupStack(14),
+			maxStack:    maxDupStack(14),
+			valid:       true,
 		},
 		DUP15: {
-			execute:       makeDup(15),
-			gasCost:       gasDup,
-			validateStack: makeDupStackFunc(15),
-			valid:         true,
+			execute:     makeDup(15),
+			constantGas: GasFastestStep,
+			minStack:    minDupStack(15),
+			maxStack:    maxDupStack(15),
+			valid:       true,
 		},
 		DUP16: {
-			execute:       makeDup(16),
-			gasCost:       gasDup,
-			validateStack: makeDupStackFunc(16),
-			valid:         true,
+			execute:     makeDup(16),
+			constantGas: GasFastestStep,
+			minStack:    minDupStack(16),
+			maxStack:    maxDupStack(16),
+			valid:       true,
 		},
 		SWAP1: {
-			execute:       makeSwap(1),
-			gasCost:       gasSwap,
-			validateStack: makeSwapStackFunc(2),
-			valid:         true,
+			execute:     makeSwap(1),
+			constantGas: GasFastestStep,
+			minStack:    minSwapStack(2),
+			maxStack:    maxSwapStack(2),
+			valid:       true,
 		},
 		SWAP2: {
-			execute:       makeSwap(2),
-			gasCost:       gasSwap,
-			validateStack: makeSwapStackFunc(3),
-			valid:         true,
+			execute:     makeSwap(2),
+			constantGas: GasFastestStep,
+			minStack:    minSwapStack(3),
+			maxStack:    maxSwapStack(3),
+			valid:       true,
 		},
 		SWAP3: {
-			execute:       makeSwap(3),
-			gasCost:       gasSwap,
-			validateStack: makeSwapStackFunc(4),
-			valid:         true,
+			execute:     makeSwap(3),
+			constantGas: GasFastestStep,
+			minStack:    minSwapStack(4),
+			maxStack:    maxSwapStack(4),
+			valid:       true,
 		},
 		SWAP4: {
-			execute:       makeSwap(4),
-			gasCost:       gasSwap,
-			validateStack: makeSwapStackFunc(5),
-			valid:         true,
+			execute:     makeSwap(4),
+			constantGas: GasFastestStep,
+			minStack:    minSwapStack(5),
+			maxStack:    maxSwapStack(5),
+			valid:       true,
 		},
 		SWAP5: {
-			execute:       makeSwap(5),
-			gasCost:       gasSwap,
-			validateStack: makeSwapStackFunc(6),
-			valid:         true,
+			execute:     makeSwap(5),
+			constantGas: GasFastestStep,
+			minStack:    minSwapStack(6),
+			maxStack:    maxSwapStack(6),
+			valid:       true,
 		},
 		SWAP6: {
-			execute:       makeSwap(6),
-			gasCost:       gasSwap,
-			validateStack: makeSwapStackFunc(7),
-			valid:         true,
+			execute:     makeSwap(6),
+			constantGas: GasFastestStep,
+			minStack:    minSwapStack(7),
+			maxStack:    maxSwapStack(7),
+			valid:       true,
 		},
 		SWAP7: {
-			execute:       makeSwap(7),
-			gasCost:       gasSwap,
-			validateStack: makeSwapStackFunc(8),
-			valid:         true,
+			execute:     makeSwap(7),
+			constantGas: GasFastestStep,
+			minStack:    minSwapStack(8),
+			maxStack:    maxSwapStack(8),
+			valid:       true,
 		},
 		SWAP8: {
-			execute:       makeSwap(8),
-			gasCost:       gasSwap,
-			validateStack: makeSwapStackFunc(9),
-			valid:         true,
+			execute:     makeSwap(8),
+			constantGas: GasFastestStep,
+			minStack:    minSwapStack(9),
+			maxStack:    maxSwapStack(9),
+			valid:       true,
 		},
 		SWAP9: {
-			execute:       makeSwap(9),
-			gasCost:       gasSwap,
-			validateStack: makeSwapStackFunc(10),
-			valid:         true,
+			execute:     makeSwap(9),
+			constantGas: GasFastestStep,
+			minStack:    minSwapStack(10),
+			maxStack:    maxSwapStack(10),
+			valid:       true,
 		},
 		SWAP10: {
-			execute:       makeSwap(10),
-			gasCost:       gasSwap,
-			validateStack: makeSwapStackFunc(11),
-			valid:         true,
+			execute:     makeSwap(10),
+			constantGas: GasFastestStep,
+			minStack:    minSwapStack(11),
+			maxStack:    maxSwapStack(11),
+			valid:       true,
 		},
 		SWAP11: {
-			execute:       makeSwap(11),
-			gasCost:       gasSwap,
-			validateStack: makeSwapStackFunc(12),
-			valid:         true,
+			execute:     makeSwap(11),
+			constantGas: GasFastestStep,
+			minStack:    minSwapStack(12),
+			maxStack:    maxSwapStack(12),
+			valid:       true,
 		},
 		SWAP12: {
-			execute:       makeSwap(12),
-			gasCost:       gasSwap,
-			validateStack: makeSwapStackFunc(13),
-			valid:         true,
+			execute:     makeSwap(12),
+			constantGas: GasFastestStep,
+			minStack:    minSwapStack(13),
+			maxStack:    maxSwapStack(13),
+			valid:       true,
 		},
 		SWAP13: {
-			execute:       makeSwap(13),
-			gasCost:       gasSwap,
-			validateStack: makeSwapStackFunc(14),
-			valid:         true,
+			execute:     makeSwap(13),
+			constantGas: GasFastestStep,
+			minStack:    minSwapStack(14),
+			maxStack:    maxSwapStack(14),
+			valid:       true,
 		},
 		SWAP14: {
-			execute:       makeSwap(14),
-			gasCost:       gasSwap,
-			validateStack: makeSwapStackFunc(15),
-			valid:         true,
+			execute:     makeSwap(14),
+			constantGas: GasFastestStep,
+			minStack:    minSwapStack(15),
+			maxStack:    maxSwapStack(15),
+			valid:       true,
 		},
 		SWAP15: {
-			execute:       makeSwap(15),
-			gasCost:       gasSwap,
-			validateStack: makeSwapStackFunc(16),
-			valid:         true,
+			execute:     makeSwap(15),
+			constantGas: GasFastestStep,
+			minStack:    minSwapStack(16),
+			maxStack:    maxSwapStack(16),
+			valid:       true,
 		},
 		SWAP16: {
-			execute:       makeSwap(16),
-			gasCost:       gasSwap,
-			validateStack: makeSwapStackFunc(17),
-			valid:         true,
+			execute:     makeSwap(16),
+			constantGas: GasFastestStep,
+			minStack:    minSwapStack(17),
+			maxStack:    maxSwapStack(17),
+			valid:       true,
 		},
 		LOG0: {
-			execute:       makeLog(0),
-			gasCost:       makeGasLog(0),
-			validateStack: makeStackFunc(2, 0),
-			memorySize:    memoryLog,
-			valid:         true,
-			writes:        true,
+			execute:    makeLog(0),
+			dynamicGas: makeGasLog(0),
+			minStack:   minStack(2, 0),
+			maxStack:   maxStack(2, 0),
+			memorySize: memoryLog,
+			valid:      true,
+			writes:     true,
 		},
 		LOG1: {
-			execute:       makeLog(1),
-			gasCost:       makeGasLog(1),
-			validateStack: makeStackFunc(3, 0),
-			memorySize:    memoryLog,
-			valid:         true,
-			writes:        true,
+			execute:    makeLog(1),
+			dynamicGas: makeGasLog(1),
+			minStack:   minStack(3, 0),
+			maxStack:   maxStack(3, 0),
+			memorySize: memoryLog,
+			valid:      true,
+			writes:     true,
 		},
 		LOG2: {
-			execute:       makeLog(2),
-			gasCost:       makeGasLog(2),
-			validateStack: makeStackFunc(4, 0),
-			memorySize:    memoryLog,
-			valid:         true,
-			writes:        true,
+			execute:    makeLog(2),
+			dynamicGas: makeGasLog(2),
+			minStack:   minStack(4, 0),
+			maxStack:   maxStack(4, 0),
+			memorySize: memoryLog,
+			valid:      true,
+			writes:     true,
 		},
 		LOG3: {
-			execute:       makeLog(3),
-			gasCost:       makeGasLog(3),
-			validateStack: makeStackFunc(5, 0),
-			memorySize:    memoryLog,
-			valid:         true,
-			writes:        true,
+			execute:    makeLog(3),
+			dynamicGas: makeGasLog(3),
+			minStack:   minStack(5, 0),
+			maxStack:   maxStack(5, 0),
+			memorySize: memoryLog,
+			valid:      true,
+			writes:     true,
 		},
 		LOG4: {
-			execute:       makeLog(4),
-			gasCost:       makeGasLog(4),
-			validateStack: makeStackFunc(6, 0),
-			memorySize:    memoryLog,
-			valid:         true,
-			writes:        true,
+			execute:    makeLog(4),
+			dynamicGas: makeGasLog(4),
+			minStack:   minStack(6, 0),
+			maxStack:   maxStack(6, 0),
+			memorySize: memoryLog,
+			valid:      true,
+			writes:     true,
 		},
 		CREATE: {
-			execute:       opCreate,
-			gasCost:       gasCreate,
-			validateStack: makeStackFunc(3, 1),
-			memorySize:    memoryCreate,
-			valid:         true,
-			writes:        true,
-			returns:       true,
+			execute:    opCreate,
+			dynamicGas: gasCreate,
+			minStack:   minStack(3, 1),
+			maxStack:   maxStack(3, 1),
+			memorySize: memoryCreate,
+			valid:      true,
+			writes:     true,
+			returns:    true,
 		},
 		CALL: {
-			execute:       opCall,
-			gasCost:       gasCall,
-			validateStack: makeStackFunc(7, 1),
-			memorySize:    memoryCall,
-			valid:         true,
-			returns:       true,
+			execute:    opCall,
+			dynamicGas: gasCall,
+			minStack:   minStack(7, 1),
+			maxStack:   maxStack(7, 1),
+			memorySize: memoryCall,
+			valid:      true,
+			returns:    true,
 		},
 		CALLCODE: {
-			execute:       opCallCode,
-			gasCost:       gasCallCode,
-			validateStack: makeStackFunc(7, 1),
-			memorySize:    memoryCall,
-			valid:         true,
-			returns:       true,
+			execute:    opCallCode,
+			dynamicGas: gasCallCode,
+			minStack:   minStack(7, 1),
+			maxStack:   maxStack(7, 1),
+			memorySize: memoryCall,
+			valid:      true,
+			returns:    true,
 		},
 		RETURN: {
-			execute:       opReturn,
-			gasCost:       gasReturn,
-			validateStack: makeStackFunc(2, 0),
-			memorySize:    memoryReturn,
-			halts:         true,
-			valid:         true,
+			execute:    opReturn,
+			dynamicGas: gasReturn,
+			minStack:   minStack(2, 0),
+			maxStack:   maxStack(2, 0),
+			memorySize: memoryReturn,
+			halts:      true,
+			valid:      true,
 		},
 		SELFDESTRUCT: {
-			execute:       opSuicide,
-			gasCost:       gasSuicide,
-			validateStack: makeStackFunc(1, 0),
-			halts:         true,
-			valid:         true,
-			writes:        true,
+			execute:    opSuicide,
+			dynamicGas: gasSuicide,
+			minStack:   minStack(1, 0),
+			maxStack:   maxStack(1, 0),
+			halts:      true,
+			valid:      true,
+			writes:     true,
 		},
 	}
 }

+ 65 - 49
core/vm/memory_table.go

@@ -16,82 +16,98 @@
 
 package vm
 
-import (
-	"math/big"
-
-	"github.com/ethereum/go-ethereum/common/math"
-)
-
-func memorySha3(stack *Stack) *big.Int {
-	return calcMemSize(stack.Back(0), stack.Back(1))
+func memorySha3(stack *Stack) (uint64, bool) {
+	return calcMemSize64(stack.Back(0), stack.Back(1))
 }
 
-func memoryCallDataCopy(stack *Stack) *big.Int {
-	return calcMemSize(stack.Back(0), stack.Back(2))
+func memoryCallDataCopy(stack *Stack) (uint64, bool) {
+	return calcMemSize64(stack.Back(0), stack.Back(2))
 }
 
-func memoryReturnDataCopy(stack *Stack) *big.Int {
-	return calcMemSize(stack.Back(0), stack.Back(2))
+func memoryReturnDataCopy(stack *Stack) (uint64, bool) {
+	return calcMemSize64(stack.Back(0), stack.Back(2))
 }
 
-func memoryCodeCopy(stack *Stack) *big.Int {
-	return calcMemSize(stack.Back(0), stack.Back(2))
+func memoryCodeCopy(stack *Stack) (uint64, bool) {
+	return calcMemSize64(stack.Back(0), stack.Back(2))
 }
 
-func memoryExtCodeCopy(stack *Stack) *big.Int {
-	return calcMemSize(stack.Back(1), stack.Back(3))
+func memoryExtCodeCopy(stack *Stack) (uint64, bool) {
+	return calcMemSize64(stack.Back(1), stack.Back(3))
 }
 
-func memoryMLoad(stack *Stack) *big.Int {
-	return calcMemSize(stack.Back(0), big.NewInt(32))
+func memoryMLoad(stack *Stack) (uint64, bool) {
+	return calcMemSize64WithUint(stack.Back(0), 32)
 }
 
-func memoryMStore8(stack *Stack) *big.Int {
-	return calcMemSize(stack.Back(0), big.NewInt(1))
+func memoryMStore8(stack *Stack) (uint64, bool) {
+	return calcMemSize64WithUint(stack.Back(0), 1)
 }
 
-func memoryMStore(stack *Stack) *big.Int {
-	return calcMemSize(stack.Back(0), big.NewInt(32))
+func memoryMStore(stack *Stack) (uint64, bool) {
+	return calcMemSize64WithUint(stack.Back(0), 32)
 }
 
-func memoryCreate(stack *Stack) *big.Int {
-	return calcMemSize(stack.Back(1), stack.Back(2))
+func memoryCreate(stack *Stack) (uint64, bool) {
+	return calcMemSize64(stack.Back(1), stack.Back(2))
 }
 
-func memoryCreate2(stack *Stack) *big.Int {
-	return calcMemSize(stack.Back(1), stack.Back(2))
+func memoryCreate2(stack *Stack) (uint64, bool) {
+	return calcMemSize64(stack.Back(1), stack.Back(2))
 }
 
-func memoryCall(stack *Stack) *big.Int {
-	x := calcMemSize(stack.Back(5), stack.Back(6))
-	y := calcMemSize(stack.Back(3), stack.Back(4))
-
-	return math.BigMax(x, y)
+func memoryCall(stack *Stack) (uint64, bool) {
+	x, overflow := calcMemSize64(stack.Back(5), stack.Back(6))
+	if overflow {
+		return 0, true
+	}
+	y, overflow := calcMemSize64(stack.Back(3), stack.Back(4))
+	if overflow {
+		return 0, true
+	}
+	if x > y {
+		return x, false
+	}
+	return y, false
 }
-
-func memoryDelegateCall(stack *Stack) *big.Int {
-	x := calcMemSize(stack.Back(4), stack.Back(5))
-	y := calcMemSize(stack.Back(2), stack.Back(3))
-
-	return math.BigMax(x, y)
+func memoryDelegateCall(stack *Stack) (uint64, bool) {
+	x, overflow := calcMemSize64(stack.Back(4), stack.Back(5))
+	if overflow {
+		return 0, true
+	}
+	y, overflow := calcMemSize64(stack.Back(2), stack.Back(3))
+	if overflow {
+		return 0, true
+	}
+	if x > y {
+		return x, false
+	}
+	return y, false
 }
 
-func memoryStaticCall(stack *Stack) *big.Int {
-	x := calcMemSize(stack.Back(4), stack.Back(5))
-	y := calcMemSize(stack.Back(2), stack.Back(3))
-
-	return math.BigMax(x, y)
+func memoryStaticCall(stack *Stack) (uint64, bool) {
+	x, overflow := calcMemSize64(stack.Back(4), stack.Back(5))
+	if overflow {
+		return 0, true
+	}
+	y, overflow := calcMemSize64(stack.Back(2), stack.Back(3))
+	if overflow {
+		return 0, true
+	}
+	if x > y {
+		return x, false
+	}
+	return y, false
 }
 
-func memoryReturn(stack *Stack) *big.Int {
-	return calcMemSize(stack.Back(0), stack.Back(1))
+func memoryReturn(stack *Stack) (uint64, bool) {
+	return calcMemSize64(stack.Back(0), stack.Back(1))
 }
 
-func memoryRevert(stack *Stack) *big.Int {
-	return calcMemSize(stack.Back(0), stack.Back(1))
+func memoryRevert(stack *Stack) (uint64, bool) {
+	return calcMemSize64(stack.Back(0), stack.Back(1))
 }
 
-func memoryLog(stack *Stack) *big.Int {
-	mSize, mStart := stack.Back(1), stack.Back(0)
-	return calcMemSize(mStart, mSize)
+func memoryLog(stack *Stack) (uint64, bool) {
+	return calcMemSize64(stack.Back(0), stack.Back(1))
 }

+ 15 - 17
core/vm/stack_table.go

@@ -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
-		}
-
-		if stack.len()+push-pop > int(params.StackLimit) {
-			return fmt.Errorf("stack limit reached %d (%d)", stack.len(), params.StackLimit)
-		}
-		return nil
-	}
+func minSwapStack(n int) int {
+	return minStack(n, n)
+}
+func maxSwapStack(n int) int {
+	return maxStack(n, n)
 }
 
-func makeDupStackFunc(n int) stackValidationFunc {
-	return makeStackFunc(n, n+1)
+func minDupStack(n int) int {
+	return minStack(n, n+1)
+}
+func maxDupStack(n int) int {
+	return maxStack(n, n+1)
 }
 
-func makeSwapStackFunc(n int) stackValidationFunc {
-	return makeStackFunc(n, n)
+func maxStack(pop, push int) int {
+	return int(params.StackLimit) + pop - push
+}
+func minStack(pops, push int) int {
+	return pops
 }

+ 1 - 1
eth/tracers/testdata/call_tracer_inner_create_oog_outer_throw.json

@@ -65,7 +65,7 @@
         "value": "0x0"
       }
     ],
-    "error": "invalid jump destination (PUSH1) 0",
+    "error": "evm: invalid jump destination",
     "from": "0xe4a13bc304682a903e9472f469c33801dd18d9e8",
     "gas": "0x435c8",
     "gasUsed": "0x435c8",

+ 1 - 1
eth/tracers/testdata/call_tracer_throw.json

@@ -50,7 +50,7 @@
   },
   "input": "0xf88b8206668504a817c8008303d09094c212e03b9e060e36facad5fd8f4435412ca22e6b80a451a34eb8000000000000000000000000000000000000000000000027fad02094277c000029a0692a3b4e7b2842f8dd7832e712c21e09f451f416c8976d5b8d02e8c0c2b4bea9a07645e90fc421b63dd755767fd93d3c03b4ec0c4d8fafa059558d08cf11d59750",
   "result": {
-    "error": "invalid jump destination (PUSH1) 2",
+    "error": "evm: invalid jump destination",
     "from": "0x70c9217d814985faef62b124420f8dfbddd96433",
     "gas": "0x37b38",
     "gasUsed": "0x37b38",