nimbus-eth1/nimbus/vm/transaction_tracer.nim

73 lines
2.3 KiB
Nim
Raw Normal View History

2018-10-28 12:11:19 +00:00
import
2018-12-04 08:53:03 +00:00
json, strutils, nimcrypto, eth_common, stint,
../vm_types, memory, stack, ../db/[db_chain, state_db],
eth_trie/hexary, ./message, ranges/typedranges
2018-10-28 12:11:19 +00:00
2018-12-03 10:54:19 +00:00
proc initTracer*(tracer: var TransactionTracer, flags: set[TracerFlags] = {}) =
tracer.trace = newJObject()
2018-12-03 16:22:08 +00:00
# make appear at the top of json object
tracer.trace["gas"] = %0
tracer.trace["failed"] = %false
tracer.trace["returnValue"] = %""
2018-12-03 10:54:19 +00:00
tracer.trace["structLogs"] = newJArray()
tracer.flags = flags
2018-10-28 12:11:19 +00:00
2018-12-03 10:54:19 +00:00
proc traceOpCodeStarted*(tracer: var TransactionTracer, c: BaseComputation, op: string) =
if unlikely tracer.trace.isNil:
tracer.initTracer()
2018-10-28 12:11:19 +00:00
let j = newJObject()
2018-12-03 10:54:19 +00:00
tracer.trace["structLogs"].add(j)
2018-10-28 12:11:19 +00:00
j["op"] = %op.toUpperAscii
j["pc"] = %(c.code.pc - 1)
j["depth"] = %1 # stub
j["gas"] = %c.gasMeter.gasRemaining
2018-12-03 10:54:19 +00:00
tracer.gasRemaining = c.gasMeter.gasRemaining
2018-10-28 12:11:19 +00:00
# log stack
2018-12-03 10:54:19 +00:00
if TracerFlags.DisableStack notin tracer.flags:
let st = newJArray()
for v in c.stack.values:
st.add(%v.dumpHex())
j["stack"] = st
2018-10-28 12:11:19 +00:00
# log memory
2018-12-03 10:54:19 +00:00
if TracerFlags.DisableMemory notin tracer.flags:
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
2018-10-28 12:11:19 +00:00
2018-12-04 08:13:35 +00:00
proc traceOpCodeEnded*(tracer: var TransactionTracer, c: BaseComputation) =
let j = tracer.trace["structLogs"].elems[^1]
2018-12-03 16:22:08 +00:00
# TODO: figure out how to get storage
# when contract excecution interrupted by exception
2018-12-03 10:54:19 +00:00
if TracerFlags.DisableStorage notin tracer.flags:
2018-12-03 16:22:08 +00:00
var storage = newJObject()
var stateDB = c.vmState.chaindb.getStateDb(c.vmState.blockHeader.stateRoot, readOnly = true)
2018-12-04 08:13:35 +00:00
for key, value in stateDB.storage(c.msg.storageAddress):
storage[key.dumpHex] = %(value.dumpHex)
2018-12-03 10:54:19 +00:00
j["storage"] = storage
2018-10-28 12:11:19 +00:00
2018-12-03 10:54:19 +00:00
j["gasCost"] = %(tracer.gasRemaining - c.gasMeter.gasRemaining)
2018-12-03 16:22:08 +00:00
2018-12-04 08:53:03 +00:00
if c.lastOpCodeHasRetVal:
j["returnValue"] = %("0x" & toHex(c.rawOutput, true))
2018-12-03 16:22:08 +00:00
proc traceError*(tracer: var TransactionTracer, c: BaseComputation) =
let j = tracer.trace["structLogs"].elems[^1]
# TODO: figure out how to get gasCost
# when contract execution failed before traceOpCodeEnded called
# because exception raised
#j["gasCost"] = %
j["error"] = %(c.error.info)
tracer.trace["failed"] = %true