mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-02-03 07:45:18 +00:00
Initial TransactionTracer impl
This commit is contained in:
parent
5095bfa8d8
commit
bac452f589
@ -11,7 +11,7 @@ import
|
||||
./interpreter/[opcode_values, opcodes_impl, vm_forks, gas_costs, gas_meter, utils/macros_gen_opcodes],
|
||||
./code_stream,
|
||||
../vm_types, ../errors,
|
||||
./stack, ./computation, terminal # Those are only needed for logging
|
||||
./stack, ./computation, ./transaction_tracer, terminal # Those are only needed for logging
|
||||
|
||||
func invalidInstruction*(computation: var BaseComputation) {.inline.} =
|
||||
raise newException(ValueError, "Invalid instruction, received an opcode not implemented in the current fork.")
|
||||
@ -191,12 +191,20 @@ proc opTableToCaseStmt(opTable: array[Op, NimNode], computation: NimNode): NimNo
|
||||
let asOp = quote do: Op(`op`) # TODO: unfortunately when passing to runtime, ops are transformed into int
|
||||
if BaseGasCosts[op].kind == GckFixed:
|
||||
quote do:
|
||||
if `computation`.tracingEnabled:
|
||||
`computation`.tracer.traceOpCodeStarted(`computation`, $`asOp`)
|
||||
`computation`.gasMeter.consumeGas(`computation`.gasCosts[`asOp`].cost, reason = $`asOp`)
|
||||
`opImpl`(`computation`)
|
||||
if `computation`.tracingEnabled:
|
||||
`computation`.tracer.traceOpCodeEnded(`computation`)
|
||||
`instr` = `computation`.code.next()
|
||||
else:
|
||||
quote do:
|
||||
if `computation`.tracingEnabled:
|
||||
`computation`.tracer.traceOpCodeStarted(`computation`, $`asOp`)
|
||||
`opImpl`(`computation`)
|
||||
if `computation`.tracingEnabled:
|
||||
`computation`.tracer.traceOpCodeEnded(`computation`)
|
||||
when `asOp` in {Return, Revert, SelfDestruct}:
|
||||
break
|
||||
else:
|
||||
|
40
nimbus/vm/transaction_tracer.nim
Normal file
40
nimbus/vm/transaction_tracer.nim
Normal file
@ -0,0 +1,40 @@
|
||||
import
|
||||
json, strutils,
|
||||
eth_common, stint, byteutils,
|
||||
../vm_types, memory, stack
|
||||
|
||||
proc initTrace(t: var TransactionTracer) =
|
||||
t.trace = newJObject()
|
||||
t.trace["structLogs"] = newJArray()
|
||||
|
||||
proc traceOpCodeStarted*(t: var TransactionTracer, c: BaseComputation, op: string) =
|
||||
if unlikely t.trace.isNil:
|
||||
t.initTrace()
|
||||
|
||||
let j = newJObject()
|
||||
t.trace["structLogs"].add(j)
|
||||
|
||||
j["op"] = %op.toUpperAscii
|
||||
j["pc"] = %(c.code.pc - 1)
|
||||
j["depth"] = %1 # stub
|
||||
j["gas"] = %c.gasMeter.gasRemaining
|
||||
t.gasRemaining = c.gasMeter.gasRemaining
|
||||
|
||||
# log stack
|
||||
let st = newJArray()
|
||||
for v in c.stack.values:
|
||||
st.add(%v.dumpHex())
|
||||
j["stack"] = st
|
||||
# log memory
|
||||
let mem = newJArray()
|
||||
const chunkLen = 32
|
||||
let numChunks = c.memory.len div chunkLen
|
||||
for i in 0 ..< numChunks:
|
||||
mem.add(%c.memory.bytes.toOpenArray(i * chunkLen, (i + 1) * chunkLen - 1).toHex())
|
||||
j["memory"] = mem
|
||||
# TODO: log storage
|
||||
|
||||
proc traceOpCodeEnded*(t: var TransactionTracer, c: BaseComputation) =
|
||||
let j = t.trace["structLogs"].elems[^1]
|
||||
j["gasCost"] = %(t.gasRemaining - c.gasMeter.gasRemaining)
|
||||
|
@ -6,7 +6,7 @@
|
||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
tables,
|
||||
tables, json,
|
||||
eth_common,
|
||||
./constants, ./vm_state,
|
||||
./vm/[memory, stack, code_stream],
|
||||
@ -35,6 +35,8 @@ type
|
||||
precompiles*: Table[string, Opcode]
|
||||
gasCosts*: GasCosts # TODO - will be hidden at a lower layer
|
||||
opCodeExec*: OpcodeExecutor
|
||||
tracingEnabled*: bool
|
||||
tracer*: TransactionTracer
|
||||
|
||||
Error* = ref object
|
||||
info*: string
|
||||
@ -105,3 +107,8 @@ type
|
||||
createAddress*: EthAddress
|
||||
codeAddress*: EthAddress
|
||||
flags*: MsgFlags
|
||||
|
||||
TransactionTracer* = object
|
||||
trace*: JsonNode
|
||||
gasRemaining*: GasInt
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user