From 673007d7aed1d2678ea3277eceb7b55dc29cf092 Mon Sep 17 00:00:00 2001
From: cdetrio <cdetrio@gmail.com>
Date: Fri, 22 Sep 2017 04:22:56 -0400
Subject: [PATCH] core/vm: standard vm traces (#15035)

---
 cmd/evm/json_logger.go |  2 +-
 core/vm/interpreter.go | 22 +++++++++++++++++++---
 2 files changed, 20 insertions(+), 4 deletions(-)

diff --git a/cmd/evm/json_logger.go b/cmd/evm/json_logger.go
index 2cfeaa795..eb7b0c466 100644
--- a/cmd/evm/json_logger.go
+++ b/cmd/evm/json_logger.go
@@ -40,7 +40,7 @@ func (l *JSONLogger) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode, gas, cos
 	log := vm.StructLog{
 		Pc:         pc,
 		Op:         op,
-		Gas:        gas + cost,
+		Gas:        gas,
 		GasCost:    cost,
 		MemorySize: memory.Len(),
 		Storage:    nil,
diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go
index b0d796a44..94b922c79 100644
--- a/core/vm/interpreter.go
+++ b/core/vm/interpreter.go
@@ -137,12 +137,17 @@ func (in *Interpreter) Run(snapshot int, contract *Contract, input []byte) (ret
 		// to be uint256. Practically much less so feasible.
 		pc   = uint64(0) // program counter
 		cost uint64
+		// copies used by tracer
+		stackCopy = newstack() // stackCopy needed for Tracer since stack is mutated by 63/64 gas rule 
+		pcCopy uint64 // needed for the deferred Tracer
+		gasCopy uint64 // for Tracer to log gas remaining before execution
+		logged bool // deferred Tracer should ignore already logged steps
 	)
 	contract.Input = input
 
 	defer func() {
-		if err != nil && in.cfg.Debug {
-			in.cfg.Tracer.CaptureState(in.evm, pc, op, contract.Gas, cost, mem, stack, contract, in.evm.depth, err)
+		if err != nil && !logged && in.cfg.Debug {
+			in.cfg.Tracer.CaptureState(in.evm, pcCopy, op, gasCopy, cost, mem, stackCopy, contract, in.evm.depth, err)
 		}
 	}()
 
@@ -154,6 +159,16 @@ func (in *Interpreter) Run(snapshot int, contract *Contract, input []byte) (ret
 		// Get the memory location of pc
 		op = contract.GetOp(pc)
 
+		if in.cfg.Debug {
+			logged = false
+			pcCopy = uint64(pc)
+			gasCopy = uint64(contract.Gas)
+			stackCopy = newstack()
+			for _, val := range stack.data {
+				stackCopy.push(val)
+			}
+		}
+
 		// get the operation from the jump table matching the opcode
 		operation := in.cfg.JumpTable[op]
 		if err := in.enforceRestrictions(op, operation, stack); err != nil {
@@ -199,7 +214,8 @@ func (in *Interpreter) Run(snapshot int, contract *Contract, input []byte) (ret
 		}
 
 		if in.cfg.Debug {
-			in.cfg.Tracer.CaptureState(in.evm, pc, op, contract.Gas, cost, mem, stack, contract, in.evm.depth, err)
+			in.cfg.Tracer.CaptureState(in.evm, pc, op, gasCopy, cost, mem, stackCopy, contract, in.evm.depth, err)
+			logged = true
 		}
 
 		// execute the operation
-- 
GitLab