|
|
@@ -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)
|