diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 1bc0e80dfc44..a38ea8fdc955 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -148,6 +148,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( logged bool // deferred EVMLogger should ignore already logged steps res []byte // result of the opcode execution function debug = in.evm.Config.Tracer != nil + witness uint64 ) // Don't move this deferred function, it's placed before the capturestate-deferred method, // so that it get's executed _after_: the capturestate needs the stacks before @@ -161,9 +162,9 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( defer func() { if err != nil { if !logged { - in.evm.Config.Tracer.CaptureState(pcCopy, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err) + in.evm.Config.Tracer.CaptureState(pcCopy, op, gasCopy, cost, 0, callContext, in.returnData, in.evm.depth, err) } else { - in.evm.Config.Tracer.CaptureFault(pcCopy, op, gasCopy, cost, callContext, in.evm.depth, err) + in.evm.Config.Tracer.CaptureFault(pcCopy, op, gasCopy, cost, 0, callContext, in.evm.depth, err) } } }() @@ -176,14 +177,16 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( for { if debug { // Capture pre-execution values for tracing. - logged, pcCopy, gasCopy = false, pc, contract.Gas + logged, pcCopy, gasCopy, witness = false, pc, contract.Gas, 0 } if in.evm.chainRules.IsPrague && !contract.IsDeployment { // if the PC ends up in a new "chunk" of verkleized code, charge the // associated costs. contractAddr := contract.Address() - contract.Gas -= touchCodeChunksRangeOnReadAndChargeGas(contractAddr[:], pc, 1, uint64(len(contract.Code)), in.evm.TxContext.Accesses) + w := touchCodeChunksRangeOnReadAndChargeGas(contractAddr[:], pc, 1, uint64(len(contract.Code)), in.evm.TxContext.Accesses) + contract.Gas -= w + witness += w } // Get the operation from the jump table and validate the stack to ensure there are @@ -228,14 +231,14 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( } // Do tracing before memory expansion if debug { - in.evm.Config.Tracer.CaptureState(pc, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err) + in.evm.Config.Tracer.CaptureState(pc, op, gasCopy, cost, witness, callContext, in.returnData, in.evm.depth, err) logged = true } if memorySize > 0 { mem.Resize(memorySize) } } else if debug { - in.evm.Config.Tracer.CaptureState(pc, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err) + in.evm.Config.Tracer.CaptureState(pc, op, gasCopy, cost, witness, callContext, in.returnData, in.evm.depth, err) logged = true } // execute the operation diff --git a/core/vm/logger.go b/core/vm/logger.go index 2667908a84d1..0a09c8bbfb26 100644 --- a/core/vm/logger.go +++ b/core/vm/logger.go @@ -38,6 +38,6 @@ type EVMLogger interface { CaptureEnter(typ OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) CaptureExit(output []byte, gasUsed uint64, err error) // Opcode level - CaptureState(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) - CaptureFault(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, depth int, err error) + CaptureState(pc uint64, op OpCode, gas, cost, witness uint64, scope *ScopeContext, rData []byte, depth int, err error) + CaptureFault(pc uint64, op OpCode, gas, cost, witness uint64, scope *ScopeContext, depth int, err error) } diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index f3d63df8ed5d..f963f9b08519 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -250,7 +250,7 @@ func (t *jsTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Addr } // CaptureState implements the Tracer interface to trace a single step of VM execution. -func (t *jsTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { +func (t *jsTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost, _ uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { if !t.traceStep { return } @@ -275,7 +275,7 @@ func (t *jsTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope } // CaptureFault implements the Tracer interface to trace an execution fault -func (t *jsTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) { +func (t *jsTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost, _ uint64, scope *vm.ScopeContext, depth int, err error) { if t.err != nil { return } diff --git a/eth/tracers/logger/access_list_tracer.go b/eth/tracers/logger/access_list_tracer.go index 766ee4e4b95c..d9d15767e77a 100644 --- a/eth/tracers/logger/access_list_tracer.go +++ b/eth/tracers/logger/access_list_tracer.go @@ -136,7 +136,7 @@ func (a *AccessListTracer) CaptureStart(env *vm.EVM, from common.Address, to com } // CaptureState captures all opcodes that touch storage or addresses and adds them to the accesslist. -func (a *AccessListTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { +func (a *AccessListTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost, _ uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { stack := scope.Stack stackData := stack.Data() stackLen := len(stackData) @@ -158,7 +158,7 @@ func (a *AccessListTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint6 } } -func (*AccessListTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) { +func (*AccessListTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost, _ uint64, scope *vm.ScopeContext, depth int, err error) { } func (*AccessListTracer) CaptureEnd(output []byte, gasUsed uint64, err error) {} diff --git a/eth/tracers/logger/gen_structlog.go b/eth/tracers/logger/gen_structlog.go index df06a9ee6b66..c77c43410ea3 100644 --- a/eth/tracers/logger/gen_structlog.go +++ b/eth/tracers/logger/gen_structlog.go @@ -21,6 +21,7 @@ func (s StructLog) MarshalJSON() ([]byte, error) { Op vm.OpCode `json:"op"` Gas math.HexOrDecimal64 `json:"gas"` GasCost math.HexOrDecimal64 `json:"gasCost"` + WitnessCost math.HexOrDecimal64 `json:"witnessCost"` Memory hexutil.Bytes `json:"memory,omitempty"` MemorySize int `json:"memSize"` Stack []uint256.Int `json:"stack"` @@ -37,6 +38,7 @@ func (s StructLog) MarshalJSON() ([]byte, error) { enc.Op = s.Op enc.Gas = math.HexOrDecimal64(s.Gas) enc.GasCost = math.HexOrDecimal64(s.GasCost) + enc.WitnessCost = math.HexOrDecimal64(s.WitnessCost) enc.Memory = s.Memory enc.MemorySize = s.MemorySize enc.Stack = s.Stack @@ -57,6 +59,7 @@ func (s *StructLog) UnmarshalJSON(input []byte) error { Op *vm.OpCode `json:"op"` Gas *math.HexOrDecimal64 `json:"gas"` GasCost *math.HexOrDecimal64 `json:"gasCost"` + WitnessCost *math.HexOrDecimal64 `json:"witnessCost"` Memory *hexutil.Bytes `json:"memory,omitempty"` MemorySize *int `json:"memSize"` Stack []uint256.Int `json:"stack"` @@ -82,6 +85,9 @@ func (s *StructLog) UnmarshalJSON(input []byte) error { if dec.GasCost != nil { s.GasCost = uint64(*dec.GasCost) } + if dec.WitnessCost != nil { + s.WitnessCost = uint64(*dec.WitnessCost) + } if dec.Memory != nil { s.Memory = *dec.Memory } diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index 4c9b910a27f1..e73a74580420 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -67,6 +67,7 @@ type StructLog struct { Op vm.OpCode `json:"op"` Gas uint64 `json:"gas"` GasCost uint64 `json:"gasCost"` + WitnessCost uint64 `json:"witnessCost"` Memory []byte `json:"memory,omitempty"` MemorySize int `json:"memSize"` Stack []uint256.Int `json:"stack"` @@ -81,6 +82,7 @@ type StructLog struct { type structLogMarshaling struct { Gas math.HexOrDecimal64 GasCost math.HexOrDecimal64 + WitnessCost math.HexOrDecimal64 Memory hexutil.Bytes ReturnData hexutil.Bytes OpName string `json:"opName"` // adds call to OpName() in MarshalJSON @@ -147,7 +149,7 @@ func (l *StructLogger) CaptureStart(env *vm.EVM, from common.Address, to common. // CaptureState logs a new structured log message and pushes it out to the environment // // CaptureState also tracks SLOAD/SSTORE ops to track storage change. -func (l *StructLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { +func (l *StructLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost, witness uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { // If tracing was interrupted, set the error and stop if l.interrupt.Load() { return @@ -208,13 +210,13 @@ func (l *StructLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, s copy(rdata, rData) } // create a new snapshot of the EVM. - log := StructLog{pc, op, gas, cost, mem, memory.Len(), stck, rdata, storage, depth, l.env.StateDB.GetRefund(), err} + log := StructLog{pc, op, gas, cost, witness, mem, memory.Len(), stck, rdata, storage, depth, l.env.StateDB.GetRefund(), err} l.logs = append(l.logs, log) } // CaptureFault implements the EVMLogger interface to trace an execution fault // while running an opcode. -func (l *StructLogger) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) { +func (l *StructLogger) CaptureFault(pc uint64, op vm.OpCode, gas, cost, _ uint64, scope *vm.ScopeContext, depth int, err error) { } // CaptureEnd is called after the call finishes to finalize the tracing. @@ -360,7 +362,7 @@ func (t *mdLogger) CaptureStart(env *vm.EVM, from common.Address, to common.Addr } // CaptureState also tracks SLOAD/SSTORE ops to track storage change. -func (t *mdLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { +func (t *mdLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost, _ uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { stack := scope.Stack fmt.Fprintf(t.out, "| %4d | %10v | %3d |", pc, op, cost) @@ -380,7 +382,7 @@ func (t *mdLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope } } -func (t *mdLogger) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) { +func (t *mdLogger) CaptureFault(pc uint64, op vm.OpCode, gas, cost, _ uint64, scope *vm.ScopeContext, depth int, err error) { fmt.Fprintf(t.out, "\nError: at pc=%d, op=%v: %v\n", pc, op, err) } diff --git a/eth/tracers/logger/logger_json.go b/eth/tracers/logger/logger_json.go index a2cb4cd9fc59..b77ebb952dd3 100644 --- a/eth/tracers/logger/logger_json.go +++ b/eth/tracers/logger/logger_json.go @@ -46,13 +46,13 @@ func (l *JSONLogger) CaptureStart(env *vm.EVM, from, to common.Address, create b l.env = env } -func (l *JSONLogger) CaptureFault(pc uint64, op vm.OpCode, gas uint64, cost uint64, scope *vm.ScopeContext, depth int, err error) { +func (l *JSONLogger) CaptureFault(pc uint64, op vm.OpCode, gas uint64, cost, witness uint64, scope *vm.ScopeContext, depth int, err error) { // TODO: Add rData to this interface as well - l.CaptureState(pc, op, gas, cost, scope, nil, depth, err) + l.CaptureState(pc, op, gas, cost, witness, scope, nil, depth, err) } // CaptureState outputs state information on the logger. -func (l *JSONLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { +func (l *JSONLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost, witness uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { memory := scope.Memory stack := scope.Stack @@ -61,6 +61,7 @@ func (l *JSONLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, sco Op: op, Gas: gas, GasCost: cost, + WitnessCost: witness, MemorySize: memory.Len(), Depth: depth, RefundCounter: l.env.StateDB.GetRefund(), diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index 34cf027acacf..e5eef1780470 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -148,7 +148,7 @@ func (t *callTracer) CaptureEnd(output []byte, gasUsed uint64, err error) { } // CaptureState implements the EVMLogger interface to trace a single step of VM execution. -func (t *callTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { +func (t *callTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost, _ uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { // skip if the previous op caused an error if err != nil { return diff --git a/eth/tracers/native/call_flat.go b/eth/tracers/native/call_flat.go index 266ab9900146..7c005279e170 100644 --- a/eth/tracers/native/call_flat.go +++ b/eth/tracers/native/call_flat.go @@ -157,13 +157,13 @@ func (t *flatCallTracer) CaptureEnd(output []byte, gasUsed uint64, err error) { } // CaptureState implements the EVMLogger interface to trace a single step of VM execution. -func (t *flatCallTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { - t.tracer.CaptureState(pc, op, gas, cost, scope, rData, depth, err) +func (t *flatCallTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost, witness uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { + t.tracer.CaptureState(pc, op, gas, cost, witness, scope, rData, depth, err) } // CaptureFault implements the EVMLogger interface to trace an execution fault. -func (t *flatCallTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) { - t.tracer.CaptureFault(pc, op, gas, cost, scope, depth, err) +func (t *flatCallTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost, witness uint64, scope *vm.ScopeContext, depth int, err error) { + t.tracer.CaptureFault(pc, op, gas, cost, witness, scope, depth, err) } // CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). diff --git a/eth/tracers/native/mux.go b/eth/tracers/native/mux.go index db8ddd64380d..ee454d0396e3 100644 --- a/eth/tracers/native/mux.go +++ b/eth/tracers/native/mux.go @@ -73,16 +73,16 @@ func (t *muxTracer) CaptureEnd(output []byte, gasUsed uint64, err error) { } // CaptureState implements the EVMLogger interface to trace a single step of VM execution. -func (t *muxTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { +func (t *muxTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost, witness uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { for _, t := range t.tracers { - t.CaptureState(pc, op, gas, cost, scope, rData, depth, err) + t.CaptureState(pc, op, gas, cost, witness, scope, rData, depth, err) } } // CaptureFault implements the EVMLogger interface to trace an execution fault. -func (t *muxTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) { +func (t *muxTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost, witness uint64, scope *vm.ScopeContext, depth int, err error) { for _, t := range t.tracers { - t.CaptureFault(pc, op, gas, cost, scope, depth, err) + t.CaptureFault(pc, op, gas, cost, witness, scope, depth, err) } } diff --git a/eth/tracers/native/noop.go b/eth/tracers/native/noop.go index 3beecd8abfed..3f153ce58bea 100644 --- a/eth/tracers/native/noop.go +++ b/eth/tracers/native/noop.go @@ -47,11 +47,11 @@ func (t *noopTracer) CaptureEnd(output []byte, gasUsed uint64, err error) { } // CaptureState implements the EVMLogger interface to trace a single step of VM execution. -func (t *noopTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { +func (t *noopTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost, witness uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { } // CaptureFault implements the EVMLogger interface to trace an execution fault. -func (t *noopTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, _ *vm.ScopeContext, depth int, err error) { +func (t *noopTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost, _ uint64, _ *vm.ScopeContext, depth int, err error) { } // CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index 82451c40a65f..7f5a68ce8a1b 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -133,7 +133,7 @@ func (t *prestateTracer) CaptureEnd(output []byte, gasUsed uint64, err error) { } // CaptureState implements the EVMLogger interface to trace a single step of VM execution. -func (t *prestateTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { +func (t *prestateTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost, _ uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { if err != nil { return }