diff --git a/core/vm/eips.go b/core/vm/eips.go index 062d40779..8bf697e1b 100644 --- a/core/vm/eips.go +++ b/core/vm/eips.go @@ -60,9 +60,9 @@ func enable1884(jt *JumpTable) { } } -func opSelfBalance(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - balance := interpreter.intPool.get().Set(interpreter.evm.StateDB.GetBalance(contract.Address())) - stack.push(balance) +func opSelfBalance(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + balance := interpreter.intPool.get().Set(interpreter.evm.StateDB.GetBalance(callContext.contract.Address())) + callContext.stack.push(balance) return nil, nil } @@ -80,9 +80,9 @@ func enable1344(jt *JumpTable) { } // opChainID implements CHAINID opcode -func opChainID(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opChainID(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { chainId := interpreter.intPool.get().Set(interpreter.evm.chainConfig.ChainID) - stack.push(chainId) + callContext.stack.push(chainId) return nil, nil } diff --git a/core/vm/instructions.go b/core/vm/instructions.go index d65664b67..9ac4cd47c 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -37,48 +37,48 @@ var ( errInvalidJump = errors.New("evm: invalid jump destination") ) -func opAdd(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.peek() +func opAdd(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + x, y := callContext.stack.pop(), callContext.stack.peek() math.U256(y.Add(x, y)) - interpreter.intPool.put(x) + interpreter.intPool.putOne(x) return nil, nil } -func opSub(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.peek() +func opSub(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + x, y := callContext.stack.pop(), callContext.stack.peek() math.U256(y.Sub(x, y)) - interpreter.intPool.put(x) + interpreter.intPool.putOne(x) return nil, nil } -func opMul(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.pop() - stack.push(math.U256(x.Mul(x, y))) +func opMul(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + x, y := callContext.stack.pop(), callContext.stack.pop() + callContext.stack.push(math.U256(x.Mul(x, y))) - interpreter.intPool.put(y) + interpreter.intPool.putOne(y) return nil, nil } -func opDiv(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.peek() +func opDiv(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + x, y := callContext.stack.pop(), callContext.stack.peek() if y.Sign() != 0 { math.U256(y.Div(x, y)) } else { y.SetUint64(0) } - interpreter.intPool.put(x) + interpreter.intPool.putOne(x) return nil, nil } -func opSdiv(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := math.S256(stack.pop()), math.S256(stack.pop()) +func opSdiv(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + x, y := math.S256(callContext.stack.pop()), math.S256(callContext.stack.pop()) res := interpreter.intPool.getZero() if y.Sign() == 0 || x.Sign() == 0 { - stack.push(res) + callContext.stack.push(res) } else { if x.Sign() != y.Sign() { res.Div(x.Abs(x), y.Abs(y)) @@ -86,29 +86,29 @@ func opSdiv(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory } else { res.Div(x.Abs(x), y.Abs(y)) } - stack.push(math.U256(res)) + callContext.stack.push(math.U256(res)) } interpreter.intPool.put(x, y) return nil, nil } -func opMod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.pop() +func opMod(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + x, y := callContext.stack.pop(), callContext.stack.pop() if y.Sign() == 0 { - stack.push(x.SetUint64(0)) + callContext.stack.push(x.SetUint64(0)) } else { - stack.push(math.U256(x.Mod(x, y))) + callContext.stack.push(math.U256(x.Mod(x, y))) } - interpreter.intPool.put(y) + interpreter.intPool.putOne(y) return nil, nil } -func opSmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := math.S256(stack.pop()), math.S256(stack.pop()) +func opSmod(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + x, y := math.S256(callContext.stack.pop()), math.S256(callContext.stack.pop()) res := interpreter.intPool.getZero() if y.Sign() == 0 { - stack.push(res) + callContext.stack.push(res) } else { if x.Sign() < 0 { res.Mod(x.Abs(x), y.Abs(y)) @@ -116,38 +116,38 @@ func opSmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory } else { res.Mod(x.Abs(x), y.Abs(y)) } - stack.push(math.U256(res)) + callContext.stack.push(math.U256(res)) } interpreter.intPool.put(x, y) return nil, nil } -func opExp(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - base, exponent := stack.pop(), stack.pop() +func opExp(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + base, exponent := callContext.stack.pop(), callContext.stack.pop() // some shortcuts cmpToOne := exponent.Cmp(big1) if cmpToOne < 0 { // Exponent is zero // x ^ 0 == 1 - stack.push(base.SetUint64(1)) + callContext.stack.push(base.SetUint64(1)) } else if base.Sign() == 0 { // 0 ^ y, if y != 0, == 0 - stack.push(base.SetUint64(0)) + callContext.stack.push(base.SetUint64(0)) } else if cmpToOne == 0 { // Exponent is one // x ^ 1 == x - stack.push(base) + callContext.stack.push(base) } else { - stack.push(math.Exp(base, exponent)) - interpreter.intPool.put(base) + callContext.stack.push(math.Exp(base, exponent)) + interpreter.intPool.putOne(base) } - interpreter.intPool.put(exponent) + interpreter.intPool.putOne(exponent) return nil, nil } -func opSignExtend(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - back := stack.pop() +func opSignExtend(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + back := callContext.stack.pop() if back.Cmp(big.NewInt(31)) < 0 { bit := uint(back.Uint64()*8 + 7) - num := stack.pop() + num := callContext.stack.pop() mask := back.Lsh(common.Big1, bit) mask.Sub(mask, common.Big1) if num.Bit(int(bit)) > 0 { @@ -156,43 +156,43 @@ func opSignExtend(pc *uint64, interpreter *EVMInterpreter, contract *Contract, m num.And(num, mask) } - stack.push(math.U256(num)) + callContext.stack.push(math.U256(num)) } - interpreter.intPool.put(back) + interpreter.intPool.putOne(back) return nil, nil } -func opNot(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x := stack.peek() +func opNot(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + x := callContext.stack.peek() math.U256(x.Not(x)) return nil, nil } -func opLt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.peek() +func opLt(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + x, y := callContext.stack.pop(), callContext.stack.peek() if x.Cmp(y) < 0 { y.SetUint64(1) } else { y.SetUint64(0) } - interpreter.intPool.put(x) + interpreter.intPool.putOne(x) return nil, nil } -func opGt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.peek() +func opGt(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + x, y := callContext.stack.pop(), callContext.stack.peek() if x.Cmp(y) > 0 { y.SetUint64(1) } else { y.SetUint64(0) } - interpreter.intPool.put(x) + interpreter.intPool.putOne(x) return nil, nil } -func opSlt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.peek() +func opSlt(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + x, y := callContext.stack.pop(), callContext.stack.peek() xSign := x.Cmp(tt255) ySign := y.Cmp(tt255) @@ -211,12 +211,12 @@ func opSlt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory * y.SetUint64(0) } } - interpreter.intPool.put(x) + interpreter.intPool.putOne(x) return nil, nil } -func opSgt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.peek() +func opSgt(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + x, y := callContext.stack.pop(), callContext.stack.peek() xSign := x.Cmp(tt255) ySign := y.Cmp(tt255) @@ -235,23 +235,23 @@ func opSgt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory * y.SetUint64(0) } } - interpreter.intPool.put(x) + interpreter.intPool.putOne(x) return nil, nil } -func opEq(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.peek() +func opEq(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + x, y := callContext.stack.pop(), callContext.stack.peek() if x.Cmp(y) == 0 { y.SetUint64(1) } else { y.SetUint64(0) } - interpreter.intPool.put(x) + interpreter.intPool.putOne(x) return nil, nil } -func opIszero(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x := stack.peek() +func opIszero(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + x := callContext.stack.peek() if x.Sign() > 0 { x.SetUint64(0) } else { @@ -260,63 +260,63 @@ func opIszero(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor return nil, nil } -func opAnd(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.pop() - stack.push(x.And(x, y)) +func opAnd(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + x, y := callContext.stack.pop(), callContext.stack.pop() + callContext.stack.push(x.And(x, y)) - interpreter.intPool.put(y) + interpreter.intPool.putOne(y) return nil, nil } -func opOr(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.peek() +func opOr(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + x, y := callContext.stack.pop(), callContext.stack.peek() y.Or(x, y) - interpreter.intPool.put(x) + interpreter.intPool.putOne(x) return nil, nil } -func opXor(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.peek() +func opXor(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + x, y := callContext.stack.pop(), callContext.stack.peek() y.Xor(x, y) - interpreter.intPool.put(x) + interpreter.intPool.putOne(x) return nil, nil } -func opByte(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - th, val := stack.pop(), stack.peek() +func opByte(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + th, val := callContext.stack.pop(), callContext.stack.peek() if th.Cmp(common.Big32) < 0 { b := math.Byte(val, 32, int(th.Int64())) val.SetUint64(uint64(b)) } else { val.SetUint64(0) } - interpreter.intPool.put(th) + interpreter.intPool.putOne(th) return nil, nil } -func opAddmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y, z := stack.pop(), stack.pop(), stack.pop() +func opAddmod(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + x, y, z := callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop() if z.Cmp(bigZero) > 0 { x.Add(x, y) x.Mod(x, z) - stack.push(math.U256(x)) + callContext.stack.push(math.U256(x)) } else { - stack.push(x.SetUint64(0)) + callContext.stack.push(x.SetUint64(0)) } interpreter.intPool.put(y, z) return nil, nil } -func opMulmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y, z := stack.pop(), stack.pop(), stack.pop() +func opMulmod(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + x, y, z := callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop() if z.Cmp(bigZero) > 0 { x.Mul(x, y) x.Mod(x, z) - stack.push(math.U256(x)) + callContext.stack.push(math.U256(x)) } else { - stack.push(x.SetUint64(0)) + callContext.stack.push(x.SetUint64(0)) } interpreter.intPool.put(y, z) return nil, nil @@ -325,10 +325,10 @@ func opMulmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor // opSHL implements Shift Left // The SHL instruction (shift left) pops 2 values from the stack, first arg1 and then arg2, // and pushes on the stack arg2 shifted to the left by arg1 number of bits. -func opSHL(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opSHL(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { // Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards - shift, value := math.U256(stack.pop()), math.U256(stack.peek()) - defer interpreter.intPool.put(shift) // First operand back into the pool + shift, value := math.U256(callContext.stack.pop()), math.U256(callContext.stack.peek()) + defer interpreter.intPool.putOne(shift) // First operand back into the pool if shift.Cmp(common.Big256) >= 0 { value.SetUint64(0) @@ -343,10 +343,10 @@ func opSHL(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory * // opSHR implements Logical Shift Right // The SHR instruction (logical shift right) pops 2 values from the stack, first arg1 and then arg2, // and pushes on the stack arg2 shifted to the right by arg1 number of bits with zero fill. -func opSHR(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opSHR(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { // Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards - shift, value := math.U256(stack.pop()), math.U256(stack.peek()) - defer interpreter.intPool.put(shift) // First operand back into the pool + shift, value := math.U256(callContext.stack.pop()), math.U256(callContext.stack.peek()) + defer interpreter.intPool.putOne(shift) // First operand back into the pool if shift.Cmp(common.Big256) >= 0 { value.SetUint64(0) @@ -361,10 +361,10 @@ func opSHR(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory * // opSAR implements Arithmetic Shift Right // The SAR instruction (arithmetic shift right) pops 2 values from the stack, first arg1 and then arg2, // and pushes on the stack arg2 shifted to the right by arg1 number of bits with sign extension. -func opSAR(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opSAR(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { // Note, S256 returns (potentially) a new bigint, so we're popping, not peeking this one - shift, value := math.U256(stack.pop()), math.S256(stack.pop()) - defer interpreter.intPool.put(shift) // First operand back into the pool + shift, value := math.U256(callContext.stack.pop()), math.S256(callContext.stack.pop()) + defer interpreter.intPool.putOne(shift) // First operand back into the pool if shift.Cmp(common.Big256) >= 0 { if value.Sign() >= 0 { @@ -372,19 +372,19 @@ func opSAR(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory * } else { value.SetInt64(-1) } - stack.push(math.U256(value)) + callContext.stack.push(math.U256(value)) return nil, nil } n := uint(shift.Uint64()) value.Rsh(value, n) - stack.push(math.U256(value)) + callContext.stack.push(math.U256(value)) return nil, nil } -func opSha3(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - offset, size := stack.pop(), stack.pop() - data := memory.GetPtr(offset.Int64(), size.Int64()) +func opSha3(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + offset, size := callContext.stack.pop(), callContext.stack.pop() + data := callContext.memory.GetPtr(offset.Int64(), size.Int64()) if interpreter.hasher == nil { interpreter.hasher = sha3.NewLegacyKeccak256().(keccakState) @@ -398,70 +398,70 @@ func opSha3(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory if evm.vmConfig.EnablePreimageRecording { evm.StateDB.AddPreimage(interpreter.hasherBuf, data) } - stack.push(interpreter.intPool.get().SetBytes(interpreter.hasherBuf[:])) + callContext.stack.push(interpreter.intPool.get().SetBytes(interpreter.hasherBuf[:])) interpreter.intPool.put(offset, size) return nil, nil } -func opAddress(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(interpreter.intPool.get().SetBytes(contract.Address().Bytes())) +func opAddress(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + callContext.stack.push(interpreter.intPool.get().SetBytes(callContext.contract.Address().Bytes())) return nil, nil } -func opBalance(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - slot := stack.peek() +func opBalance(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + slot := callContext.stack.peek() slot.Set(interpreter.evm.StateDB.GetBalance(common.BigToAddress(slot))) return nil, nil } -func opOrigin(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(interpreter.intPool.get().SetBytes(interpreter.evm.Origin.Bytes())) +func opOrigin(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + callContext.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(interpreter.intPool.get().SetBytes(contract.Caller().Bytes())) +func opCaller(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + callContext.stack.push(interpreter.intPool.get().SetBytes(callContext.contract.Caller().Bytes())) return nil, nil } -func opCallValue(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(interpreter.intPool.get().Set(contract.value)) +func opCallValue(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + callContext.stack.push(interpreter.intPool.get().Set(callContext.contract.value)) return nil, nil } -func opCallDataLoad(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(interpreter.intPool.get().SetBytes(getDataBig(contract.Input, stack.pop(), big32))) +func opCallDataLoad(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + callContext.stack.push(interpreter.intPool.get().SetBytes(getDataBig(callContext.contract.Input, callContext.stack.pop(), big32))) return nil, nil } -func opCallDataSize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(interpreter.intPool.get().SetInt64(int64(len(contract.Input)))) +func opCallDataSize(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + callContext.stack.push(interpreter.intPool.get().SetInt64(int64(len(callContext.contract.Input)))) return nil, nil } -func opCallDataCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opCallDataCopy(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { var ( - memOffset = stack.pop() - dataOffset = stack.pop() - length = stack.pop() + memOffset = callContext.stack.pop() + dataOffset = callContext.stack.pop() + length = callContext.stack.pop() ) - memory.Set(memOffset.Uint64(), length.Uint64(), getDataBig(contract.Input, dataOffset, length)) + callContext.memory.Set(memOffset.Uint64(), length.Uint64(), getDataBig(callContext.contract.Input, dataOffset, length)) interpreter.intPool.put(memOffset, dataOffset, length) return nil, nil } -func opReturnDataSize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(interpreter.intPool.get().SetUint64(uint64(len(interpreter.returnData)))) +func opReturnDataSize(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + callContext.stack.push(interpreter.intPool.get().SetUint64(uint64(len(interpreter.returnData)))) return nil, nil } -func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { var ( - memOffset = stack.pop() - dataOffset = stack.pop() - length = stack.pop() + memOffset = callContext.stack.pop() + dataOffset = callContext.stack.pop() + length = callContext.stack.pop() end = interpreter.intPool.get().Add(dataOffset, length) ) @@ -470,47 +470,47 @@ func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contrac if !end.IsUint64() || uint64(len(interpreter.returnData)) < end.Uint64() { return nil, errReturnDataOutOfBounds } - memory.Set(memOffset.Uint64(), length.Uint64(), interpreter.returnData[dataOffset.Uint64():end.Uint64()]) + callContext.memory.Set(memOffset.Uint64(), length.Uint64(), interpreter.returnData[dataOffset.Uint64():end.Uint64()]) return nil, nil } -func opExtCodeSize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - slot := stack.peek() +func opExtCodeSize(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + slot := callContext.stack.peek() slot.SetUint64(uint64(interpreter.evm.StateDB.GetCodeSize(common.BigToAddress(slot)))) return nil, nil } -func opCodeSize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - l := interpreter.intPool.get().SetInt64(int64(len(contract.Code))) - stack.push(l) +func opCodeSize(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + l := interpreter.intPool.get().SetInt64(int64(len(callContext.contract.Code))) + callContext.stack.push(l) return nil, nil } -func opCodeCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opCodeCopy(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { var ( - memOffset = stack.pop() - codeOffset = stack.pop() - length = stack.pop() + memOffset = callContext.stack.pop() + codeOffset = callContext.stack.pop() + length = callContext.stack.pop() ) - codeCopy := getDataBig(contract.Code, codeOffset, length) - memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy) + codeCopy := getDataBig(callContext.contract.Code, codeOffset, length) + callContext.memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy) interpreter.intPool.put(memOffset, codeOffset, length) return nil, nil } -func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { var ( - addr = common.BigToAddress(stack.pop()) - memOffset = stack.pop() - codeOffset = stack.pop() - length = stack.pop() + addr = common.BigToAddress(callContext.stack.pop()) + memOffset = callContext.stack.pop() + codeOffset = callContext.stack.pop() + length = callContext.stack.pop() ) codeCopy := getDataBig(interpreter.evm.StateDB.GetCode(addr), codeOffset, length) - memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy) + callContext.memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy) interpreter.intPool.put(memOffset, codeOffset, length) return nil, nil @@ -542,8 +542,8 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract, // // (6) Caller tries to get the code hash for an account which is marked as deleted, // this account should be regarded as a non-existent account and zero should be returned. -func opExtCodeHash(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - slot := stack.peek() +func opExtCodeHash(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + slot := callContext.stack.peek() address := common.BigToAddress(slot) if interpreter.evm.StateDB.Empty(address) { slot.SetUint64(0) @@ -553,108 +553,108 @@ func opExtCodeHash(pc *uint64, interpreter *EVMInterpreter, contract *Contract, return nil, nil } -func opGasprice(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(interpreter.intPool.get().Set(interpreter.evm.GasPrice)) +func opGasprice(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + callContext.stack.push(interpreter.intPool.get().Set(interpreter.evm.GasPrice)) return nil, nil } -func opBlockhash(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - num := stack.pop() +func opBlockhash(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + num := callContext.stack.pop() n := interpreter.intPool.get().Sub(interpreter.evm.BlockNumber, common.Big257) if num.Cmp(n) > 0 && num.Cmp(interpreter.evm.BlockNumber) < 0 { - stack.push(interpreter.evm.GetHash(num.Uint64()).Big()) + callContext.stack.push(interpreter.evm.GetHash(num.Uint64()).Big()) } else { - stack.push(interpreter.intPool.getZero()) + callContext.stack.push(interpreter.intPool.getZero()) } interpreter.intPool.put(num, n) return nil, nil } -func opCoinbase(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(interpreter.intPool.get().SetBytes(interpreter.evm.Coinbase.Bytes())) +func opCoinbase(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + callContext.stack.push(interpreter.intPool.get().SetBytes(interpreter.evm.Coinbase.Bytes())) return nil, nil } -func opTimestamp(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(math.U256(interpreter.intPool.get().Set(interpreter.evm.Time))) +func opTimestamp(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + callContext.stack.push(math.U256(interpreter.intPool.get().Set(interpreter.evm.Time))) return nil, nil } -func opNumber(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(math.U256(interpreter.intPool.get().Set(interpreter.evm.BlockNumber))) +func opNumber(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + callContext.stack.push(math.U256(interpreter.intPool.get().Set(interpreter.evm.BlockNumber))) return nil, nil } -func opDifficulty(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(math.U256(interpreter.intPool.get().Set(interpreter.evm.Difficulty))) +func opDifficulty(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + callContext.stack.push(math.U256(interpreter.intPool.get().Set(interpreter.evm.Difficulty))) return nil, nil } -func opGasLimit(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(math.U256(interpreter.intPool.get().SetUint64(interpreter.evm.GasLimit))) +func opGasLimit(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + callContext.stack.push(math.U256(interpreter.intPool.get().SetUint64(interpreter.evm.GasLimit))) return nil, nil } -func opPop(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - interpreter.intPool.put(stack.pop()) +func opPop(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + interpreter.intPool.putOne(callContext.stack.pop()) return nil, nil } -func opMload(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - v := stack.peek() +func opMload(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + v := callContext.stack.peek() offset := v.Int64() - v.SetBytes(memory.GetPtr(offset, 32)) + v.SetBytes(callContext.memory.GetPtr(offset, 32)) return nil, nil } -func opMstore(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opMstore(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { // pop value of the stack - mStart, val := stack.pop(), stack.pop() - memory.Set32(mStart.Uint64(), val) + mStart, val := callContext.stack.pop(), callContext.stack.pop() + callContext.memory.Set32(mStart.Uint64(), val) interpreter.intPool.put(mStart, val) return nil, nil } -func opMstore8(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - off, val := stack.pop().Int64(), stack.pop().Int64() - memory.store[off] = byte(val & 0xff) +func opMstore8(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + off, val := callContext.stack.pop().Int64(), callContext.stack.pop().Int64() + callContext.memory.store[off] = byte(val & 0xff) return nil, nil } -func opSload(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - loc := stack.peek() - val := interpreter.evm.StateDB.GetState(contract.Address(), common.BigToHash(loc)) +func opSload(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + loc := callContext.stack.peek() + val := interpreter.evm.StateDB.GetState(callContext.contract.Address(), common.BigToHash(loc)) loc.SetBytes(val.Bytes()) return nil, nil } -func opSstore(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - loc := common.BigToHash(stack.pop()) - val := stack.pop() - interpreter.evm.StateDB.SetState(contract.Address(), loc, common.BigToHash(val)) +func opSstore(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + loc := common.BigToHash(callContext.stack.pop()) + val := callContext.stack.pop() + interpreter.evm.StateDB.SetState(callContext.contract.Address(), loc, common.BigToHash(val)) - interpreter.intPool.put(val) + interpreter.intPool.putOne(val) return nil, nil } -func opJump(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - pos := stack.pop() - if !contract.validJumpdest(pos) { +func opJump(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + pos := callContext.stack.pop() + if !callContext.contract.validJumpdest(pos) { return nil, errInvalidJump } *pc = pos.Uint64() - interpreter.intPool.put(pos) + interpreter.intPool.putOne(pos) return nil, nil } -func opJumpi(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - pos, cond := stack.pop(), stack.pop() +func opJumpi(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + pos, cond := callContext.stack.pop(), callContext.stack.pop() if cond.Sign() != 0 { - if !contract.validJumpdest(pos) { + if !callContext.contract.validJumpdest(pos) { return nil, errInvalidJump } *pc = pos.Uint64() @@ -666,50 +666,50 @@ func opJumpi(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory return nil, nil } -func opJumpdest(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opJumpdest(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { return nil, nil } -func opPc(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(interpreter.intPool.get().SetUint64(*pc)) +func opPc(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + callContext.stack.push(interpreter.intPool.get().SetUint64(*pc)) return nil, nil } -func opMsize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(interpreter.intPool.get().SetInt64(int64(memory.Len()))) +func opMsize(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + callContext.stack.push(interpreter.intPool.get().SetInt64(int64(callContext.memory.Len()))) return nil, nil } -func opGas(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(interpreter.intPool.get().SetUint64(contract.Gas)) +func opGas(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + callContext.stack.push(interpreter.intPool.get().SetUint64(callContext.contract.Gas)) return nil, nil } -func opCreate(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opCreate(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { var ( - value = stack.pop() - offset, size = stack.pop(), stack.pop() - input = memory.GetCopy(offset.Int64(), size.Int64()) - gas = contract.Gas + value = callContext.stack.pop() + offset, size = callContext.stack.pop(), callContext.stack.pop() + input = callContext.memory.GetCopy(offset.Int64(), size.Int64()) + gas = callContext.contract.Gas ) if interpreter.evm.chainRules.IsEIP150 { gas -= gas / 64 } - contract.UseGas(gas) - res, addr, returnGas, suberr := interpreter.evm.Create(contract, input, gas, value) + callContext.contract.UseGas(gas) + res, addr, returnGas, suberr := interpreter.evm.Create(callContext.contract, input, gas, value) // Push item on the stack based on the returned error. If the ruleset is // homestead we must check for CodeStoreOutOfGasError (homestead only // rule) and treat as an error, if the ruleset is frontier we must // ignore this error and pretend the operation was successful. if interpreter.evm.chainRules.IsHomestead && suberr == ErrCodeStoreOutOfGas { - stack.push(interpreter.intPool.getZero()) + callContext.stack.push(interpreter.intPool.getZero()) } else if suberr != nil && suberr != ErrCodeStoreOutOfGas { - stack.push(interpreter.intPool.getZero()) + callContext.stack.push(interpreter.intPool.getZero()) } else { - stack.push(interpreter.intPool.get().SetBytes(addr.Bytes())) + callContext.stack.push(interpreter.intPool.get().SetBytes(addr.Bytes())) } - contract.Gas += returnGas + callContext.contract.Gas += returnGas interpreter.intPool.put(value, offset, size) if suberr == errExecutionReverted { @@ -718,26 +718,26 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor return nil, nil } -func opCreate2(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opCreate2(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { var ( - endowment = stack.pop() - offset, size = stack.pop(), stack.pop() - salt = stack.pop() - input = memory.GetCopy(offset.Int64(), size.Int64()) - gas = contract.Gas + endowment = callContext.stack.pop() + offset, size = callContext.stack.pop(), callContext.stack.pop() + salt = callContext.stack.pop() + input = callContext.memory.GetCopy(offset.Int64(), size.Int64()) + gas = callContext.contract.Gas ) // Apply EIP150 gas -= gas / 64 - contract.UseGas(gas) - res, addr, returnGas, suberr := interpreter.evm.Create2(contract, input, gas, endowment, salt) + callContext.contract.UseGas(gas) + res, addr, returnGas, suberr := interpreter.evm.Create2(callContext.contract, input, gas, endowment, salt) // Push item on the stack based on the returned error. if suberr != nil { - stack.push(interpreter.intPool.getZero()) + callContext.stack.push(interpreter.intPool.getZero()) } else { - stack.push(interpreter.intPool.get().SetBytes(addr.Bytes())) + callContext.stack.push(interpreter.intPool.get().SetBytes(addr.Bytes())) } - contract.Gas += returnGas + callContext.contract.Gas += returnGas interpreter.intPool.put(endowment, offset, size, salt) if suberr == errExecutionReverted { @@ -746,139 +746,139 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memo return nil, nil } -func opCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opCall(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { // Pop gas. The actual gas in interpreter.evm.callGasTemp. - interpreter.intPool.put(stack.pop()) + interpreter.intPool.putOne(callContext.stack.pop()) gas := interpreter.evm.callGasTemp // Pop other call parameters. - addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() + addr, value, inOffset, inSize, retOffset, retSize := callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop() toAddr := common.BigToAddress(addr) value = math.U256(value) // Get the arguments from the memory. - args := memory.GetPtr(inOffset.Int64(), inSize.Int64()) + args := callContext.memory.GetPtr(inOffset.Int64(), inSize.Int64()) if value.Sign() != 0 { gas += params.CallStipend } - ret, returnGas, err := interpreter.evm.Call(contract, toAddr, args, gas, value) + ret, returnGas, err := interpreter.evm.Call(callContext.contract, toAddr, args, gas, value) if err != nil { - stack.push(interpreter.intPool.getZero()) + callContext.stack.push(interpreter.intPool.getZero()) } else { - stack.push(interpreter.intPool.get().SetUint64(1)) + callContext.stack.push(interpreter.intPool.get().SetUint64(1)) } if err == nil || err == errExecutionReverted { - memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) + callContext.memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } - contract.Gas += returnGas + callContext.contract.Gas += returnGas interpreter.intPool.put(addr, value, inOffset, inSize, retOffset, retSize) return ret, nil } -func opCallCode(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opCallCode(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { // Pop gas. The actual gas is in interpreter.evm.callGasTemp. - interpreter.intPool.put(stack.pop()) + interpreter.intPool.putOne(callContext.stack.pop()) gas := interpreter.evm.callGasTemp // Pop other call parameters. - addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() + addr, value, inOffset, inSize, retOffset, retSize := callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop() toAddr := common.BigToAddress(addr) value = math.U256(value) // Get arguments from the memory. - args := memory.GetPtr(inOffset.Int64(), inSize.Int64()) + args := callContext.memory.GetPtr(inOffset.Int64(), inSize.Int64()) if value.Sign() != 0 { gas += params.CallStipend } - ret, returnGas, err := interpreter.evm.CallCode(contract, toAddr, args, gas, value) + ret, returnGas, err := interpreter.evm.CallCode(callContext.contract, toAddr, args, gas, value) if err != nil { - stack.push(interpreter.intPool.getZero()) + callContext.stack.push(interpreter.intPool.getZero()) } else { - stack.push(interpreter.intPool.get().SetUint64(1)) + callContext.stack.push(interpreter.intPool.get().SetUint64(1)) } if err == nil || err == errExecutionReverted { - memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) + callContext.memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } - contract.Gas += returnGas + callContext.contract.Gas += returnGas interpreter.intPool.put(addr, value, inOffset, inSize, retOffset, retSize) return ret, nil } -func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { // Pop gas. The actual gas is in interpreter.evm.callGasTemp. - interpreter.intPool.put(stack.pop()) + interpreter.intPool.putOne(callContext.stack.pop()) gas := interpreter.evm.callGasTemp // Pop other call parameters. - addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() + addr, inOffset, inSize, retOffset, retSize := callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop() toAddr := common.BigToAddress(addr) // Get arguments from the memory. - args := memory.GetPtr(inOffset.Int64(), inSize.Int64()) + args := callContext.memory.GetPtr(inOffset.Int64(), inSize.Int64()) - ret, returnGas, err := interpreter.evm.DelegateCall(contract, toAddr, args, gas) + ret, returnGas, err := interpreter.evm.DelegateCall(callContext.contract, toAddr, args, gas) if err != nil { - stack.push(interpreter.intPool.getZero()) + callContext.stack.push(interpreter.intPool.getZero()) } else { - stack.push(interpreter.intPool.get().SetUint64(1)) + callContext.stack.push(interpreter.intPool.get().SetUint64(1)) } if err == nil || err == errExecutionReverted { - memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) + callContext.memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } - contract.Gas += returnGas + callContext.contract.Gas += returnGas interpreter.intPool.put(addr, inOffset, inSize, retOffset, retSize) return ret, nil } -func opStaticCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opStaticCall(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { // Pop gas. The actual gas is in interpreter.evm.callGasTemp. - interpreter.intPool.put(stack.pop()) + interpreter.intPool.putOne(callContext.stack.pop()) gas := interpreter.evm.callGasTemp // Pop other call parameters. - addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() + addr, inOffset, inSize, retOffset, retSize := callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop(), callContext.stack.pop() toAddr := common.BigToAddress(addr) // Get arguments from the memory. - args := memory.GetPtr(inOffset.Int64(), inSize.Int64()) + args := callContext.memory.GetPtr(inOffset.Int64(), inSize.Int64()) - ret, returnGas, err := interpreter.evm.StaticCall(contract, toAddr, args, gas) + ret, returnGas, err := interpreter.evm.StaticCall(callContext.contract, toAddr, args, gas) if err != nil { - stack.push(interpreter.intPool.getZero()) + callContext.stack.push(interpreter.intPool.getZero()) } else { - stack.push(interpreter.intPool.get().SetUint64(1)) + callContext.stack.push(interpreter.intPool.get().SetUint64(1)) } if err == nil || err == errExecutionReverted { - memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) + callContext.memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } - contract.Gas += returnGas + callContext.contract.Gas += returnGas interpreter.intPool.put(addr, inOffset, inSize, retOffset, retSize) return ret, nil } -func opReturn(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - offset, size := stack.pop(), stack.pop() - ret := memory.GetPtr(offset.Int64(), size.Int64()) +func opReturn(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + offset, size := callContext.stack.pop(), callContext.stack.pop() + ret := callContext.memory.GetPtr(offset.Int64(), size.Int64()) interpreter.intPool.put(offset, size) return ret, nil } -func opRevert(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - offset, size := stack.pop(), stack.pop() - ret := memory.GetPtr(offset.Int64(), size.Int64()) +func opRevert(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + offset, size := callContext.stack.pop(), callContext.stack.pop() + ret := callContext.memory.GetPtr(offset.Int64(), size.Int64()) interpreter.intPool.put(offset, size) return ret, nil } -func opStop(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opStop(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { return nil, nil } -func opSuicide(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - balance := interpreter.evm.StateDB.GetBalance(contract.Address()) - interpreter.evm.StateDB.AddBalance(common.BigToAddress(stack.pop()), balance) +func opSuicide(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + balance := interpreter.evm.StateDB.GetBalance(callContext.contract.Address()) + interpreter.evm.StateDB.AddBalance(common.BigToAddress(callContext.stack.pop()), balance) - interpreter.evm.StateDB.Suicide(contract.Address()) + interpreter.evm.StateDB.Suicide(callContext.contract.Address()) return nil, nil } @@ -886,16 +886,16 @@ func opSuicide(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memo // make log instruction function func makeLog(size int) executionFunc { - return func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + return func(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { topics := make([]common.Hash, size) - mStart, mSize := stack.pop(), stack.pop() + mStart, mSize := callContext.stack.pop(), callContext.stack.pop() for i := 0; i < size; i++ { - topics[i] = common.BigToHash(stack.pop()) + topics[i] = common.BigToHash(callContext.stack.pop()) } - d := memory.GetCopy(mStart.Int64(), mSize.Int64()) + d := callContext.memory.GetCopy(mStart.Int64(), mSize.Int64()) interpreter.evm.StateDB.AddLog(&types.Log{ - Address: contract.Address(), + Address: callContext.contract.Address(), Topics: topics, Data: d, // This is a non-consensus field, but assigned here because @@ -909,24 +909,24 @@ 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) { +func opPush1(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { var ( - codeLen = uint64(len(contract.Code)) + codeLen = uint64(len(callContext.contract.Code)) integer = interpreter.intPool.get() ) *pc += 1 if *pc < codeLen { - stack.push(integer.SetUint64(uint64(contract.Code[*pc]))) + callContext.stack.push(integer.SetUint64(uint64(callContext.contract.Code[*pc]))) } else { - stack.push(integer.SetUint64(0)) + callContext.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) { - codeLen := len(contract.Code) + return func(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + codeLen := len(callContext.contract.Code) startMin := codeLen if int(*pc+1) < startMin { @@ -939,7 +939,7 @@ func makePush(size uint64, pushByteSize int) executionFunc { } integer := interpreter.intPool.get() - stack.push(integer.SetBytes(common.RightPadBytes(contract.Code[startMin:endMin], pushByteSize))) + callContext.stack.push(integer.SetBytes(common.RightPadBytes(callContext.contract.Code[startMin:endMin], pushByteSize))) *pc += size return nil, nil @@ -948,8 +948,8 @@ func makePush(size uint64, pushByteSize int) executionFunc { // make dup instruction function func makeDup(size int64) executionFunc { - return func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.dup(interpreter.intPool, int(size)) + return func(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + callContext.stack.dup(interpreter.intPool, int(size)) return nil, nil } } @@ -958,8 +958,8 @@ func makeDup(size int64) executionFunc { func makeSwap(size int64) executionFunc { // switch n + 1 otherwise n would be swapped with n size++ - return func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.swap(int(size)) + return func(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + callContext.stack.swap(int(size)) return nil, nil } } diff --git a/core/vm/instructions_test.go b/core/vm/instructions_test.go index bdc62d177..d21dbf142 100644 --- a/core/vm/instructions_test.go +++ b/core/vm/instructions_test.go @@ -109,7 +109,7 @@ func testTwoOperandOp(t *testing.T, tests []TwoOperandTestcase, opFn executionFu expected := new(big.Int).SetBytes(common.Hex2Bytes(test.Expected)) stack.push(x) stack.push(y) - opFn(&pc, evmInterpreter, nil, nil, stack) + opFn(&pc, evmInterpreter, &callCtx{nil, stack, nil}) actual := stack.pop() if actual.Cmp(expected) != 0 { @@ -223,7 +223,7 @@ func getResult(args []*twoOperandParams, opFn executionFunc) []TwoOperandTestcas y := new(big.Int).SetBytes(common.Hex2Bytes(param.y)) stack.push(x) stack.push(y) - opFn(&pc, interpreter, nil, nil, stack) + opFn(&pc, interpreter, &callCtx{nil, stack, nil}) actual := stack.pop() result[i] = TwoOperandTestcase{param.x, param.y, fmt.Sprintf("%064x", actual)} } @@ -260,7 +260,7 @@ func TestJsonTestcases(t *testing.T) { } } -func opBenchmark(bench *testing.B, op func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error), args ...string) { +func opBenchmark(bench *testing.B, op executionFunc, args ...string) { var ( env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}) stack = newstack() @@ -281,7 +281,7 @@ func opBenchmark(bench *testing.B, op func(pc *uint64, interpreter *EVMInterpret a := new(big.Int).SetBytes(arg) stack.push(a) } - op(&pc, evmInterpreter, nil, nil, stack) + op(&pc, evmInterpreter, &callCtx{nil, stack, nil}) stack.pop() } poolOfIntPools.put(evmInterpreter.intPool) @@ -509,12 +509,12 @@ func TestOpMstore(t *testing.T) { pc := uint64(0) v := "abcdef00000000000000abba000000000deaf000000c0de00100000000133700" stack.pushN(new(big.Int).SetBytes(common.Hex2Bytes(v)), big.NewInt(0)) - opMstore(&pc, evmInterpreter, nil, mem, stack) + opMstore(&pc, evmInterpreter, &callCtx{mem, stack, nil}) if got := common.Bytes2Hex(mem.GetCopy(0, 32)); got != v { t.Fatalf("Mstore fail, got %v, expected %v", got, v) } stack.pushN(big.NewInt(0x1), big.NewInt(0)) - opMstore(&pc, evmInterpreter, nil, mem, stack) + opMstore(&pc, evmInterpreter, &callCtx{mem, stack, nil}) if common.Bytes2Hex(mem.GetCopy(0, 32)) != "0000000000000000000000000000000000000000000000000000000000000001" { t.Fatalf("Mstore failed to overwrite previous value") } @@ -539,7 +539,7 @@ func BenchmarkOpMstore(bench *testing.B) { bench.ResetTimer() for i := 0; i < bench.N; i++ { stack.pushN(value, memStart) - opMstore(&pc, evmInterpreter, nil, mem, stack) + opMstore(&pc, evmInterpreter, &callCtx{mem, stack, nil}) } poolOfIntPools.put(evmInterpreter.intPool) } @@ -560,7 +560,7 @@ func BenchmarkOpSHA3(bench *testing.B) { bench.ResetTimer() for i := 0; i < bench.N; i++ { stack.pushN(big.NewInt(32), start) - opSha3(&pc, evmInterpreter, nil, mem, stack) + opSha3(&pc, evmInterpreter, &callCtx{mem, stack, nil}) } poolOfIntPools.put(evmInterpreter.intPool) } diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index fe06492de..5d213acc8 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -63,6 +63,14 @@ type Interpreter interface { CanRun([]byte) bool } +// callCtx contains the things that are per-call, such as stack and memory, +// but not transients like pc and gas +type callCtx struct { + memory *Memory + stack *Stack + contract *Contract +} + // keccakState wraps sha3.state. In addition to the usual hash methods, it also supports // Read to get a variable amount of data from the hash state. Read is faster than Sum // because it doesn't copy the internal state, but also modifies the internal state. @@ -160,9 +168,14 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( } var ( - op OpCode // current opcode - mem = NewMemory() // bound memory - stack = newstack() // local stack + op OpCode // current opcode + mem = NewMemory() // bound memory + stack = newstack() // local stack + callContext = &callCtx{ + memory: mem, + stack: stack, + contract: contract, + } // For optimisation reason we're using uint64 as the program counter. // It's theoretically possible to go above 2^64. The YP defines the PC // to be uint256. Practically much less so feasible. @@ -194,7 +207,12 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( // explicit STOP, RETURN or SELFDESTRUCT is executed, an error occurred during // the execution of one of the operations or until the done flag is set by the // parent context. - for atomic.LoadInt32(&in.evm.abort) == 0 { + steps := 0 + for { + steps++ + if steps%1000 == 0 && atomic.LoadInt32(&in.evm.abort) != 0 { + break + } if in.cfg.Debug { // Capture pre-execution values for tracing. logged, pcCopy, gasCopy = false, pc, contract.Gas @@ -267,7 +285,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( } // execute the operation - res, err = operation.execute(&pc, in, contract, mem, stack) + res, err = operation.execute(&pc, in, callContext) // verifyPool is a build flag. Pool verification makes sure the integrity // of the integer pool by comparing values to a default value. if verifyPool { diff --git a/core/vm/intpool.go b/core/vm/intpool.go index 917a78d56..eed074b07 100644 --- a/core/vm/intpool.go +++ b/core/vm/intpool.go @@ -53,6 +53,17 @@ func (p *intPool) getZero() *big.Int { return new(big.Int) } +// putOne returns an allocated big int to the pool to be later reused by get calls. +// Note, the values as saved as is; neither put nor get zeroes the ints out! +// As opposed to 'put' with variadic args, this method becomes inlined by the +// go compiler +func (p *intPool) putOne(i *big.Int) { + if len(p.pool.data) > poolLimit { + return + } + p.pool.push(i) +} + // put returns an allocated big int to the pool to be later reused by get calls. // Note, the values as saved as is; neither put nor get zeroes the ints out! func (p *intPool) put(is ...*big.Int) { diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index b26b55284..c1e7c88db 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -23,7 +23,7 @@ import ( ) type ( - executionFunc func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) + executionFunc func(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) gasFunc func(*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) diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index fb07d69d0..decde46ea 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -316,3 +316,31 @@ func TestBlockhash(t *testing.T) { t.Errorf("suboptimal; too much chain iteration, expected %d, got %d", exp, got) } } + +// BenchmarkSimpleLoop test a pretty simple loop which loops +// 1M (1 048 575) times. +// Takes about 200 ms +func BenchmarkSimpleLoop(b *testing.B) { + // 0xfffff = 1048575 loops + code := []byte{ + byte(vm.PUSH3), 0x0f, 0xff, 0xff, + byte(vm.JUMPDEST), // [ count ] + byte(vm.PUSH1), 1, // [count, 1] + byte(vm.SWAP1), // [1, count] + byte(vm.SUB), // [ count -1 ] + byte(vm.DUP1), // [ count -1 , count-1] + byte(vm.PUSH1), 4, // [count-1, count -1, label] + byte(vm.JUMPI), // [ 0 ] + byte(vm.STOP), + } + //tracer := vm.NewJSONLogger(nil, os.Stdout) + //Execute(code, nil, &Config{ + // EVMConfig: vm.Config{ + // Debug: true, + // Tracer: tracer, + // }}) + + for i := 0; i < b.N; i++ { + Execute(code, nil, nil) + } +}