|
|
|
@ -200,19 +200,18 @@ func (c *contractWrapper) toValue(vm *otto.Otto) otto.Value { |
|
|
|
|
// JavascriptTracer provides an implementation of Tracer that evaluates a
|
|
|
|
|
// Javascript function for each VM execution step.
|
|
|
|
|
type JavascriptTracer struct { |
|
|
|
|
vm *otto.Otto // Javascript VM instance
|
|
|
|
|
traceobj *otto.Object // User-supplied object to call
|
|
|
|
|
log map[string]interface{} // (Reusable) map for the `log` arg to `step`
|
|
|
|
|
logvalue otto.Value // JS view of `log`
|
|
|
|
|
memory *memoryWrapper // Wrapper around the VM memory
|
|
|
|
|
memvalue otto.Value // JS view of `memory`
|
|
|
|
|
stack *stackWrapper // Wrapper around the VM stack
|
|
|
|
|
stackvalue otto.Value // JS view of `stack`
|
|
|
|
|
db *dbWrapper // Wrapper around the VM environment
|
|
|
|
|
dbvalue otto.Value // JS view of `db`
|
|
|
|
|
contract *contractWrapper // Wrapper around the contract object
|
|
|
|
|
contractvalue otto.Value // JS view of `contract`
|
|
|
|
|
err error // Error, if one has occurred
|
|
|
|
|
vm *otto.Otto // Javascript VM instance
|
|
|
|
|
traceobj *otto.Object // User-supplied object to call
|
|
|
|
|
op *opCodeWrapper // Wrapper around the VM opcode
|
|
|
|
|
log map[string]interface{} // (Reusable) map for the `log` arg to `step`
|
|
|
|
|
logvalue otto.Value // JS view of `log`
|
|
|
|
|
memory *memoryWrapper // Wrapper around the VM memory
|
|
|
|
|
stack *stackWrapper // Wrapper around the VM stack
|
|
|
|
|
db *dbWrapper // Wrapper around the VM environment
|
|
|
|
|
dbvalue otto.Value // JS view of `db`
|
|
|
|
|
contract *contractWrapper // Wrapper around the contract object
|
|
|
|
|
err error // Error, if one has occurred
|
|
|
|
|
result interface{} // Final result to return to the user
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// NewJavascriptTracer instantiates a new JavascriptTracer instance.
|
|
|
|
@ -230,7 +229,6 @@ func NewJavascriptTracer(code string) (*JavascriptTracer, error) { |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Check the required functions exist
|
|
|
|
|
step, err := jstracer.Get("step") |
|
|
|
|
if err != nil { |
|
|
|
@ -247,31 +245,34 @@ func NewJavascriptTracer(code string) (*JavascriptTracer, error) { |
|
|
|
|
if !result.IsFunction() { |
|
|
|
|
return nil, fmt.Errorf("Trace object must expose a function result()") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Create the persistent log object
|
|
|
|
|
log := make(map[string]interface{}) |
|
|
|
|
var ( |
|
|
|
|
op = new(opCodeWrapper) |
|
|
|
|
mem = new(memoryWrapper) |
|
|
|
|
stack = new(stackWrapper) |
|
|
|
|
db = new(dbWrapper) |
|
|
|
|
contract = new(contractWrapper) |
|
|
|
|
) |
|
|
|
|
log := map[string]interface{}{ |
|
|
|
|
"op": op.toValue(vm), |
|
|
|
|
"memory": mem.toValue(vm), |
|
|
|
|
"stack": stack.toValue(vm), |
|
|
|
|
"contract": contract.toValue(vm), |
|
|
|
|
} |
|
|
|
|
logvalue, _ := vm.ToValue(log) |
|
|
|
|
|
|
|
|
|
// Create persistent wrappers for memory and stack
|
|
|
|
|
mem := &memoryWrapper{} |
|
|
|
|
stack := &stackWrapper{} |
|
|
|
|
db := &dbWrapper{} |
|
|
|
|
contract := &contractWrapper{} |
|
|
|
|
|
|
|
|
|
return &JavascriptTracer{ |
|
|
|
|
vm: vm, |
|
|
|
|
traceobj: jstracer, |
|
|
|
|
log: log, |
|
|
|
|
logvalue: logvalue, |
|
|
|
|
memory: mem, |
|
|
|
|
memvalue: mem.toValue(vm), |
|
|
|
|
stack: stack, |
|
|
|
|
stackvalue: stack.toValue(vm), |
|
|
|
|
db: db, |
|
|
|
|
dbvalue: db.toValue(vm), |
|
|
|
|
contract: contract, |
|
|
|
|
contractvalue: contract.toValue(vm), |
|
|
|
|
err: nil, |
|
|
|
|
vm: vm, |
|
|
|
|
traceobj: jstracer, |
|
|
|
|
op: op, |
|
|
|
|
log: log, |
|
|
|
|
logvalue: logvalue, |
|
|
|
|
memory: mem, |
|
|
|
|
stack: stack, |
|
|
|
|
db: db, |
|
|
|
|
dbvalue: db.toValue(vm), |
|
|
|
|
contract: contract, |
|
|
|
|
err: nil, |
|
|
|
|
}, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -319,24 +320,22 @@ func wrapError(context string, err error) error { |
|
|
|
|
// CaptureState implements the Tracer interface to trace a single step of VM execution
|
|
|
|
|
func (jst *JavascriptTracer) CaptureState(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 { |
|
|
|
|
jst.op.op = op |
|
|
|
|
jst.memory.memory = memory |
|
|
|
|
jst.stack.stack = stack |
|
|
|
|
jst.db.db = env.StateDB |
|
|
|
|
jst.contract.contract = contract |
|
|
|
|
|
|
|
|
|
ocw := &opCodeWrapper{op} |
|
|
|
|
|
|
|
|
|
jst.log["pc"] = pc |
|
|
|
|
jst.log["op"] = ocw.toValue(jst.vm) |
|
|
|
|
jst.log["gas"] = gas |
|
|
|
|
jst.log["gasPrice"] = cost |
|
|
|
|
jst.log["memory"] = jst.memvalue |
|
|
|
|
jst.log["stack"] = jst.stackvalue |
|
|
|
|
jst.log["contract"] = jst.contractvalue |
|
|
|
|
jst.log["cost"] = cost |
|
|
|
|
jst.log["depth"] = depth |
|
|
|
|
jst.log["account"] = contract.Address() |
|
|
|
|
jst.log["err"] = err |
|
|
|
|
|
|
|
|
|
delete(jst.log, "error") |
|
|
|
|
if err != nil { |
|
|
|
|
jst.log["error"] = err |
|
|
|
|
} |
|
|
|
|
_, err := jst.callSafely("step", jst.logvalue, jst.dbvalue) |
|
|
|
|
if err != nil { |
|
|
|
|
jst.err = wrapError("step", err) |
|
|
|
|