From 989fb4472a25a9b92cba95150c97719761c7ed1d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= <peterke@gmail.com>
Date: Fri, 24 Nov 2017 13:50:14 +0200
Subject: [PATCH] internal/ethapi: avoid recreating JavaScript tracer wrappers

---
 internal/ethapi/tracer.go | 85 +++++++++++++++++++--------------------
 1 file changed, 42 insertions(+), 43 deletions(-)

diff --git a/internal/ethapi/tracer.go b/internal/ethapi/tracer.go
index fc742e6c4..71cafc6e9 100644
--- a/internal/ethapi/tracer.go
+++ b/internal/ethapi/tracer.go
@@ -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)
-- 
GitLab