diff --git a/core/vm/eips.go b/core/vm/eips.go index bc52da4f8..bed0addaa 100644 --- a/core/vm/eips.go +++ b/core/vm/eips.go @@ -18,15 +18,15 @@ package vm import "github.com/core-coin/uint256" -func opSelfBalance(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - balance, _ := uint256.FromBig(interpreter.cvm.StateDB.GetBalance(contract.Address())) - stack.push(balance) +func opSelfBalance(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + balance, _ := uint256.FromBig(interpreter.cvm.StateDB.GetBalance(callContext.contract.Address())) + callContext.stack.push(balance) return nil, nil } // opNetworkID implements NETWORKID opcode -func opNetworkID(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opNetworkID(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { networkId, _ := uint256.FromBig(interpreter.cvm.chainConfig.NetworkID) - stack.push(networkId) + callContext.stack.push(networkId) return nil, nil } diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 9ad393e7a..1aa53685a 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -24,69 +24,69 @@ import ( "golang.org/x/crypto/sha3" ) -func opAdd(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.peek() +func opAdd(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + x, y := callContext.stack.pop(), callContext.stack.peek() y.Add(&x, y) return nil, nil } -func opSub(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.peek() +func opSub(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + x, y := callContext.stack.pop(), callContext.stack.peek() y.Sub(&x, y) return nil, nil } -func opMul(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.peek() +func opMul(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + x, y := callContext.stack.pop(), callContext.stack.peek() y.Mul(&x, y) return nil, nil } -func opDiv(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.peek() +func opDiv(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + x, y := callContext.stack.pop(), callContext.stack.peek() y.Div(&x, y) return nil, nil } -func opSdiv(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.peek() +func opSdiv(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + x, y := callContext.stack.pop(), callContext.stack.peek() y.SDiv(&x, y) return nil, nil } -func opMod(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.peek() +func opMod(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + x, y := callContext.stack.pop(), callContext.stack.peek() y.Mod(&x, y) return nil, nil } -func opSmod(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.peek() +func opSmod(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + x, y := callContext.stack.pop(), callContext.stack.peek() y.SMod(&x, y) return nil, nil } -func opExp(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - base, exponent := stack.pop(), stack.peek() +func opExp(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + base, exponent := callContext.stack.pop(), callContext.stack.peek() exponent.Exp(&base, exponent) return nil, nil } -func opSignExtend(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - back, num := stack.pop(), stack.peek() +func opSignExtend(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + back, num := callContext.stack.pop(), callContext.stack.peek() num.ExtendSign(num, &back) return nil, nil } -func opNot(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x := stack.peek() +func opNot(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + x := callContext.stack.peek() x.Not(x) return nil, nil } -func opLt(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.peek() +func opLt(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + x, y := callContext.stack.pop(), callContext.stack.peek() if x.Lt(y) { y.SetOne() } else { @@ -95,8 +95,8 @@ func opLt(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *M return nil, nil } -func opGt(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.peek() +func opGt(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + x, y := callContext.stack.pop(), callContext.stack.peek() if x.Gt(y) { y.SetOne() } else { @@ -105,8 +105,8 @@ func opGt(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *M return nil, nil } -func opSlt(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.peek() +func opSlt(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + x, y := callContext.stack.pop(), callContext.stack.peek() if x.Slt(y) { y.SetOne() } else { @@ -115,8 +115,8 @@ func opSlt(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory * return nil, nil } -func opSgt(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.peek() +func opSgt(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + x, y := callContext.stack.pop(), callContext.stack.peek() if x.Sgt(y) { y.SetOne() } else { @@ -125,8 +125,8 @@ func opSgt(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory * return nil, nil } -func opEq(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.peek() +func opEq(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + x, y := callContext.stack.pop(), callContext.stack.peek() if x.Eq(y) { y.SetOne() } else { @@ -135,8 +135,8 @@ func opEq(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *M return nil, nil } -func opIszero(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x := stack.peek() +func opIszero(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + x := callContext.stack.peek() if x.IsZero() { x.SetOne() } else { @@ -145,32 +145,32 @@ func opIszero(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memor return nil, nil } -func opAnd(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.peek() +func opAnd(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + x, y := callContext.stack.pop(), callContext.stack.peek() y.And(&x, y) return nil, nil } -func opOr(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.peek() +func opOr(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + x, y := callContext.stack.pop(), callContext.stack.peek() y.Or(&x, y) return nil, nil } -func opXor(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := stack.pop(), stack.peek() +func opXor(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + x, y := callContext.stack.pop(), callContext.stack.peek() y.Xor(&x, y) return nil, nil } -func opByte(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - th, val := stack.pop(), stack.peek() +func opByte(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + th, val := callContext.stack.pop(), callContext.stack.peek() val.Byte(&th) return nil, nil } -func opAddmod(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y, z := stack.pop(), stack.pop(), stack.peek() +func opAddmod(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + x, y, z := callContext.stack.pop(), callContext.stack.pop(), callContext.stack.peek() if z.IsZero() { z.Clear() } else { @@ -179,18 +179,18 @@ func opAddmod(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memor return nil, nil } -func opMulmod(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y, z := stack.pop(), stack.pop(), stack.peek() +func opMulmod(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + x, y, z := callContext.stack.pop(), callContext.stack.pop(), callContext.stack.peek() z.MulMod(&x, &y, z) return nil, nil } // 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 *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - // Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards - shift, value := stack.pop(), stack.peek() +// The SHL instruction (shift left) pops 2 values from the callContext.stack, first arg1 and then arg2, +// and pushes on the callContext.stack arg2 shifted to the left by arg1 number of bits. +func opSHL(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + // Note, second operand is left in the callContext.stack; accumulate result into it, and no need to push it afterwards + shift, value := callContext.stack.pop(), callContext.stack.peek() if shift.LtUint64(256) { value.Lsh(value, uint(shift.Uint64())) } else { @@ -201,11 +201,11 @@ func opSHL(pc *uint64, interpreter *CVMInterpreter, 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 *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - // Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards - shift, value := stack.pop(), stack.peek() +// The SHR instruction (logical shift right) pops 2 values from the callContext.stack, first arg1 and then arg2, +// and pushes on the callContext.stack arg2 shifted to the right by arg1 number of bits with zero fill. +func opSHR(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + // Note, second operand is left in the callContext.stack; accumulate result into it, and no need to push it afterwards + shift, value := callContext.stack.pop(), callContext.stack.peek() if shift.LtUint64(256) { value.Rsh(value, uint(shift.Uint64())) } else { @@ -216,11 +216,11 @@ func opSHR(pc *uint64, interpreter *CVMInterpreter, 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 *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +// The SAR instruction (arithmetic shift right) pops 2 values from the callContext.stack, first arg1 and then arg2, +// and pushes on the callContext.stack arg2 shifted to the right by arg1 number of bits with sign extension. +func opSAR(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { // Note, S256 returns (potentially) a new bigint, so we're popping, not peeking this one - shift, value := stack.pop(), stack.peek() + shift, value := callContext.stack.pop(), callContext.stack.peek() if shift.GtUint64(256) { if value.Sign() >= 0 { value.Clear() @@ -236,9 +236,9 @@ func opSAR(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory * return nil, nil } -func opSha3(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - offset, size := stack.pop(), stack.peek() - data := memory.GetPtr(int64(offset.Uint64()), int64(size.Uint64())) +func opSha3(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + offset, size := callContext.stack.pop(), callContext.stack.peek() + data := callContext.memory.GetPtr(int64(offset.Uint64()), int64(size.Uint64())) if interpreter.hasher == nil { interpreter.hasher = sha3.New256().(keccakState) @@ -256,38 +256,38 @@ func opSha3(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory return nil, nil } -func opAddress(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(new(uint256.Int).SetBytes(contract.Address().Bytes())) +func opAddress(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + callContext.stack.push(new(uint256.Int).SetBytes(callContext.contract.Address().Bytes())) return nil, nil } -func opBalance(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - slot := stack.peek() +func opBalance(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + slot := callContext.stack.peek() address := common.Address(slot.Bytes22()) slot.SetFromBig(interpreter.cvm.StateDB.GetBalance(address)) return nil, nil } -func opOrigin(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(new(uint256.Int).SetBytes(interpreter.cvm.Origin.Bytes())) +func opOrigin(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + callContext.stack.push(new(uint256.Int).SetBytes(interpreter.cvm.Origin.Bytes())) return nil, nil } -func opCaller(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(new(uint256.Int).SetBytes(contract.Caller().Bytes())) +func opCaller(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + callContext.stack.push(new(uint256.Int).SetBytes(callContext.contract.Caller().Bytes())) return nil, nil } -func opCallValue(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - v, _ := uint256.FromBig(contract.value) - stack.push(v) +func opCallValue(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + v, _ := uint256.FromBig(callContext.contract.value) + callContext.stack.push(v) return nil, nil } -func opCallDataLoad(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x := stack.peek() +func opCallDataLoad(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + x := callContext.stack.peek() if offset, overflow := x.Uint64WithOverflow(); !overflow { - data := getData(contract.Input, offset, 32) + data := getData(callContext.contract.Input, offset, 32) x.SetBytes(data) } else { x.Clear() @@ -295,16 +295,16 @@ func opCallDataLoad(pc *uint64, interpreter *CVMInterpreter, contract *Contract, return nil, nil } -func opCallDataSize(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(new(uint256.Int).SetUint64(uint64(len(contract.Input)))) +func opCallDataSize(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + callContext.stack.push(new(uint256.Int).SetUint64(uint64(len(callContext.contract.Input)))) return nil, nil } -func opCallDataCopy(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opCallDataCopy(pc *uint64, interpreter *CVMInterpreter, 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() ) dataOffset64, overflow := dataOffset.Uint64WithOverflow() if overflow { @@ -313,20 +313,20 @@ func opCallDataCopy(pc *uint64, interpreter *CVMInterpreter, contract *Contract, // These values are checked for overflow during energy cost calculation memOffset64 := memOffset.Uint64() length64 := length.Uint64() - memory.Set(memOffset64, length64, getData(contract.Input, dataOffset64, length64)) + callContext.memory.Set(memOffset64, length64, getData(callContext.contract.Input, dataOffset64, length64)) return nil, nil } -func opReturnDataSize(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(new(uint256.Int).SetUint64(uint64(len(interpreter.returnData)))) +func opReturnDataSize(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + callContext.stack.push(new(uint256.Int).SetUint64(uint64(len(interpreter.returnData)))) return nil, nil } -func opReturnDataCopy(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opReturnDataCopy(pc *uint64, interpreter *CVMInterpreter, 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() ) offset64, overflow := dataOffset.Uint64WithOverflow() @@ -340,47 +340,47 @@ func opReturnDataCopy(pc *uint64, interpreter *CVMInterpreter, contract *Contrac if overflow || uint64(len(interpreter.returnData)) < end64 { return nil, ErrReturnDataOutOfBounds } - memory.Set(memOffset.Uint64(), length.Uint64(), interpreter.returnData[offset64:end64]) + callContext.memory.Set(memOffset.Uint64(), length.Uint64(), interpreter.returnData[offset64:end64]) return nil, nil } -func opExtCodeSize(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - slot := stack.peek() +func opExtCodeSize(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + slot := callContext.stack.peek() slot.SetUint64(uint64(interpreter.cvm.StateDB.GetCodeSize(common.Address(slot.Bytes22())))) return nil, nil } -func opCodeSize(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opCodeSize(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { l := new(uint256.Int) - l.SetUint64(uint64(len(contract.Code))) - stack.push(l) + l.SetUint64(uint64(len(callContext.contract.Code))) + callContext.stack.push(l) return nil, nil } -func opCodeCopy(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opCodeCopy(pc *uint64, interpreter *CVMInterpreter, 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() ) uint64CodeOffset, overflow := codeOffset.Uint64WithOverflow() if overflow { uint64CodeOffset = 0xffffffffffffffff } - codeCopy := getData(contract.Code, uint64CodeOffset, length.Uint64()) - memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy) + codeCopy := getData(callContext.contract.Code, uint64CodeOffset, length.Uint64()) + callContext.memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy) return nil, nil } -func opExtCodeCopy(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opExtCodeCopy(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { var ( - a = stack.pop() - memOffset = stack.pop() - codeOffset = stack.pop() - length = stack.pop() + a = callContext.stack.pop() + memOffset = callContext.stack.pop() + codeOffset = callContext.stack.pop() + length = callContext.stack.pop() ) uint64CodeOffset, overflow := codeOffset.Uint64WithOverflow() if overflow { @@ -388,7 +388,7 @@ func opExtCodeCopy(pc *uint64, interpreter *CVMInterpreter, contract *Contract, } addr := common.Address(a.Bytes22()) codeCopy := getData(interpreter.cvm.StateDB.GetCode(addr), uint64CodeOffset, length.Uint64()) - memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy) + callContext.memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy) return nil, nil } @@ -396,13 +396,13 @@ func opExtCodeCopy(pc *uint64, interpreter *CVMInterpreter, contract *Contract, // opExtCodeHash returns the code hash of a specified account. // There are several cases when the function is called, while we can relay everything // to `state.GetCodeHash` function to ensure the correctness. -// (1) Caller tries to get the code hash of a normal contract account, state +// (1) Caller tries to get the code hash of a normal callContext.contract account, state // should return the relative code hash and set it as the result. // // (2) Caller tries to get the code hash of a non-existent account, state should // return common.Hash{} and zero will be set as the result. // -// (3) Caller tries to get the code hash for an account without contract code, +// (3) Caller tries to get the code hash for an account without callContext.contract code, // state should return emptyCodeHash(0xc5d246...) as the result. // // (4) Caller tries to get the code hash of a precompiled account, the result @@ -419,8 +419,8 @@ func opExtCodeCopy(pc *uint64, interpreter *CVMInterpreter, 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 *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - slot := stack.peek() +func opExtCodeHash(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + slot := callContext.stack.peek() address := common.Address(slot.Bytes22()) if interpreter.cvm.StateDB.Empty(address) { slot.Clear() @@ -430,14 +430,14 @@ func opExtCodeHash(pc *uint64, interpreter *CVMInterpreter, contract *Contract, return nil, nil } -func opEnergyprice(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opEnergyprice(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { v, _ := uint256.FromBig(interpreter.cvm.EnergyPrice) - stack.push(v) + callContext.stack.push(v) return nil, nil } -func opBlockhash(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - num := stack.peek() +func opBlockhash(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + num := callContext.stack.peek() num64, overflow := num.Uint64WithOverflow() if overflow { num.Clear() @@ -458,78 +458,78 @@ func opBlockhash(pc *uint64, interpreter *CVMInterpreter, contract *Contract, me return nil, nil } -func opCoinbase(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(new(uint256.Int).SetBytes(interpreter.cvm.Coinbase.Bytes())) +func opCoinbase(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + callContext.stack.push(new(uint256.Int).SetBytes(interpreter.cvm.Coinbase.Bytes())) return nil, nil } -func opTimestamp(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opTimestamp(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { v, _ := uint256.FromBig(interpreter.cvm.Time) - stack.push(v) + callContext.stack.push(v) return nil, nil } -func opNumber(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opNumber(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { v, _ := uint256.FromBig(interpreter.cvm.BlockNumber) - stack.push(v) + callContext.stack.push(v) return nil, nil } -func opDifficulty(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opDifficulty(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { v, _ := uint256.FromBig(interpreter.cvm.Difficulty) - stack.push(v) + callContext.stack.push(v) return nil, nil } -func opEnergyLimit(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(new(uint256.Int).SetUint64(interpreter.cvm.EnergyLimit)) +func opEnergyLimit(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + callContext.stack.push(new(uint256.Int).SetUint64(interpreter.cvm.EnergyLimit)) return nil, nil } -func opPop(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.pop() +func opPop(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + callContext.stack.pop() return nil, nil } -func opMload(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - v := stack.peek() +func opMload(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + v := callContext.stack.peek() offset := int64(v.Uint64()) - v.SetBytes(memory.GetPtr(offset, 32)) + v.SetBytes(callContext.memory.GetPtr(offset, 32)) return nil, nil } -func opMstore(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - // pop value of the stack - mStart, val := stack.pop(), stack.pop() - memory.Set32(mStart.Uint64(), &val) +func opMstore(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + // pop value of the callContext.stack + mStart, val := callContext.stack.pop(), callContext.stack.pop() + callContext.memory.Set32(mStart.Uint64(), &val) return nil, nil } -func opMstore8(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - off, val := stack.pop(), stack.pop() - memory.store[off.Uint64()] = byte(val.Uint64()) +func opMstore8(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + off, val := callContext.stack.pop(), callContext.stack.pop() + callContext.memory.store[off.Uint64()] = byte(val.Uint64()) return nil, nil } -func opSload(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - loc := stack.peek() +func opSload(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + loc := callContext.stack.peek() hash := common.Hash(loc.Bytes32()) - val := interpreter.cvm.StateDB.GetState(contract.Address(), hash) + val := interpreter.cvm.StateDB.GetState(callContext.contract.Address(), hash) loc.SetBytes(val.Bytes()) return nil, nil } -func opSstore(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - loc := stack.pop() - val := stack.pop() - interpreter.cvm.StateDB.SetState(contract.Address(), +func opSstore(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + loc := callContext.stack.pop() + val := callContext.stack.pop() + interpreter.cvm.StateDB.SetState(callContext.contract.Address(), common.Hash(loc.Bytes32()), common.Hash(val.Bytes32())) return nil, nil } -func opJump(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - pos := stack.pop() - if !contract.validJumpdest(&pos) { +func opJump(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + pos := callContext.stack.pop() + if !callContext.contract.validJumpdest(&pos) { return nil, ErrInvalidJump } *pc = pos.Uint64() @@ -537,10 +537,10 @@ func opJump(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory return nil, nil } -func opJumpi(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - pos, cond := stack.pop(), stack.pop() +func opJumpi(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + pos, cond := callContext.stack.pop(), callContext.stack.pop() if !cond.IsZero() { - if !contract.validJumpdest(&pos) { + if !callContext.contract.validJumpdest(&pos) { return nil, ErrInvalidJump } *pc = pos.Uint64() @@ -551,40 +551,40 @@ func opJumpi(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory return nil, nil } -func opJumpdest(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opJumpdest(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { return nil, nil } -func opPc(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(new(uint256.Int).SetUint64(*pc)) +func opPc(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + callContext.stack.push(new(uint256.Int).SetUint64(*pc)) return nil, nil } -func opMsize(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(new(uint256.Int).SetUint64(uint64(memory.Len()))) +func opMsize(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + callContext.stack.push(new(uint256.Int).SetUint64(uint64(callContext.memory.Len()))) return nil, nil } -func opEnergy(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(new(uint256.Int).SetUint64(contract.Energy)) +func opEnergy(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + callContext.stack.push(new(uint256.Int).SetUint64(callContext.contract.Energy)) return nil, nil } -func opCreate(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opCreate(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { var ( - value = stack.pop() - offset, size = stack.pop(), stack.pop() - input = memory.GetCopy(int64(offset.Uint64()), int64(size.Uint64())) - energy = contract.Energy + value = callContext.stack.pop() + offset, size = callContext.stack.pop(), callContext.stack.pop() + input = callContext.memory.GetCopy(int64(offset.Uint64()), int64(size.Uint64())) + energy = callContext.contract.Energy ) energy -= energy / 64 - // reuse size int for stackvalue + // reuse size int for callContext.stackvalue stackvalue := size - contract.UseEnergy(energy) - res, addr, returnEnergy, suberr := interpreter.cvm.Create(contract, input, energy, value.ToBig()) - // Push item on the stack based on the returned error. We must + callContext.contract.UseEnergy(energy) + res, addr, returnEnergy, suberr := interpreter.cvm.Create(callContext.contract, input, energy, value.ToBig()) + // Push item on the callContext.stack based on the returned error. We must // ignore this error and pretend the operation was successful. if suberr == ErrCodeStoreOutOfEnergy { stackvalue.Clear() @@ -593,8 +593,8 @@ func opCreate(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memor } else { stackvalue.SetBytes(addr.Bytes()) } - stack.push(&stackvalue) - contract.Energy += returnEnergy + callContext.stack.push(&stackvalue) + callContext.contract.Energy += returnEnergy if suberr == ErrExecutionReverted { return res, nil @@ -602,30 +602,30 @@ func opCreate(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memor return nil, nil } -func opCreate2(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opCreate2(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { var ( - endowment = stack.pop() - offset, size = stack.pop(), stack.pop() - salt = stack.pop() - input = memory.GetCopy(int64(offset.Uint64()), int64(size.Uint64())) - energy = contract.Energy + endowment = callContext.stack.pop() + offset, size = callContext.stack.pop(), callContext.stack.pop() + salt = callContext.stack.pop() + input = callContext.memory.GetCopy(int64(offset.Uint64()), int64(size.Uint64())) + energy = callContext.contract.Energy ) // Apply CIP150 energy -= energy / 64 - contract.UseEnergy(energy) - // reuse size int for stackvalue + callContext.contract.UseEnergy(energy) + // reuse size int for callContext.stackvalue stackvalue := size - res, addr, returnEnergy, suberr := interpreter.cvm.Create2(contract, input, energy, + res, addr, returnEnergy, suberr := interpreter.cvm.Create2(callContext.contract, input, energy, endowment.ToBig(), salt.ToBig()) - // Push item on the stack based on the returned error. + // Push item on the callContext.stack based on the returned error. if suberr != nil { stackvalue.Clear() } else { stackvalue.SetBytes(addr.Bytes()) } - stack.push(&stackvalue) - contract.Energy += returnEnergy + callContext.stack.push(&stackvalue) + callContext.contract.Energy += returnEnergy if suberr == ErrExecutionReverted { return res, nil @@ -633,134 +633,134 @@ func opCreate2(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memo return nil, nil } -func opCall(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opCall(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { // Pop energy. The actual energy in interpreter.cvm.callEnergyTemp. // We can use this as a temporary value - temp := stack.pop() + temp := callContext.stack.pop() energy := interpreter.cvm.callEnergyTemp // 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.Address(addr.Bytes22()) - // Get the arguments from the memory. - args := memory.GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64())) + // Get the arguments from the callContext.memory. + args := callContext.memory.GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64())) if !value.IsZero() { energy += params.CallStipend } - ret, returnEnergy, err := interpreter.cvm.Call(contract, toAddr, args, energy, value.ToBig()) + ret, returnEnergy, err := interpreter.cvm.Call(callContext.contract, toAddr, args, energy, value.ToBig()) if err != nil { temp.Clear() } else { temp.SetOne() } - stack.push(&temp) + callContext.stack.push(&temp) if err == nil || err == ErrExecutionReverted { - memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) + callContext.memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } - contract.Energy += returnEnergy + callContext.contract.Energy += returnEnergy return ret, nil } -func opCallCode(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opCallCode(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { // Pop energy. The actual energy is in interpreter.cvm.callEnergyTemp. // We use it as a temporary value - temp := stack.pop() + temp := callContext.stack.pop() energy := interpreter.cvm.callEnergyTemp // 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.Address(addr.Bytes22()) - // Get arguments from the memory. - args := memory.GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64())) + // Get arguments from the callContext.memory. + args := callContext.memory.GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64())) if !value.IsZero() { energy += params.CallStipend } - ret, returnEnergy, err := interpreter.cvm.CallCode(contract, toAddr, args, energy, value.ToBig()) + ret, returnEnergy, err := interpreter.cvm.CallCode(callContext.contract, toAddr, args, energy, value.ToBig()) if err != nil { temp.Clear() } else { temp.SetOne() } - stack.push(&temp) + callContext.stack.push(&temp) if err == nil || err == ErrExecutionReverted { - memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) + callContext.memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } - contract.Energy += returnEnergy + callContext.contract.Energy += returnEnergy return ret, nil } -func opDelegateCall(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opDelegateCall(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { // Pop energy. The actual energy is in interpreter.cvm.callEnergyTemp. // We use it as a temporary value - temp := stack.pop() + temp := callContext.stack.pop() energy := interpreter.cvm.callEnergyTemp // 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.Address(addr.Bytes22()) - // Get arguments from the memory. - args := memory.GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64())) + // Get arguments from the callContext.memory. + args := callContext.memory.GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64())) - ret, returnEnergy, err := interpreter.cvm.DelegateCall(contract, toAddr, args, energy) + ret, returnEnergy, err := interpreter.cvm.DelegateCall(callContext.contract, toAddr, args, energy) if err != nil { temp.Clear() } else { temp.SetOne() } - stack.push(&temp) + callContext.stack.push(&temp) if err == nil || err == ErrExecutionReverted { - memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) + callContext.memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } - contract.Energy += returnEnergy + callContext.contract.Energy += returnEnergy return ret, nil } -func opStaticCall(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opStaticCall(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { // Pop energy. The actual energy is in interpreter.cvm.callEnergyTemp. // We use it as a temporary value - temp := stack.pop() + temp := callContext.stack.pop() energy := interpreter.cvm.callEnergyTemp // 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.Address(addr.Bytes22()) - // Get arguments from the memory. - args := memory.GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64())) + // Get arguments from the callContext.memory. + args := callContext.memory.GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64())) - ret, returnEnergy, err := interpreter.cvm.StaticCall(contract, toAddr, args, energy) + ret, returnEnergy, err := interpreter.cvm.StaticCall(callContext.contract, toAddr, args, energy) if err != nil { temp.Clear() } else { temp.SetOne() } - stack.push(&temp) + callContext.stack.push(&temp) if err == nil || err == ErrExecutionReverted { - memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) + callContext.memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } - contract.Energy += returnEnergy + callContext.contract.Energy += returnEnergy return ret, nil } -func opReturn(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - offset, size := stack.pop(), stack.pop() - ret := memory.GetPtr(int64(offset.Uint64()), int64(size.Uint64())) +func opReturn(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + offset, size := callContext.stack.pop(), callContext.stack.pop() + ret := callContext.memory.GetPtr(int64(offset.Uint64()), int64(size.Uint64())) return ret, nil } -func opRevert(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - offset, size := stack.pop(), stack.pop() - ret := memory.GetPtr(int64(offset.Uint64()), int64(size.Uint64())) +func opRevert(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + offset, size := callContext.stack.pop(), callContext.stack.pop() + ret := callContext.memory.GetPtr(int64(offset.Uint64()), int64(size.Uint64())) return ret, nil } -func opStop(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opStop(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { return nil, nil } -func opSuicide(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - beneficiary := stack.pop() - balance := interpreter.cvm.StateDB.GetBalance(contract.Address()) +func opSuicide(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + beneficiary := callContext.stack.pop() + balance := interpreter.cvm.StateDB.GetBalance(callContext.contract.Address()) interpreter.cvm.StateDB.AddBalance(common.Address(beneficiary.Bytes22()), balance) - interpreter.cvm.StateDB.Suicide(contract.Address()) + interpreter.cvm.StateDB.Suicide(callContext.contract.Address()) return nil, nil } @@ -768,17 +768,17 @@ func opSuicide(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memo // make log instruction function func makeLog(size int) executionFunc { - return func(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + return func(pc *uint64, interpreter *CVMInterpreter, 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++ { - addr := stack.pop() + addr := callContext.stack.pop() topics[i] = common.Hash(addr.Bytes32()) } - d := memory.GetCopy(int64(mStart.Uint64()), int64(mSize.Uint64())) + d := callContext.memory.GetCopy(int64(mStart.Uint64()), int64(mSize.Uint64())) interpreter.cvm.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 @@ -791,24 +791,24 @@ func makeLog(size int) executionFunc { } // opPush1 is a specialized version of pushN -func opPush1(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opPush1(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { var ( - codeLen = uint64(len(contract.Code)) + codeLen = uint64(len(callContext.contract.Code)) integer = new(uint256.Int) ) *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.Clear()) + callContext.stack.push(integer.Clear()) } return nil, nil } // make push instruction function func makePush(size uint64, pushByteSize int) executionFunc { - return func(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - codeLen := len(contract.Code) + return func(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + codeLen := len(callContext.contract.Code) startMin := codeLen if int(*pc+1) < startMin { @@ -821,8 +821,8 @@ func makePush(size uint64, pushByteSize int) executionFunc { } integer := new(uint256.Int) - 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 @@ -831,8 +831,8 @@ func makePush(size uint64, pushByteSize int) executionFunc { // make dup instruction function func makeDup(size int64) executionFunc { - return func(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.dup(int(size)) + return func(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) { + callContext.stack.dup(int(size)) return nil, nil } } @@ -841,8 +841,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 *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.swap(int(size)) + return func(pc *uint64, interpreter *CVMInterpreter, 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 04364bbc1..58d279521 100644 --- a/core/vm/instructions_test.go +++ b/core/vm/instructions_test.go @@ -103,7 +103,7 @@ func testTwoOperandOp(t *testing.T, tests []TwoOperandTestcase, opFn executionFu expected := new(uint256.Int).SetBytes(common.Hex2Bytes(test.Expected)) stack.push(x) stack.push(y) - opFn(&pc, cvmInterpreter, nil, nil, stack) + opFn(&pc, cvmInterpreter, &callCtx{nil, stack, nil}) if len(stack.data) != 1 { t.Errorf("Expected one item on stack after %v, got %d: ", name, len(stack.data)) } @@ -176,7 +176,7 @@ func TestAddMod(t *testing.T) { stack.push(z) stack.push(y) stack.push(x) - opAddmod(&pc, cvmInterpreter, nil, nil, stack) + opAddmod(&pc, cvmInterpreter, &callCtx{nil, stack, nil}) actual := stack.pop() if actual.Cmp(expected) != 0 { t.Errorf("Testcase %d, expected %x, got %x", i, expected, actual) @@ -240,7 +240,7 @@ func getResult(args []*twoOperandParams, opFn executionFunc) []TwoOperandTestcas y := new(uint256.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)} } @@ -277,7 +277,7 @@ func TestJsonTestcases(t *testing.T) { } } -func opBenchmark(bench *testing.B, op func(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error), args ...string) { +func opBenchmark(bench *testing.B, op executionFunc, args ...string) { var ( env = NewCVM(Context{}, nil, params.TestChainConfig, Config{}) stack = newstack() @@ -297,7 +297,7 @@ func opBenchmark(bench *testing.B, op func(pc *uint64, interpreter *CVMInterpret a := new(uint256.Int) a.SetBytes(arg) } - op(&pc, cvmInterpreter, nil, nil, stack) + op(&pc, cvmInterpreter, &callCtx{nil, stack, nil}) stack.pop() } } @@ -523,12 +523,12 @@ func TestOpMstore(t *testing.T) { pc := uint64(0) v := "abcdef00000000000000abba000000000deaf000000c0de00100000000133700" stack.pushN(*new(uint256.Int).SetBytes(common.Hex2Bytes(v)), *new(uint256.Int)) - opMstore(&pc, cvmInterpreter, nil, mem, stack) + opMstore(&pc, cvmInterpreter, &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(*new(uint256.Int).SetUint64(0x1), *new(uint256.Int)) - opMstore(&pc, cvmInterpreter, nil, mem, stack) + opMstore(&pc, cvmInterpreter, &callCtx{mem, stack, nil}) if common.Bytes2Hex(mem.GetCopy(0, 32)) != "0000000000000000000000000000000000000000000000000000000000000001" { t.Fatalf("Mstore failed to overwrite previous value") } @@ -551,7 +551,7 @@ func BenchmarkOpMstore(bench *testing.B) { bench.ResetTimer() for i := 0; i < bench.N; i++ { stack.pushN(*value, *memStart) - opMstore(&pc, cvmInterpreter, nil, mem, stack) + opMstore(&pc, cvmInterpreter, &callCtx{mem, stack, nil}) } } @@ -570,7 +570,7 @@ func BenchmarkOpSHA3(bench *testing.B) { bench.ResetTimer() for i := 0; i < bench.N; i++ { stack.pushN(*uint256.NewInt(32), *start) - opSha3(&pc, cvmInterpreter, nil, mem, stack) + opSha3(&pc, cvmInterpreter, &callCtx{mem, stack, nil}) } } diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 3a61854fd..b5c0bc2e3 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -61,6 +61,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 energy +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. @@ -129,9 +137,14 @@ func (in *CVMInterpreter) 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. @@ -160,7 +173,12 @@ func (in *CVMInterpreter) 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.cvm.abort) == 0 { + steps := 0 + for { + steps++ + if steps%1000 == 0 && atomic.LoadInt32(&in.cvm.abort) != 0 { + break + } if in.cfg.Debug { // Capture pre-execution values for tracing. logged, pcCopy, energyCopy = false, pc, contract.Energy @@ -233,7 +251,7 @@ func (in *CVMInterpreter) 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) // if the operation clears the return data (e.g. it has returning data) // set the last return to the result of the operation. if operation.returns { diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index 1a05e2c98..7a0e365e4 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -21,7 +21,7 @@ import ( ) type ( - executionFunc func(pc *uint64, interpreter *CVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) + executionFunc func(pc *uint64, interpreter *CVMInterpreter, callContext *callCtx) ([]byte, error) energyFunc func(*CVM, *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 303ad4a77..7f1d07cf9 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{ + // CVMConfig: vm.Config{ + // Debug: true, + // Tracer: tracer, + // }}) + + for i := 0; i < b.N; i++ { + Execute(code, nil, nil) + } +}