Commit 7504dbd6 authored by Martin Holst Swende's avatar Martin Holst Swende Committed by Péter Szilágyi

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()
parent da5de012
...@@ -202,9 +202,6 @@ func IsHexAddress(s string) bool { ...@@ -202,9 +202,6 @@ func IsHexAddress(s string) bool {
// Bytes gets the string representation of the underlying address. // Bytes gets the string representation of the underlying address.
func (a Address) Bytes() []byte { return a[:] } 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. // Hash converts an address to a hash by left-padding it with zeros.
func (a Address) Hash() Hash { return BytesToHash(a[:]) } func (a Address) Hash() Hash { return BytesToHash(a[:]) }
......
...@@ -114,8 +114,8 @@ func TestAddressUnmarshalJSON(t *testing.T) { ...@@ -114,8 +114,8 @@ func TestAddressUnmarshalJSON(t *testing.T) {
if test.ShouldErr { if test.ShouldErr {
t.Errorf("test #%d: expected error, got none", i) t.Errorf("test #%d: expected error, got none", i)
} }
if v.Big().Cmp(test.Output) != 0 { if got := new(big.Int).SetBytes(v.Bytes()); got.Cmp(test.Output) != 0 {
t.Errorf("test #%d: address mismatch: have %v, want %v", i, v.Big(), test.Output) t.Errorf("test #%d: address mismatch: have %v, want %v", i, got, test.Output)
} }
} }
} }
......
...@@ -52,7 +52,8 @@ func makelist(g *core.Genesis) allocList { ...@@ -52,7 +52,8 @@ func makelist(g *core.Genesis) allocList {
if len(account.Storage) > 0 || len(account.Code) > 0 || account.Nonce != 0 { if len(account.Storage) > 0 || len(account.Code) > 0 || account.Nonce != 0 {
panic(fmt.Sprintf("can't encode account %x", addr)) 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) sort.Sort(a)
return a return a
......
...@@ -23,13 +23,31 @@ import ( ...@@ -23,13 +23,31 @@ import (
"github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/common/math"
) )
// calculates the memory size required for a step // calcMemSize64 calculates the required memory size, and returns
func calcMemSize(off, l *big.Int) *big.Int { // the size and whether the result overflowed uint64
if l.Sign() == 0 { func calcMemSize64(off, l *big.Int) (uint64, bool) {
return common.Big0 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 // 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 { ...@@ -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 // bigUint64 returns the integer casted to a uint64 and returns whether it
// overflowed in the process. // overflowed in the process.
func bigUint64(v *big.Int) (uint64, bool) { 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. // toWordSize returns the ceiled word size required for memory expansion.
......
...@@ -43,11 +43,11 @@ func callGas(gasTable params.GasTable, availableGas, base uint64, callCost *big. ...@@ -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 // 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 // is smaller than the requested amount. Therefor we return the new gas instead
// of returning an error. // of returning an error.
if callCost.BitLen() > 64 || gas < callCost.Uint64() { if !callCost.IsUint64() || gas < callCost.Uint64() {
return gas, nil return gas, nil
} }
} }
if callCost.BitLen() > 64 { if !callCost.IsUint64() {
return 0, errGasUintOverflow return 0, errGasUintOverflow
} }
......
...@@ -57,12 +57,6 @@ func memoryGasCost(mem *Memory, newMemSize uint64) (uint64, error) { ...@@ -57,12 +57,6 @@ func memoryGasCost(mem *Memory, newMemSize uint64) (uint64, error) {
return 0, nil 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) { func gasCallDataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
gas, err := memoryGasCost(mem, memorySize) gas, err := memoryGasCost(mem, memorySize)
if err != nil { if err != nil {
...@@ -521,15 +515,3 @@ func gasStaticCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stac ...@@ -521,15 +515,3 @@ func gasStaticCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stac
} }
return gas, nil 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
}
...@@ -18,7 +18,6 @@ package vm ...@@ -18,7 +18,6 @@ package vm
import ( import (
"errors" "errors"
"fmt"
"math/big" "math/big"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
...@@ -35,6 +34,7 @@ var ( ...@@ -35,6 +34,7 @@ var (
errReturnDataOutOfBounds = errors.New("evm: return data out of bounds") errReturnDataOutOfBounds = errors.New("evm: return data out of bounds")
errExecutionReverted = errors.New("evm: execution reverted") errExecutionReverted = errors.New("evm: execution reverted")
errMaxCodeSizeExceeded = errors.New("evm: max code size exceeded") 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) { 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 ...@@ -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) { 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 return nil, nil
} }
...@@ -416,12 +416,12 @@ func opBalance(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memo ...@@ -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) { 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 return nil, nil
} }
func opCaller(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { 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 return nil, nil
} }
...@@ -467,7 +467,7 @@ func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contrac ...@@ -467,7 +467,7 @@ func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contrac
) )
defer interpreter.intPool.put(memOffset, dataOffset, length, end) 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 return nil, errReturnDataOutOfBounds
} }
memory.Set(memOffset.Uint64(), length.Uint64(), interpreter.returnData[dataOffset.Uint64():end.Uint64()]) 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 ...@@ -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) { 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 return nil, nil
} }
...@@ -645,8 +645,7 @@ func opSstore(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor ...@@ -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) { func opJump(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
pos := stack.pop() pos := stack.pop()
if !contract.validJumpdest(pos) { if !contract.validJumpdest(pos) {
nop := contract.GetOp(pos.Uint64()) return nil, errInvalidJump
return nil, fmt.Errorf("invalid jump destination (%v) %v", nop, pos)
} }
*pc = pos.Uint64() *pc = pos.Uint64()
...@@ -658,8 +657,7 @@ func opJumpi(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory ...@@ -658,8 +657,7 @@ func opJumpi(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory
pos, cond := stack.pop(), stack.pop() pos, cond := stack.pop(), stack.pop()
if cond.Sign() != 0 { if cond.Sign() != 0 {
if !contract.validJumpdest(pos) { if !contract.validJumpdest(pos) {
nop := contract.GetOp(pos.Uint64()) return nil, errInvalidJump
return nil, fmt.Errorf("invalid jump destination (%v) %v", nop, pos)
} }
*pc = pos.Uint64() *pc = pos.Uint64()
} else { } else {
...@@ -711,7 +709,7 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor ...@@ -711,7 +709,7 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor
} else if suberr != nil && suberr != ErrCodeStoreOutOfGas { } else if suberr != nil && suberr != ErrCodeStoreOutOfGas {
stack.push(interpreter.intPool.getZero()) stack.push(interpreter.intPool.getZero())
} else { } else {
stack.push(addr.Big()) stack.push(interpreter.intPool.get().SetBytes(addr.Bytes()))
} }
contract.Gas += returnGas contract.Gas += returnGas
interpreter.intPool.put(value, offset, size) interpreter.intPool.put(value, offset, size)
...@@ -739,7 +737,7 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memo ...@@ -739,7 +737,7 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memo
if suberr != nil { if suberr != nil {
stack.push(interpreter.intPool.getZero()) stack.push(interpreter.intPool.getZero())
} else { } else {
stack.push(addr.Big()) stack.push(interpreter.intPool.get().SetBytes(addr.Bytes()))
} }
contract.Gas += returnGas contract.Gas += returnGas
interpreter.intPool.put(endowment, offset, size, salt) interpreter.intPool.put(endowment, offset, size, salt)
...@@ -912,6 +910,21 @@ func makeLog(size int) executionFunc { ...@@ -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 // make push instruction function
func makePush(size uint64, pushByteSize int) executionFunc { func makePush(size uint64, pushByteSize int) executionFunc {
return func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { return func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
......
...@@ -118,22 +118,6 @@ func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter { ...@@ -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 // 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. // the return byte-slice and an error if one occurred.
// //
...@@ -217,19 +201,35 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( ...@@ -217,19 +201,35 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
if !operation.valid { if !operation.valid {
return nil, fmt.Errorf("invalid opcode 0x%x", int(op)) return nil, fmt.Errorf("invalid opcode 0x%x", int(op))
} }
if err = operation.validateStack(stack); err != nil { // Validate stack
return nil, err 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 the operation is valid, enforce and write restrictions
if err = in.enforceRestrictions(op, operation, stack); err != nil { if in.readOnly && in.evm.chainRules.IsByzantium {
return nil, err // 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 var memorySize uint64
// calculate the new memory size and expand the memory to fit // calculate the new memory size and expand the memory to fit
// the operation // the operation
// Memory check needs to be done prior to evaluating the dynamic gas portion,
// to detect calculation overflows
if operation.memorySize != nil { if operation.memorySize != nil {
memSize, overflow := bigUint64(operation.memorySize(stack)) memSize, overflow := operation.memorySize(stack)
if overflow { if overflow {
return nil, errGasUintOverflow return nil, errGasUintOverflow
} }
...@@ -239,12 +239,15 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( ...@@ -239,12 +239,15 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
return nil, errGasUintOverflow return nil, errGasUintOverflow
} }
} }
// Dynamic portion of gas
// consume the gas and return an error if not enough gas is available. // 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 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 operation.dynamicGas != nil {
cost, err = operation.dynamicGas(in.gasTable, in.evm, contract, stack, mem, memorySize)
if err != nil || !contract.UseGas(cost) { if err != nil || !contract.UseGas(cost) {
return nil, ErrOutOfGas return nil, ErrOutOfGas
} }
}
if memorySize > 0 { if memorySize > 0 {
mem.Resize(memorySize) mem.Resize(memorySize)
} }
......
...@@ -18,7 +18,6 @@ package vm ...@@ -18,7 +18,6 @@ package vm
import ( import (
"errors" "errors"
"math/big"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
) )
...@@ -26,8 +25,8 @@ import ( ...@@ -26,8 +25,8 @@ import (
type ( type (
executionFunc func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) 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 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 returns the required size, and whether the operation overflowed a uint64
memorySizeFunc func(*Stack) *big.Int memorySizeFunc func(*Stack) (size uint64, overflow bool)
) )
var errGasUintOverflow = errors.New("gas uint64 overflow") var errGasUintOverflow = errors.New("gas uint64 overflow")
...@@ -35,10 +34,14 @@ var errGasUintOverflow = errors.New("gas uint64 overflow") ...@@ -35,10 +34,14 @@ var errGasUintOverflow = errors.New("gas uint64 overflow")
type operation struct { type operation struct {
// execute is the operation function // execute is the operation function
execute executionFunc execute executionFunc
// gasCost is the gas function and returns the gas required for execution constantGas uint64
gasCost gasFunc dynamicGas gasFunc
// validateStack validates the stack (size) for the operation // minStack tells how many stack items are required
validateStack stackValidationFunc 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 returns the memory size required for the operation
memorySize memorySizeFunc memorySize memorySizeFunc
...@@ -64,32 +67,37 @@ func newConstantinopleInstructionSet() [256]operation { ...@@ -64,32 +67,37 @@ func newConstantinopleInstructionSet() [256]operation {
instructionSet := newByzantiumInstructionSet() instructionSet := newByzantiumInstructionSet()
instructionSet[SHL] = operation{ instructionSet[SHL] = operation{
execute: opSHL, execute: opSHL,
gasCost: constGasFunc(GasFastestStep), constantGas: GasFastestStep,
validateStack: makeStackFunc(2, 1), minStack: minStack(2, 1),
maxStack: maxStack(2, 1),
valid: true, valid: true,
} }
instructionSet[SHR] = operation{ instructionSet[SHR] = operation{
execute: opSHR, execute: opSHR,
gasCost: constGasFunc(GasFastestStep), constantGas: GasFastestStep,
validateStack: makeStackFunc(2, 1), minStack: minStack(2, 1),
maxStack: maxStack(2, 1),
valid: true, valid: true,
} }
instructionSet[SAR] = operation{ instructionSet[SAR] = operation{
execute: opSAR, execute: opSAR,
gasCost: constGasFunc(GasFastestStep), constantGas: GasFastestStep,
validateStack: makeStackFunc(2, 1), minStack: minStack(2, 1),
maxStack: maxStack(2, 1),
valid: true, valid: true,
} }
instructionSet[EXTCODEHASH] = operation{ instructionSet[EXTCODEHASH] = operation{
execute: opExtCodeHash, execute: opExtCodeHash,
gasCost: gasExtCodeHash, dynamicGas: gasExtCodeHash,
validateStack: makeStackFunc(1, 1), minStack: minStack(1, 1),
maxStack: maxStack(1, 1),
valid: true, valid: true,
} }
instructionSet[CREATE2] = operation{ instructionSet[CREATE2] = operation{
execute: opCreate2, execute: opCreate2,
gasCost: gasCreate2, dynamicGas: gasCreate2,
validateStack: makeStackFunc(4, 1), minStack: minStack(4, 1),
maxStack: maxStack(4, 1),
memorySize: memoryCreate2, memorySize: memoryCreate2,
valid: true, valid: true,
writes: true, writes: true,
...@@ -105,29 +113,33 @@ func newByzantiumInstructionSet() [256]operation { ...@@ -105,29 +113,33 @@ func newByzantiumInstructionSet() [256]operation {
instructionSet := newHomesteadInstructionSet() instructionSet := newHomesteadInstructionSet()
instructionSet[STATICCALL] = operation{ instructionSet[STATICCALL] = operation{
execute: opStaticCall, execute: opStaticCall,
gasCost: gasStaticCall, dynamicGas: gasStaticCall,
validateStack: makeStackFunc(6, 1), minStack: minStack(6, 1),
maxStack: maxStack(6, 1),
memorySize: memoryStaticCall, memorySize: memoryStaticCall,
valid: true, valid: true,
returns: true, returns: true,
} }
instructionSet[RETURNDATASIZE] = operation{ instructionSet[RETURNDATASIZE] = operation{
execute: opReturnDataSize, execute: opReturnDataSize,
gasCost: constGasFunc(GasQuickStep), constantGas: GasQuickStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
} }
instructionSet[RETURNDATACOPY] = operation{ instructionSet[RETURNDATACOPY] = operation{
execute: opReturnDataCopy, execute: opReturnDataCopy,
gasCost: gasReturnDataCopy, dynamicGas: gasReturnDataCopy,
validateStack: makeStackFunc(3, 0), minStack: minStack(3, 0),
maxStack: maxStack(3, 0),
memorySize: memoryReturnDataCopy, memorySize: memoryReturnDataCopy,
valid: true, valid: true,
} }
instructionSet[REVERT] = operation{ instructionSet[REVERT] = operation{
execute: opRevert, execute: opRevert,
gasCost: gasRevert, dynamicGas: gasRevert,
validateStack: makeStackFunc(2, 0), minStack: minStack(2, 0),
maxStack: maxStack(2, 0),
memorySize: memoryRevert, memorySize: memoryRevert,
valid: true, valid: true,
reverts: true, reverts: true,
...@@ -142,8 +154,9 @@ func newHomesteadInstructionSet() [256]operation { ...@@ -142,8 +154,9 @@ func newHomesteadInstructionSet() [256]operation {
instructionSet := newFrontierInstructionSet() instructionSet := newFrontierInstructionSet()
instructionSet[DELEGATECALL] = operation{ instructionSet[DELEGATECALL] = operation{
execute: opDelegateCall, execute: opDelegateCall,
gasCost: gasDelegateCall, dynamicGas: gasDelegateCall,
validateStack: makeStackFunc(6, 1), minStack: minStack(6, 1),
maxStack: maxStack(6, 1),
memorySize: memoryDelegateCall, memorySize: memoryDelegateCall,
valid: true, valid: true,
returns: true, returns: true,
...@@ -157,774 +170,899 @@ func newFrontierInstructionSet() [256]operation { ...@@ -157,774 +170,899 @@ func newFrontierInstructionSet() [256]operation {
return [256]operation{ return [256]operation{
STOP: { STOP: {
execute: opStop, execute: opStop,
gasCost: constGasFunc(0), constantGas: 0,
validateStack: makeStackFunc(0, 0), minStack: minStack(0, 0),
maxStack: maxStack(0, 0),
halts: true, halts: true,
valid: true, valid: true,
}, },
ADD: { ADD: {
execute: opAdd, execute: opAdd,
gasCost: constGasFunc(GasFastestStep), constantGas: GasFastestStep,
validateStack: makeStackFunc(2, 1), minStack: minStack(2, 1),
maxStack: maxStack(2, 1),
valid: true, valid: true,
}, },
MUL: { MUL: {
execute: opMul, execute: opMul,
gasCost: constGasFunc(GasFastStep), constantGas: GasFastStep,
validateStack: makeStackFunc(2, 1), minStack: minStack(2, 1),
maxStack: maxStack(2, 1),
valid: true, valid: true,
}, },
SUB: { SUB: {
execute: opSub, execute: opSub,
gasCost: constGasFunc(GasFastestStep), constantGas: GasFastestStep,
validateStack: makeStackFunc(2, 1), minStack: minStack(2, 1),
maxStack: maxStack(2, 1),
valid: true, valid: true,
}, },
DIV: { DIV: {
execute: opDiv, execute: opDiv,
gasCost: constGasFunc(GasFastStep), constantGas: GasFastStep,
validateStack: makeStackFunc(2, 1), minStack: minStack(2, 1),
maxStack: maxStack(2, 1),
valid: true, valid: true,
}, },
SDIV: { SDIV: {
execute: opSdiv, execute: opSdiv,
gasCost: constGasFunc(GasFastStep), constantGas: GasFastStep,
validateStack: makeStackFunc(2, 1), minStack: minStack(2, 1),
maxStack: maxStack(2, 1),
valid: true, valid: true,
}, },
MOD: { MOD: {
execute: opMod, execute: opMod,
gasCost: constGasFunc(GasFastStep), constantGas: GasFastStep,
validateStack: makeStackFunc(2, 1), minStack: minStack(2, 1),
maxStack: maxStack(2, 1),
valid: true, valid: true,
}, },
SMOD: { SMOD: {
execute: opSmod, execute: opSmod,
gasCost: constGasFunc(GasFastStep), constantGas: GasFastStep,
validateStack: makeStackFunc(2, 1), minStack: minStack(2, 1),
maxStack: maxStack(2, 1),
valid: true, valid: true,
}, },
ADDMOD: { ADDMOD: {
execute: opAddmod, execute: opAddmod,
gasCost: constGasFunc(GasMidStep), constantGas: GasMidStep,
validateStack: makeStackFunc(3, 1), minStack: minStack(3, 1),
maxStack: maxStack(3, 1),
valid: true, valid: true,
}, },
MULMOD: { MULMOD: {
execute: opMulmod, execute: opMulmod,
gasCost: constGasFunc(GasMidStep), constantGas: GasMidStep,
validateStack: makeStackFunc(3, 1), minStack: minStack(3, 1),
maxStack: maxStack(3, 1),
valid: true, valid: true,
}, },
EXP: { EXP: {
execute: opExp, execute: opExp,
gasCost: gasExp, dynamicGas: gasExp,
validateStack: makeStackFunc(2, 1), minStack: minStack(2, 1),
maxStack: maxStack(2, 1),
valid: true, valid: true,
}, },
SIGNEXTEND: { SIGNEXTEND: {
execute: opSignExtend, execute: opSignExtend,
gasCost: constGasFunc(GasFastStep), constantGas: GasFastStep,
validateStack: makeStackFunc(2, 1), minStack: minStack(2, 1),
maxStack: maxStack(2, 1),
valid: true, valid: true,
}, },
LT: { LT: {
execute: opLt, execute: opLt,
gasCost: constGasFunc(GasFastestStep), constantGas: GasFastestStep,
validateStack: makeStackFunc(2, 1), minStack: minStack(2, 1),
maxStack: maxStack(2, 1),
valid: true, valid: true,
}, },
GT: { GT: {
execute: opGt, execute: opGt,
gasCost: constGasFunc(GasFastestStep), constantGas: GasFastestStep,
validateStack: makeStackFunc(2, 1), minStack: minStack(2, 1),
maxStack: maxStack(2, 1),
valid: true, valid: true,
}, },
SLT: { SLT: {
execute: opSlt, execute: opSlt,
gasCost: constGasFunc(GasFastestStep), constantGas: GasFastestStep,
validateStack: makeStackFunc(2, 1), minStack: minStack(2, 1),
maxStack: maxStack(2, 1),
valid: true, valid: true,
}, },
SGT: { SGT: {
execute: opSgt, execute: opSgt,
gasCost: constGasFunc(GasFastestStep), constantGas: GasFastestStep,
validateStack: makeStackFunc(2, 1), minStack: minStack(2, 1),
maxStack: maxStack(2, 1),
valid: true, valid: true,
}, },
EQ: { EQ: {
execute: opEq, execute: opEq,
gasCost: constGasFunc(GasFastestStep), constantGas: GasFastestStep,
validateStack: makeStackFunc(2, 1), minStack: minStack(2, 1),
maxStack: maxStack(2, 1),
valid: true, valid: true,
}, },
ISZERO: { ISZERO: {
execute: opIszero, execute: opIszero,
gasCost: constGasFunc(GasFastestStep), constantGas: GasFastestStep,
validateStack: makeStackFunc(1, 1), minStack: minStack(1, 1),
maxStack: maxStack(1, 1),
valid: true, valid: true,
}, },
AND: { AND: {
execute: opAnd, execute: opAnd,
gasCost: constGasFunc(GasFastestStep), constantGas: GasFastestStep,
validateStack: makeStackFunc(2, 1), minStack: minStack(2, 1),
maxStack: maxStack(2, 1),
valid: true, valid: true,
}, },
XOR: { XOR: {
execute: opXor, execute: opXor,
gasCost: constGasFunc(GasFastestStep), constantGas: GasFastestStep,
validateStack: makeStackFunc(2, 1), minStack: minStack(2, 1),
maxStack: maxStack(2, 1),
valid: true, valid: true,
}, },
OR: { OR: {
execute: opOr, execute: opOr,
gasCost: constGasFunc(GasFastestStep), constantGas: GasFastestStep,
validateStack: makeStackFunc(2, 1), minStack: minStack(2, 1),
maxStack: maxStack(2, 1),
valid: true, valid: true,
}, },
NOT: { NOT: {
execute: opNot, execute: opNot,
gasCost: constGasFunc(GasFastestStep), constantGas: GasFastestStep,
validateStack: makeStackFunc(1, 1), minStack: minStack(1, 1),
maxStack: maxStack(1, 1),
valid: true, valid: true,
}, },
BYTE: { BYTE: {
execute: opByte, execute: opByte,
gasCost: constGasFunc(GasFastestStep), constantGas: GasFastestStep,
validateStack: makeStackFunc(2, 1), minStack: minStack(2, 1),
maxStack: maxStack(2, 1),
valid: true, valid: true,
}, },
SHA3: { SHA3: {
execute: opSha3, execute: opSha3,
gasCost: gasSha3, dynamicGas: gasSha3,
validateStack: makeStackFunc(2, 1), minStack: minStack(2, 1),
maxStack: maxStack(2, 1),
memorySize: memorySha3, memorySize: memorySha3,
valid: true, valid: true,
}, },
ADDRESS: { ADDRESS: {
execute: opAddress, execute: opAddress,
gasCost: constGasFunc(GasQuickStep), constantGas: GasQuickStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
BALANCE: { BALANCE: {
execute: opBalance, execute: opBalance,
gasCost: gasBalance, dynamicGas: gasBalance,
validateStack: makeStackFunc(1, 1), minStack: minStack(1, 1),
maxStack: maxStack(1, 1),
valid: true, valid: true,
}, },
ORIGIN: { ORIGIN: {
execute: opOrigin, execute: opOrigin,
gasCost: constGasFunc(GasQuickStep), constantGas: GasQuickStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
CALLER: { CALLER: {
execute: opCaller, execute: opCaller,
gasCost: constGasFunc(GasQuickStep), constantGas: GasQuickStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
CALLVALUE: { CALLVALUE: {
execute: opCallValue, execute: opCallValue,
gasCost: constGasFunc(GasQuickStep), constantGas: GasQuickStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
CALLDATALOAD: { CALLDATALOAD: {
execute: opCallDataLoad, execute: opCallDataLoad,
gasCost: constGasFunc(GasFastestStep), constantGas: GasFastestStep,
validateStack: makeStackFunc(1, 1), minStack: minStack(1, 1),
maxStack: maxStack(1, 1),
valid: true, valid: true,
}, },
CALLDATASIZE: { CALLDATASIZE: {
execute: opCallDataSize, execute: opCallDataSize,
gasCost: constGasFunc(GasQuickStep), constantGas: GasQuickStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
CALLDATACOPY: { CALLDATACOPY: {
execute: opCallDataCopy, execute: opCallDataCopy,
gasCost: gasCallDataCopy, dynamicGas: gasCallDataCopy,
validateStack: makeStackFunc(3, 0), minStack: minStack(3, 0),
maxStack: maxStack(3, 0),
memorySize: memoryCallDataCopy, memorySize: memoryCallDataCopy,
valid: true, valid: true,
}, },
CODESIZE: { CODESIZE: {
execute: opCodeSize, execute: opCodeSize,
gasCost: constGasFunc(GasQuickStep), constantGas: GasQuickStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
CODECOPY: { CODECOPY: {
execute: opCodeCopy, execute: opCodeCopy,
gasCost: gasCodeCopy, dynamicGas: gasCodeCopy,
validateStack: makeStackFunc(3, 0), minStack: minStack(3, 0),
maxStack: maxStack(3, 0),
memorySize: memoryCodeCopy, memorySize: memoryCodeCopy,
valid: true, valid: true,
}, },
GASPRICE: { GASPRICE: {
execute: opGasprice, execute: opGasprice,
gasCost: constGasFunc(GasQuickStep), constantGas: GasQuickStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
EXTCODESIZE: { EXTCODESIZE: {
execute: opExtCodeSize, execute: opExtCodeSize,
gasCost: gasExtCodeSize, dynamicGas: gasExtCodeSize,
validateStack: makeStackFunc(1, 1), minStack: minStack(1, 1),
maxStack: maxStack(1, 1),
valid: true, valid: true,
}, },
EXTCODECOPY: { EXTCODECOPY: {
execute: opExtCodeCopy, execute: opExtCodeCopy,
gasCost: gasExtCodeCopy, dynamicGas: gasExtCodeCopy,
validateStack: makeStackFunc(4, 0), minStack: minStack(4, 0),
maxStack: maxStack(4, 0),
memorySize: memoryExtCodeCopy, memorySize: memoryExtCodeCopy,
valid: true, valid: true,
}, },
BLOCKHASH: { BLOCKHASH: {
execute: opBlockhash, execute: opBlockhash,
gasCost: constGasFunc(GasExtStep), constantGas: GasExtStep,
validateStack: makeStackFunc(1, 1), minStack: minStack(1, 1),
maxStack: maxStack(1, 1),
valid: true, valid: true,
}, },
COINBASE: { COINBASE: {
execute: opCoinbase, execute: opCoinbase,
gasCost: constGasFunc(GasQuickStep), constantGas: GasQuickStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
TIMESTAMP: { TIMESTAMP: {
execute: opTimestamp, execute: opTimestamp,
gasCost: constGasFunc(GasQuickStep), constantGas: GasQuickStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
NUMBER: { NUMBER: {
execute: opNumber, execute: opNumber,
gasCost: constGasFunc(GasQuickStep), constantGas: GasQuickStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
DIFFICULTY: { DIFFICULTY: {
execute: opDifficulty, execute: opDifficulty,
gasCost: constGasFunc(GasQuickStep), constantGas: GasQuickStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
GASLIMIT: { GASLIMIT: {
execute: opGasLimit, execute: opGasLimit,
gasCost: constGasFunc(GasQuickStep), constantGas: GasQuickStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
POP: { POP: {
execute: opPop, execute: opPop,
gasCost: constGasFunc(GasQuickStep), constantGas: GasQuickStep,
validateStack: makeStackFunc(1, 0), minStack: minStack(1, 0),
maxStack: maxStack(1, 0),
valid: true, valid: true,
}, },
MLOAD: { MLOAD: {
execute: opMload, execute: opMload,
gasCost: gasMLoad, dynamicGas: gasMLoad,
validateStack: makeStackFunc(1, 1), minStack: minStack(1, 1),
maxStack: maxStack(1, 1),
memorySize: memoryMLoad, memorySize: memoryMLoad,
valid: true, valid: true,
}, },
MSTORE: { MSTORE: {
execute: opMstore, execute: opMstore,
gasCost: gasMStore, dynamicGas: gasMStore,
validateStack: makeStackFunc(2, 0), minStack: minStack(2, 0),
maxStack: maxStack(2, 0),
memorySize: memoryMStore, memorySize: memoryMStore,
valid: true, valid: true,
}, },
MSTORE8: { MSTORE8: {
execute: opMstore8, execute: opMstore8,
gasCost: gasMStore8, dynamicGas: gasMStore8,
memorySize: memoryMStore8, memorySize: memoryMStore8,
validateStack: makeStackFunc(2, 0), minStack: minStack(2, 0),
maxStack: maxStack(2, 0),
valid: true, valid: true,
}, },
SLOAD: { SLOAD: {
execute: opSload, execute: opSload,
gasCost: gasSLoad, dynamicGas: gasSLoad,
validateStack: makeStackFunc(1, 1), minStack: minStack(1, 1),
maxStack: maxStack(1, 1),
valid: true, valid: true,
}, },
SSTORE: { SSTORE: {
execute: opSstore, execute: opSstore,
gasCost: gasSStore, dynamicGas: gasSStore,
validateStack: makeStackFunc(2, 0), minStack: minStack(2, 0),
maxStack: maxStack(2, 0),
valid: true, valid: true,
writes: true, writes: true,
}, },
JUMP: { JUMP: {
execute: opJump, execute: opJump,
gasCost: constGasFunc(GasMidStep), constantGas: GasMidStep,
validateStack: makeStackFunc(1, 0), minStack: minStack(1, 0),
maxStack: maxStack(1, 0),
jumps: true, jumps: true,
valid: true, valid: true,
}, },
JUMPI: { JUMPI: {
execute: opJumpi, execute: opJumpi,
gasCost: constGasFunc(GasSlowStep), constantGas: GasSlowStep,
validateStack: makeStackFunc(2, 0), minStack: minStack(2, 0),
maxStack: maxStack(2, 0),
jumps: true, jumps: true,
valid: true, valid: true,
}, },
PC: { PC: {
execute: opPc, execute: opPc,
gasCost: constGasFunc(GasQuickStep), constantGas: GasQuickStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
MSIZE: { MSIZE: {
execute: opMsize, execute: opMsize,
gasCost: constGasFunc(GasQuickStep), constantGas: GasQuickStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
GAS: { GAS: {
execute: opGas, execute: opGas,
gasCost: constGasFunc(GasQuickStep), constantGas: GasQuickStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
JUMPDEST: { JUMPDEST: {
execute: opJumpdest, execute: opJumpdest,
gasCost: constGasFunc(params.JumpdestGas), constantGas: params.JumpdestGas,
validateStack: makeStackFunc(0, 0), minStack: minStack(0, 0),
maxStack: maxStack(0, 0),
valid: true, valid: true,
}, },
PUSH1: { PUSH1: {
execute: makePush(1, 1), execute: opPush1,
gasCost: gasPush, constantGas: GasFastestStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
PUSH2: { PUSH2: {
execute: makePush(2, 2), execute: makePush(2, 2),
gasCost: gasPush, constantGas: GasFastestStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
PUSH3: { PUSH3: {
execute: makePush(3, 3), execute: makePush(3, 3),
gasCost: gasPush, constantGas: GasFastestStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
PUSH4: { PUSH4: {
execute: makePush(4, 4), execute: makePush(4, 4),
gasCost: gasPush, constantGas: GasFastestStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
PUSH5: { PUSH5: {
execute: makePush(5, 5), execute: makePush(5, 5),
gasCost: gasPush, constantGas: GasFastestStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
PUSH6: { PUSH6: {
execute: makePush(6, 6), execute: makePush(6, 6),
gasCost: gasPush, constantGas: GasFastestStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
PUSH7: { PUSH7: {
execute: makePush(7, 7), execute: makePush(7, 7),
gasCost: gasPush, constantGas: GasFastestStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
PUSH8: { PUSH8: {
execute: makePush(8, 8), execute: makePush(8, 8),
gasCost: gasPush, constantGas: GasFastestStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
PUSH9: { PUSH9: {
execute: makePush(9, 9), execute: makePush(9, 9),
gasCost: gasPush, constantGas: GasFastestStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
PUSH10: { PUSH10: {
execute: makePush(10, 10), execute: makePush(10, 10),
gasCost: gasPush, constantGas: GasFastestStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
PUSH11: { PUSH11: {
execute: makePush(11, 11), execute: makePush(11, 11),
gasCost: gasPush, constantGas: GasFastestStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
PUSH12: { PUSH12: {
execute: makePush(12, 12), execute: makePush(12, 12),
gasCost: gasPush, constantGas: GasFastestStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
PUSH13: { PUSH13: {
execute: makePush(13, 13), execute: makePush(13, 13),
gasCost: gasPush, constantGas: GasFastestStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
PUSH14: { PUSH14: {
execute: makePush(14, 14), execute: makePush(14, 14),
gasCost: gasPush, constantGas: GasFastestStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
PUSH15: { PUSH15: {
execute: makePush(15, 15), execute: makePush(15, 15),
gasCost: gasPush, constantGas: GasFastestStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
PUSH16: { PUSH16: {
execute: makePush(16, 16), execute: makePush(16, 16),
gasCost: gasPush, constantGas: GasFastestStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
PUSH17: { PUSH17: {
execute: makePush(17, 17), execute: makePush(17, 17),
gasCost: gasPush, constantGas: GasFastestStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
PUSH18: { PUSH18: {
execute: makePush(18, 18), execute: makePush(18, 18),
gasCost: gasPush, constantGas: GasFastestStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
PUSH19: { PUSH19: {
execute: makePush(19, 19), execute: makePush(19, 19),
gasCost: gasPush, constantGas: GasFastestStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
PUSH20: { PUSH20: {
execute: makePush(20, 20), execute: makePush(20, 20),
gasCost: gasPush, constantGas: GasFastestStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
PUSH21: { PUSH21: {
execute: makePush(21, 21), execute: makePush(21, 21),
gasCost: gasPush, constantGas: GasFastestStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
PUSH22: { PUSH22: {
execute: makePush(22, 22), execute: makePush(22, 22),
gasCost: gasPush, constantGas: GasFastestStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
PUSH23: { PUSH23: {
execute: makePush(23, 23), execute: makePush(23, 23),
gasCost: gasPush, constantGas: GasFastestStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
PUSH24: { PUSH24: {
execute: makePush(24, 24), execute: makePush(24, 24),
gasCost: gasPush, constantGas: GasFastestStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
PUSH25: { PUSH25: {
execute: makePush(25, 25), execute: makePush(25, 25),
gasCost: gasPush, constantGas: GasFastestStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
PUSH26: { PUSH26: {
execute: makePush(26, 26), execute: makePush(26, 26),
gasCost: gasPush, constantGas: GasFastestStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
PUSH27: { PUSH27: {
execute: makePush(27, 27), execute: makePush(27, 27),
gasCost: gasPush, constantGas: GasFastestStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
PUSH28: { PUSH28: {
execute: makePush(28, 28), execute: makePush(28, 28),
gasCost: gasPush, constantGas: GasFastestStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
PUSH29: { PUSH29: {
execute: makePush(29, 29), execute: makePush(29, 29),
gasCost: gasPush, constantGas: GasFastestStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
PUSH30: { PUSH30: {
execute: makePush(30, 30), execute: makePush(30, 30),
gasCost: gasPush, constantGas: GasFastestStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
PUSH31: { PUSH31: {
execute: makePush(31, 31), execute: makePush(31, 31),
gasCost: gasPush, constantGas: GasFastestStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
PUSH32: { PUSH32: {
execute: makePush(32, 32), execute: makePush(32, 32),
gasCost: gasPush, constantGas: GasFastestStep,
validateStack: makeStackFunc(0, 1), minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
valid: true, valid: true,
}, },
DUP1: { DUP1: {
execute: makeDup(1), execute: makeDup(1),
gasCost: gasDup, constantGas: GasFastestStep,
validateStack: makeDupStackFunc(1), minStack: minDupStack(1),
maxStack: maxDupStack(1),
valid: true, valid: true,
}, },
DUP2: { DUP2: {
execute: makeDup(2), execute: makeDup(2),
gasCost: gasDup, constantGas: GasFastestStep,
validateStack: makeDupStackFunc(2), minStack: minDupStack(2),
maxStack: maxDupStack(2),
valid: true, valid: true,
}, },
DUP3: { DUP3: {
execute: makeDup(3), execute: makeDup(3),
gasCost: gasDup, constantGas: GasFastestStep,
validateStack: makeDupStackFunc(3), minStack: minDupStack(3),
maxStack: maxDupStack(3),
valid: true, valid: true,
}, },
DUP4: { DUP4: {
execute: makeDup(4), execute: makeDup(4),
gasCost: gasDup, constantGas: GasFastestStep,
validateStack: makeDupStackFunc(4), minStack: minDupStack(4),
maxStack: maxDupStack(4),
valid: true, valid: true,
}, },
DUP5: { DUP5: {
execute: makeDup(5), execute: makeDup(5),
gasCost: gasDup, constantGas: GasFastestStep,
validateStack: makeDupStackFunc(5), minStack: minDupStack(5),
maxStack: maxDupStack(5),
valid: true, valid: true,
}, },
DUP6: { DUP6: {
execute: makeDup(6), execute: makeDup(6),
gasCost: gasDup, constantGas: GasFastestStep,
validateStack: makeDupStackFunc(6), minStack: minDupStack(6),
maxStack: maxDupStack(6),
valid: true, valid: true,
}, },
DUP7: { DUP7: {
execute: makeDup(7), execute: makeDup(7),
gasCost: gasDup, constantGas: GasFastestStep,
validateStack: makeDupStackFunc(7), minStack: minDupStack(7),
maxStack: maxDupStack(7),
valid: true, valid: true,
}, },
DUP8: { DUP8: {
execute: makeDup(8), execute: makeDup(8),
gasCost: gasDup, constantGas: GasFastestStep,
validateStack: makeDupStackFunc(8), minStack: minDupStack(8),
maxStack: maxDupStack(8),
valid: true, valid: true,
}, },
DUP9: { DUP9: {
execute: makeDup(9), execute: makeDup(9),
gasCost: gasDup, constantGas: GasFastestStep,
validateStack: makeDupStackFunc(9), minStack: minDupStack(9),
maxStack: maxDupStack(9),
valid: true, valid: true,
}, },
DUP10: { DUP10: {
execute: makeDup(10), execute: makeDup(10),
gasCost: gasDup, constantGas: GasFastestStep,
validateStack: makeDupStackFunc(10), minStack: minDupStack(10),
maxStack: maxDupStack(10),
valid: true, valid: true,
}, },
DUP11: { DUP11: {
execute: makeDup(11), execute: makeDup(11),
gasCost: gasDup, constantGas: GasFastestStep,
validateStack: makeDupStackFunc(11), minStack: minDupStack(11),
maxStack: maxDupStack(11),
valid: true, valid: true,
}, },
DUP12: { DUP12: {
execute: makeDup(12), execute: makeDup(12),
gasCost: gasDup, constantGas: GasFastestStep,
validateStack: makeDupStackFunc(12), minStack: minDupStack(12),
maxStack: maxDupStack(12),
valid: true, valid: true,
}, },
DUP13: { DUP13: {
execute: makeDup(13), execute: makeDup(13),
gasCost: gasDup, constantGas: GasFastestStep,
validateStack: makeDupStackFunc(13), minStack: minDupStack(13),
maxStack: maxDupStack(13),
valid: true, valid: true,
}, },
DUP14: { DUP14: {
execute: makeDup(14), execute: makeDup(14),
gasCost: gasDup, constantGas: GasFastestStep,
validateStack: makeDupStackFunc(14), minStack: minDupStack(14),
maxStack: maxDupStack(14),
valid: true, valid: true,
}, },
DUP15: { DUP15: {
execute: makeDup(15), execute: makeDup(15),
gasCost: gasDup, constantGas: GasFastestStep,
validateStack: makeDupStackFunc(15), minStack: minDupStack(15),
maxStack: maxDupStack(15),
valid: true, valid: true,
}, },
DUP16: { DUP16: {
execute: makeDup(16), execute: makeDup(16),
gasCost: gasDup, constantGas: GasFastestStep,
validateStack: makeDupStackFunc(16), minStack: minDupStack(16),
maxStack: maxDupStack(16),
valid: true, valid: true,
}, },
SWAP1: { SWAP1: {
execute: makeSwap(1), execute: makeSwap(1),
gasCost: gasSwap, constantGas: GasFastestStep,
validateStack: makeSwapStackFunc(2), minStack: minSwapStack(2),
maxStack: maxSwapStack(2),
valid: true, valid: true,
}, },
SWAP2: { SWAP2: {
execute: makeSwap(2), execute: makeSwap(2),
gasCost: gasSwap, constantGas: GasFastestStep,
validateStack: makeSwapStackFunc(3), minStack: minSwapStack(3),
maxStack: maxSwapStack(3),
valid: true, valid: true,
}, },
SWAP3: { SWAP3: {
execute: makeSwap(3), execute: makeSwap(3),
gasCost: gasSwap, constantGas: GasFastestStep,
validateStack: makeSwapStackFunc(4), minStack: minSwapStack(4),
maxStack: maxSwapStack(4),
valid: true, valid: true,
}, },
SWAP4: { SWAP4: {
execute: makeSwap(4), execute: makeSwap(4),
gasCost: gasSwap, constantGas: GasFastestStep,
validateStack: makeSwapStackFunc(5), minStack: minSwapStack(5),
maxStack: maxSwapStack(5),
valid: true, valid: true,
}, },
SWAP5: { SWAP5: {
execute: makeSwap(5), execute: makeSwap(5),
gasCost: gasSwap, constantGas: GasFastestStep,
validateStack: makeSwapStackFunc(6), minStack: minSwapStack(6),
maxStack: maxSwapStack(6),
valid: true, valid: true,
}, },
SWAP6: { SWAP6: {
execute: makeSwap(6), execute: makeSwap(6),
gasCost: gasSwap, constantGas: GasFastestStep,
validateStack: makeSwapStackFunc(7), minStack: minSwapStack(7),
maxStack: maxSwapStack(7),
valid: true, valid: true,
}, },
SWAP7: { SWAP7: {
execute: makeSwap(7), execute: makeSwap(7),
gasCost: gasSwap, constantGas: GasFastestStep,
validateStack: makeSwapStackFunc(8), minStack: minSwapStack(8),
maxStack: maxSwapStack(8),
valid: true, valid: true,
}, },
SWAP8: { SWAP8: {
execute: makeSwap(8), execute: makeSwap(8),
gasCost: gasSwap, constantGas: GasFastestStep,
validateStack: makeSwapStackFunc(9), minStack: minSwapStack(9),
maxStack: maxSwapStack(9),
valid: true, valid: true,
}, },
SWAP9: { SWAP9: {
execute: makeSwap(9), execute: makeSwap(9),
gasCost: gasSwap, constantGas: GasFastestStep,
validateStack: makeSwapStackFunc(10), minStack: minSwapStack(10),
maxStack: maxSwapStack(10),
valid: true, valid: true,
}, },
SWAP10: { SWAP10: {
execute: makeSwap(10), execute: makeSwap(10),
gasCost: gasSwap, constantGas: GasFastestStep,
validateStack: makeSwapStackFunc(11), minStack: minSwapStack(11),
maxStack: maxSwapStack(11),
valid: true, valid: true,
}, },
SWAP11: { SWAP11: {
execute: makeSwap(11), execute: makeSwap(11),
gasCost: gasSwap, constantGas: GasFastestStep,
validateStack: makeSwapStackFunc(12), minStack: minSwapStack(12),
maxStack: maxSwapStack(12),
valid: true, valid: true,
}, },
SWAP12: { SWAP12: {
execute: makeSwap(12), execute: makeSwap(12),
gasCost: gasSwap, constantGas: GasFastestStep,
validateStack: makeSwapStackFunc(13), minStack: minSwapStack(13),
maxStack: maxSwapStack(13),
valid: true, valid: true,
}, },
SWAP13: { SWAP13: {
execute: makeSwap(13), execute: makeSwap(13),
gasCost: gasSwap, constantGas: GasFastestStep,
validateStack: makeSwapStackFunc(14), minStack: minSwapStack(14),
maxStack: maxSwapStack(14),
valid: true, valid: true,
}, },
SWAP14: { SWAP14: {
execute: makeSwap(14), execute: makeSwap(14),
gasCost: gasSwap, constantGas: GasFastestStep,
validateStack: makeSwapStackFunc(15), minStack: minSwapStack(15),
maxStack: maxSwapStack(15),
valid: true, valid: true,
}, },
SWAP15: { SWAP15: {
execute: makeSwap(15), execute: makeSwap(15),
gasCost: gasSwap, constantGas: GasFastestStep,
validateStack: makeSwapStackFunc(16), minStack: minSwapStack(16),
maxStack: maxSwapStack(16),
valid: true, valid: true,
}, },
SWAP16: { SWAP16: {
execute: makeSwap(16), execute: makeSwap(16),
gasCost: gasSwap, constantGas: GasFastestStep,
validateStack: makeSwapStackFunc(17), minStack: minSwapStack(17),
maxStack: maxSwapStack(17),
valid: true, valid: true,
}, },
LOG0: { LOG0: {
execute: makeLog(0), execute: makeLog(0),
gasCost: makeGasLog(0), dynamicGas: makeGasLog(0),
validateStack: makeStackFunc(2, 0), minStack: minStack(2, 0),
maxStack: maxStack(2, 0),
memorySize: memoryLog, memorySize: memoryLog,
valid: true, valid: true,
writes: true, writes: true,
}, },
LOG1: { LOG1: {
execute: makeLog(1), execute: makeLog(1),
gasCost: makeGasLog(1), dynamicGas: makeGasLog(1),
validateStack: makeStackFunc(3, 0), minStack: minStack(3, 0),
maxStack: maxStack(3, 0),
memorySize: memoryLog, memorySize: memoryLog,
valid: true, valid: true,
writes: true, writes: true,
}, },
LOG2: { LOG2: {
execute: makeLog(2), execute: makeLog(2),
gasCost: makeGasLog(2), dynamicGas: makeGasLog(2),
validateStack: makeStackFunc(4, 0), minStack: minStack(4, 0),
maxStack: maxStack(4, 0),
memorySize: memoryLog, memorySize: memoryLog,
valid: true, valid: true,
writes: true, writes: true,
}, },
LOG3: { LOG3: {
execute: makeLog(3), execute: makeLog(3),
gasCost: makeGasLog(3), dynamicGas: makeGasLog(3),
validateStack: makeStackFunc(5, 0), minStack: minStack(5, 0),
maxStack: maxStack(5, 0),
memorySize: memoryLog, memorySize: memoryLog,
valid: true, valid: true,
writes: true, writes: true,
}, },
LOG4: { LOG4: {
execute: makeLog(4), execute: makeLog(4),
gasCost: makeGasLog(4), dynamicGas: makeGasLog(4),
validateStack: makeStackFunc(6, 0), minStack: minStack(6, 0),
maxStack: maxStack(6, 0),
memorySize: memoryLog, memorySize: memoryLog,
valid: true, valid: true,
writes: true, writes: true,
}, },
CREATE: { CREATE: {
execute: opCreate, execute: opCreate,
gasCost: gasCreate, dynamicGas: gasCreate,
validateStack: makeStackFunc(3, 1), minStack: minStack(3, 1),
maxStack: maxStack(3, 1),
memorySize: memoryCreate, memorySize: memoryCreate,
valid: true, valid: true,
writes: true, writes: true,
...@@ -932,32 +1070,36 @@ func newFrontierInstructionSet() [256]operation { ...@@ -932,32 +1070,36 @@ func newFrontierInstructionSet() [256]operation {
}, },
CALL: { CALL: {
execute: opCall, execute: opCall,
gasCost: gasCall, dynamicGas: gasCall,
validateStack: makeStackFunc(7, 1), minStack: minStack(7, 1),
maxStack: maxStack(7, 1),
memorySize: memoryCall, memorySize: memoryCall,
valid: true, valid: true,
returns: true, returns: true,
}, },
CALLCODE: { CALLCODE: {
execute: opCallCode, execute: opCallCode,
gasCost: gasCallCode, dynamicGas: gasCallCode,
validateStack: makeStackFunc(7, 1), minStack: minStack(7, 1),
maxStack: maxStack(7, 1),
memorySize: memoryCall, memorySize: memoryCall,
valid: true, valid: true,
returns: true, returns: true,
}, },
RETURN: { RETURN: {
execute: opReturn, execute: opReturn,
gasCost: gasReturn, dynamicGas: gasReturn,
validateStack: makeStackFunc(2, 0), minStack: minStack(2, 0),
maxStack: maxStack(2, 0),
memorySize: memoryReturn, memorySize: memoryReturn,
halts: true, halts: true,
valid: true, valid: true,
}, },
SELFDESTRUCT: { SELFDESTRUCT: {
execute: opSuicide, execute: opSuicide,
gasCost: gasSuicide, dynamicGas: gasSuicide,
validateStack: makeStackFunc(1, 0), minStack: minStack(1, 0),
maxStack: maxStack(1, 0),
halts: true, halts: true,
valid: true, valid: true,
writes: true, writes: true,
......
...@@ -16,82 +16,98 @@ ...@@ -16,82 +16,98 @@
package vm package vm
import ( func memorySha3(stack *Stack) (uint64, bool) {
"math/big" return calcMemSize64(stack.Back(0), stack.Back(1))
"github.com/ethereum/go-ethereum/common/math"
)
func memorySha3(stack *Stack) *big.Int {
return calcMemSize(stack.Back(0), stack.Back(1))
} }
func memoryCallDataCopy(stack *Stack) *big.Int { func memoryCallDataCopy(stack *Stack) (uint64, bool) {
return calcMemSize(stack.Back(0), stack.Back(2)) return calcMemSize64(stack.Back(0), stack.Back(2))
} }
func memoryReturnDataCopy(stack *Stack) *big.Int { func memoryReturnDataCopy(stack *Stack) (uint64, bool) {
return calcMemSize(stack.Back(0), stack.Back(2)) return calcMemSize64(stack.Back(0), stack.Back(2))
} }
func memoryCodeCopy(stack *Stack) *big.Int { func memoryCodeCopy(stack *Stack) (uint64, bool) {
return calcMemSize(stack.Back(0), stack.Back(2)) return calcMemSize64(stack.Back(0), stack.Back(2))
} }
func memoryExtCodeCopy(stack *Stack) *big.Int { func memoryExtCodeCopy(stack *Stack) (uint64, bool) {
return calcMemSize(stack.Back(1), stack.Back(3)) return calcMemSize64(stack.Back(1), stack.Back(3))
} }
func memoryMLoad(stack *Stack) *big.Int { func memoryMLoad(stack *Stack) (uint64, bool) {
return calcMemSize(stack.Back(0), big.NewInt(32)) return calcMemSize64WithUint(stack.Back(0), 32)
} }
func memoryMStore8(stack *Stack) *big.Int { func memoryMStore8(stack *Stack) (uint64, bool) {
return calcMemSize(stack.Back(0), big.NewInt(1)) return calcMemSize64WithUint(stack.Back(0), 1)
} }
func memoryMStore(stack *Stack) *big.Int { func memoryMStore(stack *Stack) (uint64, bool) {
return calcMemSize(stack.Back(0), big.NewInt(32)) return calcMemSize64WithUint(stack.Back(0), 32)
} }
func memoryCreate(stack *Stack) *big.Int { func memoryCreate(stack *Stack) (uint64, bool) {
return calcMemSize(stack.Back(1), stack.Back(2)) return calcMemSize64(stack.Back(1), stack.Back(2))
} }
func memoryCreate2(stack *Stack) *big.Int { func memoryCreate2(stack *Stack) (uint64, bool) {
return calcMemSize(stack.Back(1), stack.Back(2)) return calcMemSize64(stack.Back(1), stack.Back(2))
} }
func memoryCall(stack *Stack) *big.Int { func memoryCall(stack *Stack) (uint64, bool) {
x := calcMemSize(stack.Back(5), stack.Back(6)) x, overflow := calcMemSize64(stack.Back(5), stack.Back(6))
y := calcMemSize(stack.Back(3), stack.Back(4)) if overflow {
return 0, true
return math.BigMax(x, y) }
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) (uint64, bool) {
func memoryDelegateCall(stack *Stack) *big.Int { x, overflow := calcMemSize64(stack.Back(4), stack.Back(5))
x := calcMemSize(stack.Back(4), stack.Back(5)) if overflow {
y := calcMemSize(stack.Back(2), stack.Back(3)) return 0, true
}
return math.BigMax(x, y) 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 { func memoryStaticCall(stack *Stack) (uint64, bool) {
x := calcMemSize(stack.Back(4), stack.Back(5)) x, overflow := calcMemSize64(stack.Back(4), stack.Back(5))
y := calcMemSize(stack.Back(2), stack.Back(3)) if overflow {
return 0, true
return math.BigMax(x, y) }
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 { func memoryReturn(stack *Stack) (uint64, bool) {
return calcMemSize(stack.Back(0), stack.Back(1)) return calcMemSize64(stack.Back(0), stack.Back(1))
} }
func memoryRevert(stack *Stack) *big.Int { func memoryRevert(stack *Stack) (uint64, bool) {
return calcMemSize(stack.Back(0), stack.Back(1)) return calcMemSize64(stack.Back(0), stack.Back(1))
} }
func memoryLog(stack *Stack) *big.Int { func memoryLog(stack *Stack) (uint64, bool) {
mSize, mStart := stack.Back(1), stack.Back(0) return calcMemSize64(stack.Back(0), stack.Back(1))
return calcMemSize(mStart, mSize)
} }
...@@ -17,28 +17,26 @@ ...@@ -17,28 +17,26 @@
package vm package vm
import ( import (
"fmt"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
) )
func makeStackFunc(pop, push int) stackValidationFunc { func minSwapStack(n int) int {
return func(stack *Stack) error { return minStack(n, n)
if err := stack.require(pop); err != nil { }
return err 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 makeDupStackFunc(n int) stackValidationFunc { func minDupStack(n int) int {
return makeStackFunc(n, n+1) return minStack(n, n+1)
}
func maxDupStack(n int) int {
return maxStack(n, n+1)
} }
func makeSwapStackFunc(n int) stackValidationFunc { func maxStack(pop, push int) int {
return makeStackFunc(n, n) return int(params.StackLimit) + pop - push
}
func minStack(pops, push int) int {
return pops
} }
...@@ -65,7 +65,7 @@ ...@@ -65,7 +65,7 @@
"value": "0x0" "value": "0x0"
} }
], ],
"error": "invalid jump destination (PUSH1) 0", "error": "evm: invalid jump destination",
"from": "0xe4a13bc304682a903e9472f469c33801dd18d9e8", "from": "0xe4a13bc304682a903e9472f469c33801dd18d9e8",
"gas": "0x435c8", "gas": "0x435c8",
"gasUsed": "0x435c8", "gasUsed": "0x435c8",
......
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
}, },
"input": "0xf88b8206668504a817c8008303d09094c212e03b9e060e36facad5fd8f4435412ca22e6b80a451a34eb8000000000000000000000000000000000000000000000027fad02094277c000029a0692a3b4e7b2842f8dd7832e712c21e09f451f416c8976d5b8d02e8c0c2b4bea9a07645e90fc421b63dd755767fd93d3c03b4ec0c4d8fafa059558d08cf11d59750", "input": "0xf88b8206668504a817c8008303d09094c212e03b9e060e36facad5fd8f4435412ca22e6b80a451a34eb8000000000000000000000000000000000000000000000027fad02094277c000029a0692a3b4e7b2842f8dd7832e712c21e09f451f416c8976d5b8d02e8c0c2b4bea9a07645e90fc421b63dd755767fd93d3c03b4ec0c4d8fafa059558d08cf11d59750",
"result": { "result": {
"error": "invalid jump destination (PUSH1) 2", "error": "evm: invalid jump destination",
"from": "0x70c9217d814985faef62b124420f8dfbddd96433", "from": "0x70c9217d814985faef62b124420f8dfbddd96433",
"gas": "0x37b38", "gas": "0x37b38",
"gasUsed": "0x37b38", "gasUsed": "0x37b38",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment