forked from cerc-io/plugeth
eth/tracers, core: use scopecontext in tracers, provide statedb in capturestart (#22333)
Fixes the CaptureStart api to include the EVM, thus being able to set the statedb early on. This pr also exposes the struct we used internally in the interpreter to encapsulate the contract, mem, stack, rstack, so we pass it as a single struct to the tracer, and removes the error returns on the capture methods.
This commit is contained in:
parent
c5df05b9a9
commit
0fda25e471
@ -76,9 +76,9 @@ func enable1884(jt *JumpTable) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSelfBalance(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opSelfBalance(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
balance, _ := uint256.FromBig(interpreter.evm.StateDB.GetBalance(callContext.contract.Address()))
|
balance, _ := uint256.FromBig(interpreter.evm.StateDB.GetBalance(scope.Contract.Address()))
|
||||||
callContext.stack.push(balance)
|
scope.Stack.push(balance)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,9 +95,9 @@ func enable1344(jt *JumpTable) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// opChainID implements CHAINID opcode
|
// opChainID implements CHAINID opcode
|
||||||
func opChainID(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opChainID(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
chainId, _ := uint256.FromBig(interpreter.evm.chainConfig.ChainID)
|
chainId, _ := uint256.FromBig(interpreter.evm.chainConfig.ChainID)
|
||||||
callContext.stack.push(chainId)
|
scope.Stack.push(chainId)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,7 +239,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
|
|||||||
if !isPrecompile && evm.chainRules.IsEIP158 && value.Sign() == 0 {
|
if !isPrecompile && evm.chainRules.IsEIP158 && value.Sign() == 0 {
|
||||||
// Calling a non existing account, don't do anything, but ping the tracer
|
// Calling a non existing account, don't do anything, but ping the tracer
|
||||||
if evm.vmConfig.Debug && evm.depth == 0 {
|
if evm.vmConfig.Debug && evm.depth == 0 {
|
||||||
evm.vmConfig.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value)
|
evm.vmConfig.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value)
|
||||||
evm.vmConfig.Tracer.CaptureEnd(ret, 0, 0, nil)
|
evm.vmConfig.Tracer.CaptureEnd(ret, 0, 0, nil)
|
||||||
}
|
}
|
||||||
return nil, gas, nil
|
return nil, gas, nil
|
||||||
@ -250,7 +250,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
|
|||||||
|
|
||||||
// Capture the tracer start/end events in debug mode
|
// Capture the tracer start/end events in debug mode
|
||||||
if evm.vmConfig.Debug && evm.depth == 0 {
|
if evm.vmConfig.Debug && evm.depth == 0 {
|
||||||
evm.vmConfig.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value)
|
evm.vmConfig.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value)
|
||||||
defer func(startGas uint64, startTime time.Time) { // Lazy evaluation of the parameters
|
defer func(startGas uint64, startTime time.Time) { // Lazy evaluation of the parameters
|
||||||
evm.vmConfig.Tracer.CaptureEnd(ret, startGas-gas, time.Since(startTime), err)
|
evm.vmConfig.Tracer.CaptureEnd(ret, startGas-gas, time.Since(startTime), err)
|
||||||
}(gas, time.Now())
|
}(gas, time.Now())
|
||||||
@ -472,7 +472,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if evm.vmConfig.Debug && evm.depth == 0 {
|
if evm.vmConfig.Debug && evm.depth == 0 {
|
||||||
evm.vmConfig.Tracer.CaptureStart(caller.Address(), address, true, codeAndHash.code, gas, value)
|
evm.vmConfig.Tracer.CaptureStart(evm, caller.Address(), address, true, codeAndHash.code, gas, value)
|
||||||
}
|
}
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
|
||||||
|
@ -24,68 +24,68 @@ import (
|
|||||||
"golang.org/x/crypto/sha3"
|
"golang.org/x/crypto/sha3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func opAdd(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opAdd(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
x, y := callContext.stack.pop(), callContext.stack.peek()
|
x, y := scope.Stack.pop(), scope.Stack.peek()
|
||||||
y.Add(&x, y)
|
y.Add(&x, y)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSub(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opSub(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
x, y := callContext.stack.pop(), callContext.stack.peek()
|
x, y := scope.Stack.pop(), scope.Stack.peek()
|
||||||
y.Sub(&x, y)
|
y.Sub(&x, y)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opMul(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opMul(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
x, y := callContext.stack.pop(), callContext.stack.peek()
|
x, y := scope.Stack.pop(), scope.Stack.peek()
|
||||||
y.Mul(&x, y)
|
y.Mul(&x, y)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opDiv(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opDiv(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
x, y := callContext.stack.pop(), callContext.stack.peek()
|
x, y := scope.Stack.pop(), scope.Stack.peek()
|
||||||
y.Div(&x, y)
|
y.Div(&x, y)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSdiv(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opSdiv(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
x, y := callContext.stack.pop(), callContext.stack.peek()
|
x, y := scope.Stack.pop(), scope.Stack.peek()
|
||||||
y.SDiv(&x, y)
|
y.SDiv(&x, y)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opMod(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opMod(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
x, y := callContext.stack.pop(), callContext.stack.peek()
|
x, y := scope.Stack.pop(), scope.Stack.peek()
|
||||||
y.Mod(&x, y)
|
y.Mod(&x, y)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSmod(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opSmod(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
x, y := callContext.stack.pop(), callContext.stack.peek()
|
x, y := scope.Stack.pop(), scope.Stack.peek()
|
||||||
y.SMod(&x, y)
|
y.SMod(&x, y)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opExp(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opExp(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
base, exponent := callContext.stack.pop(), callContext.stack.peek()
|
base, exponent := scope.Stack.pop(), scope.Stack.peek()
|
||||||
exponent.Exp(&base, exponent)
|
exponent.Exp(&base, exponent)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSignExtend(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opSignExtend(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
back, num := callContext.stack.pop(), callContext.stack.peek()
|
back, num := scope.Stack.pop(), scope.Stack.peek()
|
||||||
num.ExtendSign(num, &back)
|
num.ExtendSign(num, &back)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opNot(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opNot(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
x := callContext.stack.peek()
|
x := scope.Stack.peek()
|
||||||
x.Not(x)
|
x.Not(x)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opLt(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opLt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
x, y := callContext.stack.pop(), callContext.stack.peek()
|
x, y := scope.Stack.pop(), scope.Stack.peek()
|
||||||
if x.Lt(y) {
|
if x.Lt(y) {
|
||||||
y.SetOne()
|
y.SetOne()
|
||||||
} else {
|
} else {
|
||||||
@ -94,8 +94,8 @@ func opLt(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opGt(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opGt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
x, y := callContext.stack.pop(), callContext.stack.peek()
|
x, y := scope.Stack.pop(), scope.Stack.peek()
|
||||||
if x.Gt(y) {
|
if x.Gt(y) {
|
||||||
y.SetOne()
|
y.SetOne()
|
||||||
} else {
|
} else {
|
||||||
@ -104,8 +104,8 @@ func opGt(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSlt(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opSlt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
x, y := callContext.stack.pop(), callContext.stack.peek()
|
x, y := scope.Stack.pop(), scope.Stack.peek()
|
||||||
if x.Slt(y) {
|
if x.Slt(y) {
|
||||||
y.SetOne()
|
y.SetOne()
|
||||||
} else {
|
} else {
|
||||||
@ -114,8 +114,8 @@ func opSlt(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byt
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSgt(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opSgt(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
x, y := callContext.stack.pop(), callContext.stack.peek()
|
x, y := scope.Stack.pop(), scope.Stack.peek()
|
||||||
if x.Sgt(y) {
|
if x.Sgt(y) {
|
||||||
y.SetOne()
|
y.SetOne()
|
||||||
} else {
|
} else {
|
||||||
@ -124,8 +124,8 @@ func opSgt(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byt
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opEq(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opEq(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
x, y := callContext.stack.pop(), callContext.stack.peek()
|
x, y := scope.Stack.pop(), scope.Stack.peek()
|
||||||
if x.Eq(y) {
|
if x.Eq(y) {
|
||||||
y.SetOne()
|
y.SetOne()
|
||||||
} else {
|
} else {
|
||||||
@ -134,8 +134,8 @@ func opEq(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opIszero(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opIszero(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
x := callContext.stack.peek()
|
x := scope.Stack.peek()
|
||||||
if x.IsZero() {
|
if x.IsZero() {
|
||||||
x.SetOne()
|
x.SetOne()
|
||||||
} else {
|
} else {
|
||||||
@ -144,32 +144,32 @@ func opIszero(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opAnd(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opAnd(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
x, y := callContext.stack.pop(), callContext.stack.peek()
|
x, y := scope.Stack.pop(), scope.Stack.peek()
|
||||||
y.And(&x, y)
|
y.And(&x, y)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opOr(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opOr(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
x, y := callContext.stack.pop(), callContext.stack.peek()
|
x, y := scope.Stack.pop(), scope.Stack.peek()
|
||||||
y.Or(&x, y)
|
y.Or(&x, y)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opXor(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opXor(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
x, y := callContext.stack.pop(), callContext.stack.peek()
|
x, y := scope.Stack.pop(), scope.Stack.peek()
|
||||||
y.Xor(&x, y)
|
y.Xor(&x, y)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opByte(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opByte(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
th, val := callContext.stack.pop(), callContext.stack.peek()
|
th, val := scope.Stack.pop(), scope.Stack.peek()
|
||||||
val.Byte(&th)
|
val.Byte(&th)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opAddmod(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opAddmod(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
x, y, z := callContext.stack.pop(), callContext.stack.pop(), callContext.stack.peek()
|
x, y, z := scope.Stack.pop(), scope.Stack.pop(), scope.Stack.peek()
|
||||||
if z.IsZero() {
|
if z.IsZero() {
|
||||||
z.Clear()
|
z.Clear()
|
||||||
} else {
|
} else {
|
||||||
@ -178,8 +178,8 @@ func opAddmod(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opMulmod(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opMulmod(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
x, y, z := callContext.stack.pop(), callContext.stack.pop(), callContext.stack.peek()
|
x, y, z := scope.Stack.pop(), scope.Stack.pop(), scope.Stack.peek()
|
||||||
z.MulMod(&x, &y, z)
|
z.MulMod(&x, &y, z)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
@ -187,9 +187,9 @@ func opMulmod(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]
|
|||||||
// opSHL implements Shift Left
|
// opSHL implements Shift Left
|
||||||
// The SHL instruction (shift left) pops 2 values from the stack, first arg1 and then arg2,
|
// 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.
|
// and pushes on the stack arg2 shifted to the left by arg1 number of bits.
|
||||||
func opSHL(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opSHL(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
// Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards
|
// Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards
|
||||||
shift, value := callContext.stack.pop(), callContext.stack.peek()
|
shift, value := scope.Stack.pop(), scope.Stack.peek()
|
||||||
if shift.LtUint64(256) {
|
if shift.LtUint64(256) {
|
||||||
value.Lsh(value, uint(shift.Uint64()))
|
value.Lsh(value, uint(shift.Uint64()))
|
||||||
} else {
|
} else {
|
||||||
@ -201,9 +201,9 @@ func opSHL(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byt
|
|||||||
// opSHR implements Logical Shift Right
|
// opSHR implements Logical Shift Right
|
||||||
// The SHR instruction (logical shift right) pops 2 values from the stack, first arg1 and then arg2,
|
// 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.
|
// and pushes on the stack arg2 shifted to the right by arg1 number of bits with zero fill.
|
||||||
func opSHR(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opSHR(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
// Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards
|
// Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards
|
||||||
shift, value := callContext.stack.pop(), callContext.stack.peek()
|
shift, value := scope.Stack.pop(), scope.Stack.peek()
|
||||||
if shift.LtUint64(256) {
|
if shift.LtUint64(256) {
|
||||||
value.Rsh(value, uint(shift.Uint64()))
|
value.Rsh(value, uint(shift.Uint64()))
|
||||||
} else {
|
} else {
|
||||||
@ -215,8 +215,8 @@ func opSHR(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byt
|
|||||||
// opSAR implements Arithmetic Shift Right
|
// opSAR implements Arithmetic Shift Right
|
||||||
// The SAR instruction (arithmetic shift right) pops 2 values from the stack, first arg1 and then arg2,
|
// 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.
|
// and pushes on the stack arg2 shifted to the right by arg1 number of bits with sign extension.
|
||||||
func opSAR(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opSAR(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
shift, value := callContext.stack.pop(), callContext.stack.peek()
|
shift, value := scope.Stack.pop(), scope.Stack.peek()
|
||||||
if shift.GtUint64(256) {
|
if shift.GtUint64(256) {
|
||||||
if value.Sign() >= 0 {
|
if value.Sign() >= 0 {
|
||||||
value.Clear()
|
value.Clear()
|
||||||
@ -231,9 +231,9 @@ func opSAR(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byt
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSha3(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opSha3(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
offset, size := callContext.stack.pop(), callContext.stack.peek()
|
offset, size := scope.Stack.pop(), scope.Stack.peek()
|
||||||
data := callContext.memory.GetPtr(int64(offset.Uint64()), int64(size.Uint64()))
|
data := scope.Memory.GetPtr(int64(offset.Uint64()), int64(size.Uint64()))
|
||||||
|
|
||||||
if interpreter.hasher == nil {
|
if interpreter.hasher == nil {
|
||||||
interpreter.hasher = sha3.NewLegacyKeccak256().(keccakState)
|
interpreter.hasher = sha3.NewLegacyKeccak256().(keccakState)
|
||||||
@ -251,37 +251,37 @@ func opSha3(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]by
|
|||||||
size.SetBytes(interpreter.hasherBuf[:])
|
size.SetBytes(interpreter.hasherBuf[:])
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
func opAddress(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opAddress(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
callContext.stack.push(new(uint256.Int).SetBytes(callContext.contract.Address().Bytes()))
|
scope.Stack.push(new(uint256.Int).SetBytes(scope.Contract.Address().Bytes()))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opBalance(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opBalance(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
slot := callContext.stack.peek()
|
slot := scope.Stack.peek()
|
||||||
address := common.Address(slot.Bytes20())
|
address := common.Address(slot.Bytes20())
|
||||||
slot.SetFromBig(interpreter.evm.StateDB.GetBalance(address))
|
slot.SetFromBig(interpreter.evm.StateDB.GetBalance(address))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opOrigin(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opOrigin(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
callContext.stack.push(new(uint256.Int).SetBytes(interpreter.evm.Origin.Bytes()))
|
scope.Stack.push(new(uint256.Int).SetBytes(interpreter.evm.Origin.Bytes()))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
func opCaller(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opCaller(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
callContext.stack.push(new(uint256.Int).SetBytes(callContext.contract.Caller().Bytes()))
|
scope.Stack.push(new(uint256.Int).SetBytes(scope.Contract.Caller().Bytes()))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opCallValue(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opCallValue(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
v, _ := uint256.FromBig(callContext.contract.value)
|
v, _ := uint256.FromBig(scope.Contract.value)
|
||||||
callContext.stack.push(v)
|
scope.Stack.push(v)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opCallDataLoad(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opCallDataLoad(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
x := callContext.stack.peek()
|
x := scope.Stack.peek()
|
||||||
if offset, overflow := x.Uint64WithOverflow(); !overflow {
|
if offset, overflow := x.Uint64WithOverflow(); !overflow {
|
||||||
data := getData(callContext.contract.Input, offset, 32)
|
data := getData(scope.Contract.Input, offset, 32)
|
||||||
x.SetBytes(data)
|
x.SetBytes(data)
|
||||||
} else {
|
} else {
|
||||||
x.Clear()
|
x.Clear()
|
||||||
@ -289,16 +289,16 @@ func opCallDataLoad(pc *uint64, interpreter *EVMInterpreter, callContext *callCt
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opCallDataSize(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opCallDataSize(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
callContext.stack.push(new(uint256.Int).SetUint64(uint64(len(callContext.contract.Input))))
|
scope.Stack.push(new(uint256.Int).SetUint64(uint64(len(scope.Contract.Input))))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opCallDataCopy(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opCallDataCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
var (
|
var (
|
||||||
memOffset = callContext.stack.pop()
|
memOffset = scope.Stack.pop()
|
||||||
dataOffset = callContext.stack.pop()
|
dataOffset = scope.Stack.pop()
|
||||||
length = callContext.stack.pop()
|
length = scope.Stack.pop()
|
||||||
)
|
)
|
||||||
dataOffset64, overflow := dataOffset.Uint64WithOverflow()
|
dataOffset64, overflow := dataOffset.Uint64WithOverflow()
|
||||||
if overflow {
|
if overflow {
|
||||||
@ -307,21 +307,21 @@ func opCallDataCopy(pc *uint64, interpreter *EVMInterpreter, callContext *callCt
|
|||||||
// These values are checked for overflow during gas cost calculation
|
// These values are checked for overflow during gas cost calculation
|
||||||
memOffset64 := memOffset.Uint64()
|
memOffset64 := memOffset.Uint64()
|
||||||
length64 := length.Uint64()
|
length64 := length.Uint64()
|
||||||
callContext.memory.Set(memOffset64, length64, getData(callContext.contract.Input, dataOffset64, length64))
|
scope.Memory.Set(memOffset64, length64, getData(scope.Contract.Input, dataOffset64, length64))
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opReturnDataSize(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opReturnDataSize(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
callContext.stack.push(new(uint256.Int).SetUint64(uint64(len(interpreter.returnData))))
|
scope.Stack.push(new(uint256.Int).SetUint64(uint64(len(interpreter.returnData))))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
var (
|
var (
|
||||||
memOffset = callContext.stack.pop()
|
memOffset = scope.Stack.pop()
|
||||||
dataOffset = callContext.stack.pop()
|
dataOffset = scope.Stack.pop()
|
||||||
length = callContext.stack.pop()
|
length = scope.Stack.pop()
|
||||||
)
|
)
|
||||||
|
|
||||||
offset64, overflow := dataOffset.Uint64WithOverflow()
|
offset64, overflow := dataOffset.Uint64WithOverflow()
|
||||||
@ -335,42 +335,42 @@ func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, callContext *call
|
|||||||
if overflow || uint64(len(interpreter.returnData)) < end64 {
|
if overflow || uint64(len(interpreter.returnData)) < end64 {
|
||||||
return nil, ErrReturnDataOutOfBounds
|
return nil, ErrReturnDataOutOfBounds
|
||||||
}
|
}
|
||||||
callContext.memory.Set(memOffset.Uint64(), length.Uint64(), interpreter.returnData[offset64:end64])
|
scope.Memory.Set(memOffset.Uint64(), length.Uint64(), interpreter.returnData[offset64:end64])
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opExtCodeSize(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opExtCodeSize(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
slot := callContext.stack.peek()
|
slot := scope.Stack.peek()
|
||||||
slot.SetUint64(uint64(interpreter.evm.StateDB.GetCodeSize(slot.Bytes20())))
|
slot.SetUint64(uint64(interpreter.evm.StateDB.GetCodeSize(slot.Bytes20())))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opCodeSize(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opCodeSize(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
l := new(uint256.Int)
|
l := new(uint256.Int)
|
||||||
l.SetUint64(uint64(len(callContext.contract.Code)))
|
l.SetUint64(uint64(len(scope.Contract.Code)))
|
||||||
callContext.stack.push(l)
|
scope.Stack.push(l)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opCodeCopy(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
var (
|
var (
|
||||||
memOffset = callContext.stack.pop()
|
memOffset = scope.Stack.pop()
|
||||||
codeOffset = callContext.stack.pop()
|
codeOffset = scope.Stack.pop()
|
||||||
length = callContext.stack.pop()
|
length = scope.Stack.pop()
|
||||||
)
|
)
|
||||||
uint64CodeOffset, overflow := codeOffset.Uint64WithOverflow()
|
uint64CodeOffset, overflow := codeOffset.Uint64WithOverflow()
|
||||||
if overflow {
|
if overflow {
|
||||||
uint64CodeOffset = 0xffffffffffffffff
|
uint64CodeOffset = 0xffffffffffffffff
|
||||||
}
|
}
|
||||||
codeCopy := getData(callContext.contract.Code, uint64CodeOffset, length.Uint64())
|
codeCopy := getData(scope.Contract.Code, uint64CodeOffset, length.Uint64())
|
||||||
callContext.memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy)
|
scope.Memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy)
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
var (
|
var (
|
||||||
stack = callContext.stack
|
stack = scope.Stack
|
||||||
a = stack.pop()
|
a = stack.pop()
|
||||||
memOffset = stack.pop()
|
memOffset = stack.pop()
|
||||||
codeOffset = stack.pop()
|
codeOffset = stack.pop()
|
||||||
@ -382,7 +382,7 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx
|
|||||||
}
|
}
|
||||||
addr := common.Address(a.Bytes20())
|
addr := common.Address(a.Bytes20())
|
||||||
codeCopy := getData(interpreter.evm.StateDB.GetCode(addr), uint64CodeOffset, length.Uint64())
|
codeCopy := getData(interpreter.evm.StateDB.GetCode(addr), uint64CodeOffset, length.Uint64())
|
||||||
callContext.memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy)
|
scope.Memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy)
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
@ -413,8 +413,8 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx
|
|||||||
//
|
//
|
||||||
// (6) Caller tries to get the code hash for an account which is marked as deleted,
|
// (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.
|
// this account should be regarded as a non-existent account and zero should be returned.
|
||||||
func opExtCodeHash(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opExtCodeHash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
slot := callContext.stack.peek()
|
slot := scope.Stack.peek()
|
||||||
address := common.Address(slot.Bytes20())
|
address := common.Address(slot.Bytes20())
|
||||||
if interpreter.evm.StateDB.Empty(address) {
|
if interpreter.evm.StateDB.Empty(address) {
|
||||||
slot.Clear()
|
slot.Clear()
|
||||||
@ -424,14 +424,14 @@ func opExtCodeHash(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opGasprice(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opGasprice(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
v, _ := uint256.FromBig(interpreter.evm.GasPrice)
|
v, _ := uint256.FromBig(interpreter.evm.GasPrice)
|
||||||
callContext.stack.push(v)
|
scope.Stack.push(v)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opBlockhash(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opBlockhash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
num := callContext.stack.peek()
|
num := scope.Stack.peek()
|
||||||
num64, overflow := num.Uint64WithOverflow()
|
num64, overflow := num.Uint64WithOverflow()
|
||||||
if overflow {
|
if overflow {
|
||||||
num.Clear()
|
num.Clear()
|
||||||
@ -452,88 +452,88 @@ func opBlockhash(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx)
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opCoinbase(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opCoinbase(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
callContext.stack.push(new(uint256.Int).SetBytes(interpreter.evm.Context.Coinbase.Bytes()))
|
scope.Stack.push(new(uint256.Int).SetBytes(interpreter.evm.Context.Coinbase.Bytes()))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opTimestamp(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opTimestamp(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
v, _ := uint256.FromBig(interpreter.evm.Context.Time)
|
v, _ := uint256.FromBig(interpreter.evm.Context.Time)
|
||||||
callContext.stack.push(v)
|
scope.Stack.push(v)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opNumber(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opNumber(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
v, _ := uint256.FromBig(interpreter.evm.Context.BlockNumber)
|
v, _ := uint256.FromBig(interpreter.evm.Context.BlockNumber)
|
||||||
callContext.stack.push(v)
|
scope.Stack.push(v)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opDifficulty(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opDifficulty(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
v, _ := uint256.FromBig(interpreter.evm.Context.Difficulty)
|
v, _ := uint256.FromBig(interpreter.evm.Context.Difficulty)
|
||||||
callContext.stack.push(v)
|
scope.Stack.push(v)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opGasLimit(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opGasLimit(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
callContext.stack.push(new(uint256.Int).SetUint64(interpreter.evm.Context.GasLimit))
|
scope.Stack.push(new(uint256.Int).SetUint64(interpreter.evm.Context.GasLimit))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opPop(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opPop(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
callContext.stack.pop()
|
scope.Stack.pop()
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opMload(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opMload(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
v := callContext.stack.peek()
|
v := scope.Stack.peek()
|
||||||
offset := int64(v.Uint64())
|
offset := int64(v.Uint64())
|
||||||
v.SetBytes(callContext.memory.GetPtr(offset, 32))
|
v.SetBytes(scope.Memory.GetPtr(offset, 32))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opMstore(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opMstore(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
// pop value of the stack
|
// pop value of the stack
|
||||||
mStart, val := callContext.stack.pop(), callContext.stack.pop()
|
mStart, val := scope.Stack.pop(), scope.Stack.pop()
|
||||||
callContext.memory.Set32(mStart.Uint64(), &val)
|
scope.Memory.Set32(mStart.Uint64(), &val)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opMstore8(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opMstore8(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
off, val := callContext.stack.pop(), callContext.stack.pop()
|
off, val := scope.Stack.pop(), scope.Stack.pop()
|
||||||
callContext.memory.store[off.Uint64()] = byte(val.Uint64())
|
scope.Memory.store[off.Uint64()] = byte(val.Uint64())
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSload(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opSload(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
loc := callContext.stack.peek()
|
loc := scope.Stack.peek()
|
||||||
hash := common.Hash(loc.Bytes32())
|
hash := common.Hash(loc.Bytes32())
|
||||||
val := interpreter.evm.StateDB.GetState(callContext.contract.Address(), hash)
|
val := interpreter.evm.StateDB.GetState(scope.Contract.Address(), hash)
|
||||||
loc.SetBytes(val.Bytes())
|
loc.SetBytes(val.Bytes())
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSstore(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opSstore(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
loc := callContext.stack.pop()
|
loc := scope.Stack.pop()
|
||||||
val := callContext.stack.pop()
|
val := scope.Stack.pop()
|
||||||
interpreter.evm.StateDB.SetState(callContext.contract.Address(),
|
interpreter.evm.StateDB.SetState(scope.Contract.Address(),
|
||||||
loc.Bytes32(), val.Bytes32())
|
loc.Bytes32(), val.Bytes32())
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opJump(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opJump(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
pos := callContext.stack.pop()
|
pos := scope.Stack.pop()
|
||||||
if !callContext.contract.validJumpdest(&pos) {
|
if !scope.Contract.validJumpdest(&pos) {
|
||||||
return nil, ErrInvalidJump
|
return nil, ErrInvalidJump
|
||||||
}
|
}
|
||||||
*pc = pos.Uint64()
|
*pc = pos.Uint64()
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opJumpi(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opJumpi(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
pos, cond := callContext.stack.pop(), callContext.stack.pop()
|
pos, cond := scope.Stack.pop(), scope.Stack.pop()
|
||||||
if !cond.IsZero() {
|
if !cond.IsZero() {
|
||||||
if !callContext.contract.validJumpdest(&pos) {
|
if !scope.Contract.validJumpdest(&pos) {
|
||||||
return nil, ErrInvalidJump
|
return nil, ErrInvalidJump
|
||||||
}
|
}
|
||||||
*pc = pos.Uint64()
|
*pc = pos.Uint64()
|
||||||
@ -543,31 +543,31 @@ func opJumpi(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]b
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opJumpdest(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opJumpdest(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opPc(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opPc(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
callContext.stack.push(new(uint256.Int).SetUint64(*pc))
|
scope.Stack.push(new(uint256.Int).SetUint64(*pc))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opMsize(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opMsize(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
callContext.stack.push(new(uint256.Int).SetUint64(uint64(callContext.memory.Len())))
|
scope.Stack.push(new(uint256.Int).SetUint64(uint64(scope.Memory.Len())))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opGas(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opGas(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
callContext.stack.push(new(uint256.Int).SetUint64(callContext.contract.Gas))
|
scope.Stack.push(new(uint256.Int).SetUint64(scope.Contract.Gas))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opCreate(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
var (
|
var (
|
||||||
value = callContext.stack.pop()
|
value = scope.Stack.pop()
|
||||||
offset, size = callContext.stack.pop(), callContext.stack.pop()
|
offset, size = scope.Stack.pop(), scope.Stack.pop()
|
||||||
input = callContext.memory.GetCopy(int64(offset.Uint64()), int64(size.Uint64()))
|
input = scope.Memory.GetCopy(int64(offset.Uint64()), int64(size.Uint64()))
|
||||||
gas = callContext.contract.Gas
|
gas = scope.Contract.Gas
|
||||||
)
|
)
|
||||||
if interpreter.evm.chainRules.IsEIP150 {
|
if interpreter.evm.chainRules.IsEIP150 {
|
||||||
gas -= gas / 64
|
gas -= gas / 64
|
||||||
@ -575,14 +575,14 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]
|
|||||||
// reuse size int for stackvalue
|
// reuse size int for stackvalue
|
||||||
stackvalue := size
|
stackvalue := size
|
||||||
|
|
||||||
callContext.contract.UseGas(gas)
|
scope.Contract.UseGas(gas)
|
||||||
//TODO: use uint256.Int instead of converting with toBig()
|
//TODO: use uint256.Int instead of converting with toBig()
|
||||||
var bigVal = big0
|
var bigVal = big0
|
||||||
if !value.IsZero() {
|
if !value.IsZero() {
|
||||||
bigVal = value.ToBig()
|
bigVal = value.ToBig()
|
||||||
}
|
}
|
||||||
|
|
||||||
res, addr, returnGas, suberr := interpreter.evm.Create(callContext.contract, input, gas, bigVal)
|
res, addr, returnGas, suberr := interpreter.evm.Create(scope.Contract, input, gas, bigVal)
|
||||||
// Push item on the stack based on the returned error. If the ruleset is
|
// Push item on the stack based on the returned error. If the ruleset is
|
||||||
// homestead we must check for CodeStoreOutOfGasError (homestead only
|
// homestead we must check for CodeStoreOutOfGasError (homestead only
|
||||||
// rule) and treat as an error, if the ruleset is frontier we must
|
// rule) and treat as an error, if the ruleset is frontier we must
|
||||||
@ -594,8 +594,8 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]
|
|||||||
} else {
|
} else {
|
||||||
stackvalue.SetBytes(addr.Bytes())
|
stackvalue.SetBytes(addr.Bytes())
|
||||||
}
|
}
|
||||||
callContext.stack.push(&stackvalue)
|
scope.Stack.push(&stackvalue)
|
||||||
callContext.contract.Gas += returnGas
|
scope.Contract.Gas += returnGas
|
||||||
|
|
||||||
if suberr == ErrExecutionReverted {
|
if suberr == ErrExecutionReverted {
|
||||||
return res, nil
|
return res, nil
|
||||||
@ -603,18 +603,18 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opCreate2(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
var (
|
var (
|
||||||
endowment = callContext.stack.pop()
|
endowment = scope.Stack.pop()
|
||||||
offset, size = callContext.stack.pop(), callContext.stack.pop()
|
offset, size = scope.Stack.pop(), scope.Stack.pop()
|
||||||
salt = callContext.stack.pop()
|
salt = scope.Stack.pop()
|
||||||
input = callContext.memory.GetCopy(int64(offset.Uint64()), int64(size.Uint64()))
|
input = scope.Memory.GetCopy(int64(offset.Uint64()), int64(size.Uint64()))
|
||||||
gas = callContext.contract.Gas
|
gas = scope.Contract.Gas
|
||||||
)
|
)
|
||||||
|
|
||||||
// Apply EIP150
|
// Apply EIP150
|
||||||
gas -= gas / 64
|
gas -= gas / 64
|
||||||
callContext.contract.UseGas(gas)
|
scope.Contract.UseGas(gas)
|
||||||
// reuse size int for stackvalue
|
// reuse size int for stackvalue
|
||||||
stackvalue := size
|
stackvalue := size
|
||||||
//TODO: use uint256.Int instead of converting with toBig()
|
//TODO: use uint256.Int instead of converting with toBig()
|
||||||
@ -622,7 +622,7 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([
|
|||||||
if !endowment.IsZero() {
|
if !endowment.IsZero() {
|
||||||
bigEndowment = endowment.ToBig()
|
bigEndowment = endowment.ToBig()
|
||||||
}
|
}
|
||||||
res, addr, returnGas, suberr := interpreter.evm.Create2(callContext.contract, input, gas,
|
res, addr, returnGas, suberr := interpreter.evm.Create2(scope.Contract, input, gas,
|
||||||
bigEndowment, &salt)
|
bigEndowment, &salt)
|
||||||
// Push item on the stack based on the returned error.
|
// Push item on the stack based on the returned error.
|
||||||
if suberr != nil {
|
if suberr != nil {
|
||||||
@ -630,8 +630,8 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([
|
|||||||
} else {
|
} else {
|
||||||
stackvalue.SetBytes(addr.Bytes())
|
stackvalue.SetBytes(addr.Bytes())
|
||||||
}
|
}
|
||||||
callContext.stack.push(&stackvalue)
|
scope.Stack.push(&stackvalue)
|
||||||
callContext.contract.Gas += returnGas
|
scope.Contract.Gas += returnGas
|
||||||
|
|
||||||
if suberr == ErrExecutionReverted {
|
if suberr == ErrExecutionReverted {
|
||||||
return res, nil
|
return res, nil
|
||||||
@ -639,8 +639,8 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opCall(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
stack := callContext.stack
|
stack := scope.Stack
|
||||||
// Pop gas. The actual gas in interpreter.evm.callGasTemp.
|
// Pop gas. The actual gas in interpreter.evm.callGasTemp.
|
||||||
// We can use this as a temporary value
|
// We can use this as a temporary value
|
||||||
temp := stack.pop()
|
temp := stack.pop()
|
||||||
@ -649,7 +649,7 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]by
|
|||||||
addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
|
addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
|
||||||
toAddr := common.Address(addr.Bytes20())
|
toAddr := common.Address(addr.Bytes20())
|
||||||
// Get the arguments from the memory.
|
// Get the arguments from the memory.
|
||||||
args := callContext.memory.GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64()))
|
args := scope.Memory.GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64()))
|
||||||
|
|
||||||
var bigVal = big0
|
var bigVal = big0
|
||||||
//TODO: use uint256.Int instead of converting with toBig()
|
//TODO: use uint256.Int instead of converting with toBig()
|
||||||
@ -660,7 +660,7 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]by
|
|||||||
bigVal = value.ToBig()
|
bigVal = value.ToBig()
|
||||||
}
|
}
|
||||||
|
|
||||||
ret, returnGas, err := interpreter.evm.Call(callContext.contract, toAddr, args, gas, bigVal)
|
ret, returnGas, err := interpreter.evm.Call(scope.Contract, toAddr, args, gas, bigVal)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
temp.Clear()
|
temp.Clear()
|
||||||
@ -669,16 +669,16 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]by
|
|||||||
}
|
}
|
||||||
stack.push(&temp)
|
stack.push(&temp)
|
||||||
if err == nil || err == ErrExecutionReverted {
|
if err == nil || err == ErrExecutionReverted {
|
||||||
callContext.memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
||||||
}
|
}
|
||||||
callContext.contract.Gas += returnGas
|
scope.Contract.Gas += returnGas
|
||||||
|
|
||||||
return ret, nil
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opCallCode(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opCallCode(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
// Pop gas. The actual gas is in interpreter.evm.callGasTemp.
|
// Pop gas. The actual gas is in interpreter.evm.callGasTemp.
|
||||||
stack := callContext.stack
|
stack := scope.Stack
|
||||||
// We use it as a temporary value
|
// We use it as a temporary value
|
||||||
temp := stack.pop()
|
temp := stack.pop()
|
||||||
gas := interpreter.evm.callGasTemp
|
gas := interpreter.evm.callGasTemp
|
||||||
@ -686,7 +686,7 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) (
|
|||||||
addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
|
addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
|
||||||
toAddr := common.Address(addr.Bytes20())
|
toAddr := common.Address(addr.Bytes20())
|
||||||
// Get arguments from the memory.
|
// Get arguments from the memory.
|
||||||
args := callContext.memory.GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64()))
|
args := scope.Memory.GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64()))
|
||||||
|
|
||||||
//TODO: use uint256.Int instead of converting with toBig()
|
//TODO: use uint256.Int instead of converting with toBig()
|
||||||
var bigVal = big0
|
var bigVal = big0
|
||||||
@ -695,7 +695,7 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) (
|
|||||||
bigVal = value.ToBig()
|
bigVal = value.ToBig()
|
||||||
}
|
}
|
||||||
|
|
||||||
ret, returnGas, err := interpreter.evm.CallCode(callContext.contract, toAddr, args, gas, bigVal)
|
ret, returnGas, err := interpreter.evm.CallCode(scope.Contract, toAddr, args, gas, bigVal)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
temp.Clear()
|
temp.Clear()
|
||||||
} else {
|
} else {
|
||||||
@ -703,15 +703,15 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) (
|
|||||||
}
|
}
|
||||||
stack.push(&temp)
|
stack.push(&temp)
|
||||||
if err == nil || err == ErrExecutionReverted {
|
if err == nil || err == ErrExecutionReverted {
|
||||||
callContext.memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
||||||
}
|
}
|
||||||
callContext.contract.Gas += returnGas
|
scope.Contract.Gas += returnGas
|
||||||
|
|
||||||
return ret, nil
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
stack := callContext.stack
|
stack := scope.Stack
|
||||||
// Pop gas. The actual gas is in interpreter.evm.callGasTemp.
|
// Pop gas. The actual gas is in interpreter.evm.callGasTemp.
|
||||||
// We use it as a temporary value
|
// We use it as a temporary value
|
||||||
temp := stack.pop()
|
temp := stack.pop()
|
||||||
@ -720,9 +720,9 @@ func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, callContext *callCt
|
|||||||
addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
|
addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
|
||||||
toAddr := common.Address(addr.Bytes20())
|
toAddr := common.Address(addr.Bytes20())
|
||||||
// Get arguments from the memory.
|
// Get arguments from the memory.
|
||||||
args := callContext.memory.GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64()))
|
args := scope.Memory.GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64()))
|
||||||
|
|
||||||
ret, returnGas, err := interpreter.evm.DelegateCall(callContext.contract, toAddr, args, gas)
|
ret, returnGas, err := interpreter.evm.DelegateCall(scope.Contract, toAddr, args, gas)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
temp.Clear()
|
temp.Clear()
|
||||||
} else {
|
} else {
|
||||||
@ -730,16 +730,16 @@ func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, callContext *callCt
|
|||||||
}
|
}
|
||||||
stack.push(&temp)
|
stack.push(&temp)
|
||||||
if err == nil || err == ErrExecutionReverted {
|
if err == nil || err == ErrExecutionReverted {
|
||||||
callContext.memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
||||||
}
|
}
|
||||||
callContext.contract.Gas += returnGas
|
scope.Contract.Gas += returnGas
|
||||||
|
|
||||||
return ret, nil
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opStaticCall(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opStaticCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
// Pop gas. The actual gas is in interpreter.evm.callGasTemp.
|
// Pop gas. The actual gas is in interpreter.evm.callGasTemp.
|
||||||
stack := callContext.stack
|
stack := scope.Stack
|
||||||
// We use it as a temporary value
|
// We use it as a temporary value
|
||||||
temp := stack.pop()
|
temp := stack.pop()
|
||||||
gas := interpreter.evm.callGasTemp
|
gas := interpreter.evm.callGasTemp
|
||||||
@ -747,9 +747,9 @@ func opStaticCall(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx)
|
|||||||
addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
|
addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
|
||||||
toAddr := common.Address(addr.Bytes20())
|
toAddr := common.Address(addr.Bytes20())
|
||||||
// Get arguments from the memory.
|
// Get arguments from the memory.
|
||||||
args := callContext.memory.GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64()))
|
args := scope.Memory.GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64()))
|
||||||
|
|
||||||
ret, returnGas, err := interpreter.evm.StaticCall(callContext.contract, toAddr, args, gas)
|
ret, returnGas, err := interpreter.evm.StaticCall(scope.Contract, toAddr, args, gas)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
temp.Clear()
|
temp.Clear()
|
||||||
} else {
|
} else {
|
||||||
@ -757,36 +757,36 @@ func opStaticCall(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx)
|
|||||||
}
|
}
|
||||||
stack.push(&temp)
|
stack.push(&temp)
|
||||||
if err == nil || err == ErrExecutionReverted {
|
if err == nil || err == ErrExecutionReverted {
|
||||||
callContext.memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
||||||
}
|
}
|
||||||
callContext.contract.Gas += returnGas
|
scope.Contract.Gas += returnGas
|
||||||
|
|
||||||
return ret, nil
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opReturn(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opReturn(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
offset, size := callContext.stack.pop(), callContext.stack.pop()
|
offset, size := scope.Stack.pop(), scope.Stack.pop()
|
||||||
ret := callContext.memory.GetPtr(int64(offset.Uint64()), int64(size.Uint64()))
|
ret := scope.Memory.GetPtr(int64(offset.Uint64()), int64(size.Uint64()))
|
||||||
|
|
||||||
return ret, nil
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opRevert(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opRevert(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
offset, size := callContext.stack.pop(), callContext.stack.pop()
|
offset, size := scope.Stack.pop(), scope.Stack.pop()
|
||||||
ret := callContext.memory.GetPtr(int64(offset.Uint64()), int64(size.Uint64()))
|
ret := scope.Memory.GetPtr(int64(offset.Uint64()), int64(size.Uint64()))
|
||||||
|
|
||||||
return ret, nil
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opStop(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opStop(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSuicide(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opSuicide(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
beneficiary := callContext.stack.pop()
|
beneficiary := scope.Stack.pop()
|
||||||
balance := interpreter.evm.StateDB.GetBalance(callContext.contract.Address())
|
balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address())
|
||||||
interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance)
|
interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance)
|
||||||
interpreter.evm.StateDB.Suicide(callContext.contract.Address())
|
interpreter.evm.StateDB.Suicide(scope.Contract.Address())
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -794,18 +794,18 @@ func opSuicide(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([
|
|||||||
|
|
||||||
// make log instruction function
|
// make log instruction function
|
||||||
func makeLog(size int) executionFunc {
|
func makeLog(size int) executionFunc {
|
||||||
return func(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
topics := make([]common.Hash, size)
|
topics := make([]common.Hash, size)
|
||||||
stack := callContext.stack
|
stack := scope.Stack
|
||||||
mStart, mSize := stack.pop(), stack.pop()
|
mStart, mSize := stack.pop(), stack.pop()
|
||||||
for i := 0; i < size; i++ {
|
for i := 0; i < size; i++ {
|
||||||
addr := stack.pop()
|
addr := stack.pop()
|
||||||
topics[i] = addr.Bytes32()
|
topics[i] = addr.Bytes32()
|
||||||
}
|
}
|
||||||
|
|
||||||
d := callContext.memory.GetCopy(int64(mStart.Uint64()), int64(mSize.Uint64()))
|
d := scope.Memory.GetCopy(int64(mStart.Uint64()), int64(mSize.Uint64()))
|
||||||
interpreter.evm.StateDB.AddLog(&types.Log{
|
interpreter.evm.StateDB.AddLog(&types.Log{
|
||||||
Address: callContext.contract.Address(),
|
Address: scope.Contract.Address(),
|
||||||
Topics: topics,
|
Topics: topics,
|
||||||
Data: d,
|
Data: d,
|
||||||
// This is a non-consensus field, but assigned here because
|
// This is a non-consensus field, but assigned here because
|
||||||
@ -818,24 +818,24 @@ func makeLog(size int) executionFunc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// opPush1 is a specialized version of pushN
|
// opPush1 is a specialized version of pushN
|
||||||
func opPush1(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opPush1(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
var (
|
var (
|
||||||
codeLen = uint64(len(callContext.contract.Code))
|
codeLen = uint64(len(scope.Contract.Code))
|
||||||
integer = new(uint256.Int)
|
integer = new(uint256.Int)
|
||||||
)
|
)
|
||||||
*pc += 1
|
*pc += 1
|
||||||
if *pc < codeLen {
|
if *pc < codeLen {
|
||||||
callContext.stack.push(integer.SetUint64(uint64(callContext.contract.Code[*pc])))
|
scope.Stack.push(integer.SetUint64(uint64(scope.Contract.Code[*pc])))
|
||||||
} else {
|
} else {
|
||||||
callContext.stack.push(integer.Clear())
|
scope.Stack.push(integer.Clear())
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// make push instruction function
|
// make push instruction function
|
||||||
func makePush(size uint64, pushByteSize int) executionFunc {
|
func makePush(size uint64, pushByteSize int) executionFunc {
|
||||||
return func(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
codeLen := len(callContext.contract.Code)
|
codeLen := len(scope.Contract.Code)
|
||||||
|
|
||||||
startMin := codeLen
|
startMin := codeLen
|
||||||
if int(*pc+1) < startMin {
|
if int(*pc+1) < startMin {
|
||||||
@ -848,8 +848,8 @@ func makePush(size uint64, pushByteSize int) executionFunc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
integer := new(uint256.Int)
|
integer := new(uint256.Int)
|
||||||
callContext.stack.push(integer.SetBytes(common.RightPadBytes(
|
scope.Stack.push(integer.SetBytes(common.RightPadBytes(
|
||||||
callContext.contract.Code[startMin:endMin], pushByteSize)))
|
scope.Contract.Code[startMin:endMin], pushByteSize)))
|
||||||
|
|
||||||
*pc += size
|
*pc += size
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@ -858,8 +858,8 @@ func makePush(size uint64, pushByteSize int) executionFunc {
|
|||||||
|
|
||||||
// make dup instruction function
|
// make dup instruction function
|
||||||
func makeDup(size int64) executionFunc {
|
func makeDup(size int64) executionFunc {
|
||||||
return func(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
callContext.stack.dup(int(size))
|
scope.Stack.dup(int(size))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -868,8 +868,8 @@ func makeDup(size int64) executionFunc {
|
|||||||
func makeSwap(size int64) executionFunc {
|
func makeSwap(size int64) executionFunc {
|
||||||
// switch n + 1 otherwise n would be swapped with n
|
// switch n + 1 otherwise n would be swapped with n
|
||||||
size++
|
size++
|
||||||
return func(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
callContext.stack.swap(int(size))
|
scope.Stack.swap(int(size))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,7 +104,7 @@ func testTwoOperandOp(t *testing.T, tests []TwoOperandTestcase, opFn executionFu
|
|||||||
expected := new(uint256.Int).SetBytes(common.Hex2Bytes(test.Expected))
|
expected := new(uint256.Int).SetBytes(common.Hex2Bytes(test.Expected))
|
||||||
stack.push(x)
|
stack.push(x)
|
||||||
stack.push(y)
|
stack.push(y)
|
||||||
opFn(&pc, evmInterpreter, &callCtx{nil, stack, nil})
|
opFn(&pc, evmInterpreter, &ScopeContext{nil, stack, nil})
|
||||||
if len(stack.data) != 1 {
|
if len(stack.data) != 1 {
|
||||||
t.Errorf("Expected one item on stack after %v, got %d: ", name, len(stack.data))
|
t.Errorf("Expected one item on stack after %v, got %d: ", name, len(stack.data))
|
||||||
}
|
}
|
||||||
@ -219,7 +219,7 @@ func TestAddMod(t *testing.T) {
|
|||||||
stack.push(z)
|
stack.push(z)
|
||||||
stack.push(y)
|
stack.push(y)
|
||||||
stack.push(x)
|
stack.push(x)
|
||||||
opAddmod(&pc, evmInterpreter, &callCtx{nil, stack, nil})
|
opAddmod(&pc, evmInterpreter, &ScopeContext{nil, stack, nil})
|
||||||
actual := stack.pop()
|
actual := stack.pop()
|
||||||
if actual.Cmp(expected) != 0 {
|
if actual.Cmp(expected) != 0 {
|
||||||
t.Errorf("Testcase %d, expected %x, got %x", i, expected, actual)
|
t.Errorf("Testcase %d, expected %x, got %x", i, expected, actual)
|
||||||
@ -241,7 +241,7 @@ func getResult(args []*twoOperandParams, opFn executionFunc) []TwoOperandTestcas
|
|||||||
y := new(uint256.Int).SetBytes(common.Hex2Bytes(param.y))
|
y := new(uint256.Int).SetBytes(common.Hex2Bytes(param.y))
|
||||||
stack.push(x)
|
stack.push(x)
|
||||||
stack.push(y)
|
stack.push(y)
|
||||||
opFn(&pc, interpreter, &callCtx{nil, stack, nil})
|
opFn(&pc, interpreter, &ScopeContext{nil, stack, nil})
|
||||||
actual := stack.pop()
|
actual := stack.pop()
|
||||||
result[i] = TwoOperandTestcase{param.x, param.y, fmt.Sprintf("%064x", actual)}
|
result[i] = TwoOperandTestcase{param.x, param.y, fmt.Sprintf("%064x", actual)}
|
||||||
}
|
}
|
||||||
@ -299,7 +299,7 @@ func opBenchmark(bench *testing.B, op executionFunc, args ...string) {
|
|||||||
a.SetBytes(arg)
|
a.SetBytes(arg)
|
||||||
stack.push(a)
|
stack.push(a)
|
||||||
}
|
}
|
||||||
op(&pc, evmInterpreter, &callCtx{nil, stack, nil})
|
op(&pc, evmInterpreter, &ScopeContext{nil, stack, nil})
|
||||||
stack.pop()
|
stack.pop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -525,12 +525,12 @@ func TestOpMstore(t *testing.T) {
|
|||||||
pc := uint64(0)
|
pc := uint64(0)
|
||||||
v := "abcdef00000000000000abba000000000deaf000000c0de00100000000133700"
|
v := "abcdef00000000000000abba000000000deaf000000c0de00100000000133700"
|
||||||
stack.pushN(*new(uint256.Int).SetBytes(common.Hex2Bytes(v)), *new(uint256.Int))
|
stack.pushN(*new(uint256.Int).SetBytes(common.Hex2Bytes(v)), *new(uint256.Int))
|
||||||
opMstore(&pc, evmInterpreter, &callCtx{mem, stack, nil})
|
opMstore(&pc, evmInterpreter, &ScopeContext{mem, stack, nil})
|
||||||
if got := common.Bytes2Hex(mem.GetCopy(0, 32)); got != v {
|
if got := common.Bytes2Hex(mem.GetCopy(0, 32)); got != v {
|
||||||
t.Fatalf("Mstore fail, got %v, expected %v", got, v)
|
t.Fatalf("Mstore fail, got %v, expected %v", got, v)
|
||||||
}
|
}
|
||||||
stack.pushN(*new(uint256.Int).SetUint64(0x1), *new(uint256.Int))
|
stack.pushN(*new(uint256.Int).SetUint64(0x1), *new(uint256.Int))
|
||||||
opMstore(&pc, evmInterpreter, &callCtx{mem, stack, nil})
|
opMstore(&pc, evmInterpreter, &ScopeContext{mem, stack, nil})
|
||||||
if common.Bytes2Hex(mem.GetCopy(0, 32)) != "0000000000000000000000000000000000000000000000000000000000000001" {
|
if common.Bytes2Hex(mem.GetCopy(0, 32)) != "0000000000000000000000000000000000000000000000000000000000000001" {
|
||||||
t.Fatalf("Mstore failed to overwrite previous value")
|
t.Fatalf("Mstore failed to overwrite previous value")
|
||||||
}
|
}
|
||||||
@ -553,7 +553,7 @@ func BenchmarkOpMstore(bench *testing.B) {
|
|||||||
bench.ResetTimer()
|
bench.ResetTimer()
|
||||||
for i := 0; i < bench.N; i++ {
|
for i := 0; i < bench.N; i++ {
|
||||||
stack.pushN(*value, *memStart)
|
stack.pushN(*value, *memStart)
|
||||||
opMstore(&pc, evmInterpreter, &callCtx{mem, stack, nil})
|
opMstore(&pc, evmInterpreter, &ScopeContext{mem, stack, nil})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -572,7 +572,7 @@ func BenchmarkOpSHA3(bench *testing.B) {
|
|||||||
bench.ResetTimer()
|
bench.ResetTimer()
|
||||||
for i := 0; i < bench.N; i++ {
|
for i := 0; i < bench.N; i++ {
|
||||||
stack.pushN(*uint256.NewInt().SetUint64(32), *start)
|
stack.pushN(*uint256.NewInt().SetUint64(32), *start)
|
||||||
opSha3(&pc, evmInterpreter, &callCtx{mem, stack, nil})
|
opSha3(&pc, evmInterpreter, &ScopeContext{mem, stack, nil})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,12 +62,12 @@ type Interpreter interface {
|
|||||||
CanRun([]byte) bool
|
CanRun([]byte) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// callCtx contains the things that are per-call, such as stack and memory,
|
// ScopeContext contains the things that are per-call, such as stack and memory,
|
||||||
// but not transients like pc and gas
|
// but not transients like pc and gas
|
||||||
type callCtx struct {
|
type ScopeContext struct {
|
||||||
memory *Memory
|
Memory *Memory
|
||||||
stack *Stack
|
Stack *Stack
|
||||||
contract *Contract
|
Contract *Contract
|
||||||
}
|
}
|
||||||
|
|
||||||
// keccakState wraps sha3.state. In addition to the usual hash methods, it also supports
|
// keccakState wraps sha3.state. In addition to the usual hash methods, it also supports
|
||||||
@ -163,10 +163,10 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
|
|||||||
op OpCode // current opcode
|
op OpCode // current opcode
|
||||||
mem = NewMemory() // bound memory
|
mem = NewMemory() // bound memory
|
||||||
stack = newstack() // local stack
|
stack = newstack() // local stack
|
||||||
callContext = &callCtx{
|
callContext = &ScopeContext{
|
||||||
memory: mem,
|
Memory: mem,
|
||||||
stack: stack,
|
Stack: stack,
|
||||||
contract: contract,
|
Contract: contract,
|
||||||
}
|
}
|
||||||
// For optimisation reason we're using uint64 as the program counter.
|
// 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
|
// It's theoretically possible to go above 2^64. The YP defines the PC
|
||||||
@ -191,9 +191,9 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
|
|||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !logged {
|
if !logged {
|
||||||
in.cfg.Tracer.CaptureState(in.evm, pcCopy, op, gasCopy, cost, mem, stack, in.returnData, contract, in.evm.depth, err)
|
in.cfg.Tracer.CaptureState(in.evm, pcCopy, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err)
|
||||||
} else {
|
} else {
|
||||||
in.cfg.Tracer.CaptureFault(in.evm, pcCopy, op, gasCopy, cost, mem, stack, contract, in.evm.depth, err)
|
in.cfg.Tracer.CaptureFault(in.evm, pcCopy, op, gasCopy, cost, callContext, in.evm.depth, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@ -275,7 +275,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
if in.cfg.Debug {
|
if in.cfg.Debug {
|
||||||
in.cfg.Tracer.CaptureState(in.evm, pc, op, gasCopy, cost, mem, stack, in.returnData, contract, in.evm.depth, err)
|
in.cfg.Tracer.CaptureState(in.evm, pc, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err)
|
||||||
logged = true
|
logged = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
executionFunc func(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error)
|
executionFunc func(pc *uint64, interpreter *EVMInterpreter, callContext *ScopeContext) ([]byte, error)
|
||||||
gasFunc func(*EVM, *Contract, *Stack, *Memory, uint64) (uint64, error) // last parameter is the requested memory size as a uint64
|
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 returns the required size, and whether the operation overflowed a uint64
|
||||||
memorySizeFunc func(*Stack) (size uint64, overflow bool)
|
memorySizeFunc func(*Stack) (size uint64, overflow bool)
|
||||||
|
@ -18,7 +18,6 @@ package vm
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math/big"
|
"math/big"
|
||||||
@ -32,8 +31,6 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
var errTraceLimitReached = errors.New("the number of logs reached the specified limit")
|
|
||||||
|
|
||||||
// Storage represents a contract's storage.
|
// Storage represents a contract's storage.
|
||||||
type Storage map[common.Hash]common.Hash
|
type Storage map[common.Hash]common.Hash
|
||||||
|
|
||||||
@ -107,10 +104,10 @@ func (s *StructLog) ErrorString() string {
|
|||||||
// Note that reference types are actual VM data structures; make copies
|
// Note that reference types are actual VM data structures; make copies
|
||||||
// if you need to retain them beyond the current call.
|
// if you need to retain them beyond the current call.
|
||||||
type Tracer interface {
|
type Tracer interface {
|
||||||
CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) error
|
CaptureStart(env *EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int)
|
||||||
CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, rData []byte, contract *Contract, depth int, err error) error
|
CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error)
|
||||||
CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error
|
CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, depth int, err error)
|
||||||
CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) error
|
CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// StructLogger is an EVM state logger and implements Tracer.
|
// StructLogger is an EVM state logger and implements Tracer.
|
||||||
@ -139,17 +136,19 @@ func NewStructLogger(cfg *LogConfig) *StructLogger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CaptureStart implements the Tracer interface to initialize the tracing operation.
|
// CaptureStart implements the Tracer interface to initialize the tracing operation.
|
||||||
func (l *StructLogger) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) error {
|
func (l *StructLogger) CaptureStart(env *EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CaptureState logs a new structured log message and pushes it out to the environment
|
// CaptureState logs a new structured log message and pushes it out to the environment
|
||||||
//
|
//
|
||||||
// CaptureState also tracks SLOAD/SSTORE ops to track storage change.
|
// CaptureState also tracks SLOAD/SSTORE ops to track storage change.
|
||||||
func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, rData []byte, contract *Contract, depth int, err error) error {
|
func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) {
|
||||||
|
memory := scope.Memory
|
||||||
|
stack := scope.Stack
|
||||||
|
contract := scope.Contract
|
||||||
// check if already accumulated the specified number of logs
|
// check if already accumulated the specified number of logs
|
||||||
if l.cfg.Limit != 0 && l.cfg.Limit <= len(l.logs) {
|
if l.cfg.Limit != 0 && l.cfg.Limit <= len(l.logs) {
|
||||||
return errTraceLimitReached
|
return
|
||||||
}
|
}
|
||||||
// Copy a snapshot of the current memory state to a new buffer
|
// Copy a snapshot of the current memory state to a new buffer
|
||||||
var mem []byte
|
var mem []byte
|
||||||
@ -199,17 +198,15 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui
|
|||||||
// create a new snapshot of the EVM.
|
// create a new snapshot of the EVM.
|
||||||
log := StructLog{pc, op, gas, cost, mem, memory.Len(), stck, rdata, storage, depth, env.StateDB.GetRefund(), err}
|
log := StructLog{pc, op, gas, cost, mem, memory.Len(), stck, rdata, storage, depth, env.StateDB.GetRefund(), err}
|
||||||
l.logs = append(l.logs, log)
|
l.logs = append(l.logs, log)
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CaptureFault implements the Tracer interface to trace an execution fault
|
// CaptureFault implements the Tracer interface to trace an execution fault
|
||||||
// while running an opcode.
|
// while running an opcode.
|
||||||
func (l *StructLogger) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error {
|
func (l *StructLogger) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, depth int, err error) {
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CaptureEnd is called after the call finishes to finalize the tracing.
|
// CaptureEnd is called after the call finishes to finalize the tracing.
|
||||||
func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) error {
|
func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) {
|
||||||
l.output = output
|
l.output = output
|
||||||
l.err = err
|
l.err = err
|
||||||
if l.cfg.Debug {
|
if l.cfg.Debug {
|
||||||
@ -218,7 +215,6 @@ func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration
|
|||||||
fmt.Printf(" error: %v\n", err)
|
fmt.Printf(" error: %v\n", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// StructLogs returns the captured log entries.
|
// StructLogs returns the captured log entries.
|
||||||
@ -292,7 +288,7 @@ func NewMarkdownLogger(cfg *LogConfig, writer io.Writer) *mdLogger {
|
|||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *mdLogger) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) error {
|
func (t *mdLogger) CaptureStart(env *EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
|
||||||
if !create {
|
if !create {
|
||||||
fmt.Fprintf(t.out, "From: `%v`\nTo: `%v`\nData: `0x%x`\nGas: `%d`\nValue `%v` wei\n",
|
fmt.Fprintf(t.out, "From: `%v`\nTo: `%v`\nData: `0x%x`\nGas: `%d`\nValue `%v` wei\n",
|
||||||
from.String(), to.String(),
|
from.String(), to.String(),
|
||||||
@ -307,10 +303,11 @@ func (t *mdLogger) CaptureStart(from common.Address, to common.Address, create b
|
|||||||
| Pc | Op | Cost | Stack | RStack | Refund |
|
| Pc | Op | Cost | Stack | RStack | Refund |
|
||||||
|-------|-------------|------|-----------|-----------|---------|
|
|-------|-------------|------|-----------|-----------|---------|
|
||||||
`)
|
`)
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *mdLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, rData []byte, contract *Contract, depth int, err error) error {
|
// CaptureState also tracks SLOAD/SSTORE ops to track storage change.
|
||||||
|
func (t *mdLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) {
|
||||||
|
stack := scope.Stack
|
||||||
fmt.Fprintf(t.out, "| %4d | %10v | %3d |", pc, op, cost)
|
fmt.Fprintf(t.out, "| %4d | %10v | %3d |", pc, op, cost)
|
||||||
|
|
||||||
if !t.cfg.DisableStack {
|
if !t.cfg.DisableStack {
|
||||||
@ -327,18 +324,13 @@ func (t *mdLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(t.out, "Error: %v\n", err)
|
fmt.Fprintf(t.out, "Error: %v\n", err)
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *mdLogger) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error {
|
func (t *mdLogger) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, depth int, err error) {
|
||||||
|
|
||||||
fmt.Fprintf(t.out, "\nError: at pc=%d, op=%v: %v\n", pc, op, err)
|
fmt.Fprintf(t.out, "\nError: at pc=%d, op=%v: %v\n", pc, op, err)
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *mdLogger) CaptureEnd(output []byte, gasUsed uint64, tm time.Duration, err error) error {
|
func (t *mdLogger) CaptureEnd(output []byte, gasUsed uint64, tm time.Duration, err error) {
|
||||||
fmt.Fprintf(t.out, "\nOutput: `0x%x`\nConsumed gas: `%d`\nError: `%v`\n",
|
fmt.Fprintf(t.out, "\nOutput: `0x%x`\nConsumed gas: `%d`\nError: `%v`\n",
|
||||||
output, gasUsed, err)
|
output, gasUsed, err)
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
@ -41,12 +41,16 @@ func NewJSONLogger(cfg *LogConfig, writer io.Writer) *JSONLogger {
|
|||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *JSONLogger) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) error {
|
func (l *JSONLogger) CaptureStart(env *EVM, from, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *JSONLogger) CaptureFault(*EVM, uint64, OpCode, uint64, uint64, *ScopeContext, int, error) {}
|
||||||
|
|
||||||
// CaptureState outputs state information on the logger.
|
// CaptureState outputs state information on the logger.
|
||||||
func (l *JSONLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, rData []byte, contract *Contract, depth int, err error) error {
|
func (l *JSONLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) {
|
||||||
|
memory := scope.Memory
|
||||||
|
stack := scope.Stack
|
||||||
|
|
||||||
log := StructLog{
|
log := StructLog{
|
||||||
Pc: pc,
|
Pc: pc,
|
||||||
Op: op,
|
Op: op,
|
||||||
@ -72,16 +76,11 @@ func (l *JSONLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint
|
|||||||
if !l.cfg.DisableReturnData {
|
if !l.cfg.DisableReturnData {
|
||||||
log.ReturnData = rData
|
log.ReturnData = rData
|
||||||
}
|
}
|
||||||
return l.encoder.Encode(log)
|
l.encoder.Encode(log)
|
||||||
}
|
|
||||||
|
|
||||||
// CaptureFault outputs state information on the logger.
|
|
||||||
func (l *JSONLogger) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error {
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CaptureEnd is triggered at end of execution.
|
// CaptureEnd is triggered at end of execution.
|
||||||
func (l *JSONLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) error {
|
func (l *JSONLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) {
|
||||||
type endLog struct {
|
type endLog struct {
|
||||||
Output string `json:"output"`
|
Output string `json:"output"`
|
||||||
GasUsed math.HexOrDecimal64 `json:"gasUsed"`
|
GasUsed math.HexOrDecimal64 `json:"gasUsed"`
|
||||||
@ -89,7 +88,7 @@ func (l *JSONLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration,
|
|||||||
Err string `json:"error,omitempty"`
|
Err string `json:"error,omitempty"`
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return l.encoder.Encode(endLog{common.Bytes2Hex(output), math.HexOrDecimal64(gasUsed), t, err.Error()})
|
l.encoder.Encode(endLog{common.Bytes2Hex(output), math.HexOrDecimal64(gasUsed), t, err.Error()})
|
||||||
}
|
}
|
||||||
return l.encoder.Encode(endLog{common.Bytes2Hex(output), math.HexOrDecimal64(gasUsed), t, ""})
|
l.encoder.Encode(endLog{common.Bytes2Hex(output), math.HexOrDecimal64(gasUsed), t, ""})
|
||||||
}
|
}
|
||||||
|
@ -53,16 +53,20 @@ func TestStoreCapture(t *testing.T) {
|
|||||||
var (
|
var (
|
||||||
env = NewEVM(BlockContext{}, TxContext{}, &dummyStatedb{}, params.TestChainConfig, Config{})
|
env = NewEVM(BlockContext{}, TxContext{}, &dummyStatedb{}, params.TestChainConfig, Config{})
|
||||||
logger = NewStructLogger(nil)
|
logger = NewStructLogger(nil)
|
||||||
mem = NewMemory()
|
|
||||||
stack = newstack()
|
|
||||||
contract = NewContract(&dummyContractRef{}, &dummyContractRef{}, new(big.Int), 0)
|
contract = NewContract(&dummyContractRef{}, &dummyContractRef{}, new(big.Int), 0)
|
||||||
|
scope = &ScopeContext{
|
||||||
|
Memory: NewMemory(),
|
||||||
|
Stack: newstack(),
|
||||||
|
Contract: contract,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
stack.push(uint256.NewInt().SetUint64(1))
|
scope.Stack.push(uint256.NewInt().SetUint64(1))
|
||||||
stack.push(uint256.NewInt())
|
scope.Stack.push(uint256.NewInt())
|
||||||
var index common.Hash
|
var index common.Hash
|
||||||
logger.CaptureState(env, 0, SSTORE, 0, 0, mem, stack, nil, contract, 0, nil)
|
logger.CaptureState(env, 0, SSTORE, 0, 0, scope, nil, 0, nil)
|
||||||
if len(logger.storage[contract.Address()]) == 0 {
|
if len(logger.storage[contract.Address()]) == 0 {
|
||||||
t.Fatalf("expected exactly 1 changed value on address %x, got %d", contract.Address(), len(logger.storage[contract.Address()]))
|
t.Fatalf("expected exactly 1 changed value on address %x, got %d", contract.Address(),
|
||||||
|
len(logger.storage[contract.Address()]))
|
||||||
}
|
}
|
||||||
exp := common.BigToHash(big.NewInt(1))
|
exp := common.BigToHash(big.NewInt(1))
|
||||||
if logger.storage[contract.Address()][index] != exp {
|
if logger.storage[contract.Address()][index] != exp {
|
||||||
|
@ -326,23 +326,18 @@ type stepCounter struct {
|
|||||||
steps int
|
steps int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stepCounter) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) error {
|
func (s *stepCounter) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stepCounter) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost uint64, memory *vm.Memory, stack *vm.Stack, rData []byte, contract *vm.Contract, depth int, err error) error {
|
func (s *stepCounter) CaptureFault(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *stepCounter) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) {}
|
||||||
|
|
||||||
|
func (s *stepCounter) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
|
||||||
s.steps++
|
s.steps++
|
||||||
// Enable this for more output
|
// Enable this for more output
|
||||||
//s.inner.CaptureState(env, pc, op, gas, cost, memory, stack, rStack, contract, depth, err)
|
//s.inner.CaptureState(env, pc, op, gas, cost, memory, stack, rStack, contract, depth, err)
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *stepCounter) CaptureFault(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost uint64, memory *vm.Memory, stack *vm.Stack, contract *vm.Contract, depth int, err error) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *stepCounter) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) error {
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// benchmarkNonModifyingCode benchmarks code, but if the code modifies the
|
// benchmarkNonModifyingCode benchmarks code, but if the code modifies the
|
||||||
|
@ -287,8 +287,6 @@ func (cw *contractWrapper) pushObject(vm *duktape.Context) {
|
|||||||
// Tracer provides an implementation of Tracer that evaluates a Javascript
|
// Tracer provides an implementation of Tracer that evaluates a Javascript
|
||||||
// function for each VM execution step.
|
// function for each VM execution step.
|
||||||
type Tracer struct {
|
type Tracer struct {
|
||||||
inited bool // Flag whether the context was already inited from the EVM
|
|
||||||
|
|
||||||
vm *duktape.Context // Javascript VM instance
|
vm *duktape.Context // Javascript VM instance
|
||||||
|
|
||||||
tracerObject int // Stack index of the tracer JavaScript object
|
tracerObject int // Stack index of the tracer JavaScript object
|
||||||
@ -529,7 +527,7 @@ func wrapError(context string, err error) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CaptureStart implements the Tracer interface to initialize the tracing operation.
|
// CaptureStart implements the Tracer interface to initialize the tracing operation.
|
||||||
func (jst *Tracer) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) error {
|
func (jst *Tracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
|
||||||
jst.ctx["type"] = "CALL"
|
jst.ctx["type"] = "CALL"
|
||||||
if create {
|
if create {
|
||||||
jst.ctx["type"] = "CREATE"
|
jst.ctx["type"] = "CREATE"
|
||||||
@ -540,39 +538,33 @@ func (jst *Tracer) CaptureStart(from common.Address, to common.Address, create b
|
|||||||
jst.ctx["gas"] = gas
|
jst.ctx["gas"] = gas
|
||||||
jst.ctx["value"] = value
|
jst.ctx["value"] = value
|
||||||
|
|
||||||
return nil
|
// Initialize the context
|
||||||
}
|
|
||||||
|
|
||||||
// CaptureState implements the Tracer interface to trace a single step of VM execution.
|
|
||||||
func (jst *Tracer) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost uint64, memory *vm.Memory, stack *vm.Stack, rdata []byte, contract *vm.Contract, depth int, err error) error {
|
|
||||||
if jst.err == nil {
|
|
||||||
// Initialize the context if it wasn't done yet
|
|
||||||
if !jst.inited {
|
|
||||||
jst.ctx["block"] = env.Context.BlockNumber.Uint64()
|
jst.ctx["block"] = env.Context.BlockNumber.Uint64()
|
||||||
|
jst.dbWrapper.db = env.StateDB
|
||||||
// Compute intrinsic gas
|
// Compute intrinsic gas
|
||||||
isHomestead := env.ChainConfig().IsHomestead(env.Context.BlockNumber)
|
isHomestead := env.ChainConfig().IsHomestead(env.Context.BlockNumber)
|
||||||
isIstanbul := env.ChainConfig().IsIstanbul(env.Context.BlockNumber)
|
isIstanbul := env.ChainConfig().IsIstanbul(env.Context.BlockNumber)
|
||||||
var input []byte
|
|
||||||
if data, ok := jst.ctx["input"].([]byte); ok {
|
|
||||||
input = data
|
|
||||||
}
|
|
||||||
intrinsicGas, err := core.IntrinsicGas(input, nil, jst.ctx["type"] == "CREATE", isHomestead, isIstanbul)
|
intrinsicGas, err := core.IntrinsicGas(input, nil, jst.ctx["type"] == "CREATE", isHomestead, isIstanbul)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return
|
||||||
}
|
}
|
||||||
jst.ctx["intrinsicGas"] = intrinsicGas
|
jst.ctx["intrinsicGas"] = intrinsicGas
|
||||||
jst.inited = true
|
}
|
||||||
|
|
||||||
|
// CaptureState implements the Tracer interface to trace a single step of VM execution.
|
||||||
|
func (jst *Tracer) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
|
||||||
|
if jst.err != nil {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
// If tracing was interrupted, set the error and stop
|
// If tracing was interrupted, set the error and stop
|
||||||
if atomic.LoadUint32(&jst.interrupt) > 0 {
|
if atomic.LoadUint32(&jst.interrupt) > 0 {
|
||||||
jst.err = jst.reason
|
jst.err = jst.reason
|
||||||
return nil
|
return
|
||||||
}
|
}
|
||||||
jst.opWrapper.op = op
|
jst.opWrapper.op = op
|
||||||
jst.stackWrapper.stack = stack
|
jst.stackWrapper.stack = scope.Stack
|
||||||
jst.memoryWrapper.memory = memory
|
jst.memoryWrapper.memory = scope.Memory
|
||||||
jst.contractWrapper.contract = contract
|
jst.contractWrapper.contract = scope.Contract
|
||||||
jst.dbWrapper.db = env.StateDB
|
|
||||||
|
|
||||||
*jst.pcValue = uint(pc)
|
*jst.pcValue = uint(pc)
|
||||||
*jst.gasValue = uint(gas)
|
*jst.gasValue = uint(gas)
|
||||||
@ -585,32 +577,28 @@ func (jst *Tracer) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost
|
|||||||
jst.errorValue = new(string)
|
jst.errorValue = new(string)
|
||||||
*jst.errorValue = err.Error()
|
*jst.errorValue = err.Error()
|
||||||
}
|
}
|
||||||
_, err := jst.call("step", "log", "db")
|
|
||||||
if err != nil {
|
if _, err := jst.call("step", "log", "db"); err != nil {
|
||||||
jst.err = wrapError("step", err)
|
jst.err = wrapError("step", err)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CaptureFault implements the Tracer interface to trace an execution fault
|
// CaptureFault implements the Tracer interface to trace an execution fault
|
||||||
// while running an opcode.
|
func (jst *Tracer) CaptureFault(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) {
|
||||||
func (jst *Tracer) CaptureFault(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost uint64, memory *vm.Memory, stack *vm.Stack, contract *vm.Contract, depth int, err error) error {
|
if jst.err != nil {
|
||||||
if jst.err == nil {
|
return
|
||||||
|
}
|
||||||
// Apart from the error, everything matches the previous invocation
|
// Apart from the error, everything matches the previous invocation
|
||||||
jst.errorValue = new(string)
|
jst.errorValue = new(string)
|
||||||
*jst.errorValue = err.Error()
|
*jst.errorValue = err.Error()
|
||||||
|
|
||||||
_, err := jst.call("fault", "log", "db")
|
if _, err := jst.call("fault", "log", "db"); err != nil {
|
||||||
if err != nil {
|
|
||||||
jst.err = wrapError("fault", err)
|
jst.err = wrapError("fault", err)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CaptureEnd is called after the call finishes to finalize the tracing.
|
// CaptureEnd is called after the call finishes to finalize the tracing.
|
||||||
func (jst *Tracer) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) error {
|
func (jst *Tracer) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) {
|
||||||
jst.ctx["output"] = output
|
jst.ctx["output"] = output
|
||||||
jst.ctx["time"] = t.String()
|
jst.ctx["time"] = t.String()
|
||||||
jst.ctx["gasUsed"] = gasUsed
|
jst.ctx["gasUsed"] = gasUsed
|
||||||
@ -618,7 +606,6 @@ func (jst *Tracer) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, er
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
jst.ctx["error"] = err.Error()
|
jst.ctx["error"] = err.Error()
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetResult calls the Javascript 'result' function and returns its value, or any accumulated error
|
// GetResult calls the Javascript 'result' function and returns its value, or any accumulated error
|
||||||
|
@ -48,6 +48,7 @@ type dummyStatedb struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (*dummyStatedb) GetRefund() uint64 { return 1337 }
|
func (*dummyStatedb) GetRefund() uint64 { return 1337 }
|
||||||
|
func (*dummyStatedb) GetBalance(addr common.Address) *big.Int { return new(big.Int) }
|
||||||
|
|
||||||
type vmContext struct {
|
type vmContext struct {
|
||||||
blockCtx vm.BlockContext
|
blockCtx vm.BlockContext
|
||||||
@ -67,7 +68,7 @@ func runTrace(tracer *Tracer, vmctx *vmContext) (json.RawMessage, error) {
|
|||||||
contract := vm.NewContract(account{}, account{}, value, startGas)
|
contract := vm.NewContract(account{}, account{}, value, startGas)
|
||||||
contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x1, 0x0}
|
contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x1, 0x0}
|
||||||
|
|
||||||
tracer.CaptureStart(contract.Caller(), contract.Address(), false, []byte{}, startGas, value)
|
tracer.CaptureStart(env, contract.Caller(), contract.Address(), false, []byte{}, startGas, value)
|
||||||
ret, err := env.Interpreter().Run(contract, []byte{}, false)
|
ret, err := env.Interpreter().Run(contract, []byte{}, false)
|
||||||
tracer.CaptureEnd(ret, startGas-contract.Gas, 1, err)
|
tracer.CaptureEnd(ret, startGas-contract.Gas, 1, err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -150,14 +151,55 @@ func TestHaltBetweenSteps(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Debug: true, Tracer: tracer})
|
env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Debug: true, Tracer: tracer})
|
||||||
contract := vm.NewContract(&account{}, &account{}, big.NewInt(0), 0)
|
scope := &vm.ScopeContext{
|
||||||
|
Contract: vm.NewContract(&account{}, &account{}, big.NewInt(0), 0),
|
||||||
|
}
|
||||||
|
|
||||||
tracer.CaptureState(env, 0, 0, 0, 0, nil, nil, nil, contract, 0, nil)
|
tracer.CaptureState(env, 0, 0, 0, 0, scope, nil, 0, nil)
|
||||||
timeout := errors.New("stahp")
|
timeout := errors.New("stahp")
|
||||||
tracer.Stop(timeout)
|
tracer.Stop(timeout)
|
||||||
tracer.CaptureState(env, 0, 0, 0, 0, nil, nil, nil, contract, 0, nil)
|
tracer.CaptureState(env, 0, 0, 0, 0, scope, nil, 0, nil)
|
||||||
|
|
||||||
if _, err := tracer.GetResult(); err.Error() != timeout.Error() {
|
if _, err := tracer.GetResult(); err.Error() != timeout.Error() {
|
||||||
t.Errorf("Expected timeout error, got %v", err)
|
t.Errorf("Expected timeout error, got %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestNoStepExec tests a regular value transfer (no exec), and accessing the statedb
|
||||||
|
// in 'result'
|
||||||
|
func TestNoStepExec(t *testing.T) {
|
||||||
|
runEmptyTrace := func(tracer *Tracer, vmctx *vmContext) (json.RawMessage, error) {
|
||||||
|
env := vm.NewEVM(vmctx.blockCtx, vmctx.txCtx, &dummyStatedb{}, params.TestChainConfig, vm.Config{Debug: true, Tracer: tracer})
|
||||||
|
startGas := uint64(10000)
|
||||||
|
contract := vm.NewContract(account{}, account{}, big.NewInt(0), startGas)
|
||||||
|
tracer.CaptureStart(env, contract.Caller(), contract.Address(), false, []byte{}, startGas, big.NewInt(0))
|
||||||
|
tracer.CaptureEnd(nil, startGas-contract.Gas, 1, nil)
|
||||||
|
return tracer.GetResult()
|
||||||
|
}
|
||||||
|
execTracer := func(code string) []byte {
|
||||||
|
t.Helper()
|
||||||
|
ctx := &vmContext{blockCtx: vm.BlockContext{BlockNumber: big.NewInt(1)}, txCtx: vm.TxContext{GasPrice: big.NewInt(100000)}}
|
||||||
|
tracer, err := New(code, ctx.txCtx)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
ret, err := runEmptyTrace(tracer, ctx)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
for i, tt := range []struct {
|
||||||
|
code string
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{ // tests that we don't panic on accessing the db methods
|
||||||
|
code: "{depths: [], step: function() {}, fault: function() {}, result: function(ctx, db){ return db.getBalance(ctx.to)} }",
|
||||||
|
want: `"0"`,
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
if have := execTracer(tt.code); tt.want != string(have) {
|
||||||
|
t.Errorf("testcase %d: expected return value to be %s got %s\n\tcode: %v", i, tt.want, string(have), tt.code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user