internal/ethapi: avoid recreating JavaScript tracer wrappers

This commit is contained in:
Péter Szilágyi 2017-11-24 13:50:14 +02:00
parent 9ff9d04a69
commit 989fb4472a
No known key found for this signature in database
GPG Key ID: E9AE538CEDF8293D

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