mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-01-12 05:14:14 +00:00
add internal transactions dump
This commit is contained in:
parent
5fc134ac2a
commit
8a6d351c22
@ -52,6 +52,7 @@ const
|
||||
recipientName = "recipient"
|
||||
minerName = "miner"
|
||||
uncleName = "uncle"
|
||||
internalTxName = "internalTx"
|
||||
|
||||
proc traceTransaction*(db: BaseChainDB, header: BlockHeader,
|
||||
body: BlockBody, txIndex: int, tracerFlags: set[TracerFlags] = {}): JsonNode =
|
||||
@ -63,9 +64,11 @@ proc traceTransaction*(db: BaseChainDB, header: BlockHeader,
|
||||
captureDB = newCaptureDB(db.db, memoryDB)
|
||||
captureTrieDB = trieDB captureDB
|
||||
captureChainDB = newBaseChainDB(captureTrieDB, false) # prune or not prune?
|
||||
vmState = newBaseVMState(parent, captureChainDB, tracerFlags)
|
||||
vmState = newBaseVMState(parent, captureChainDB, tracerFlags + {EnableAccount})
|
||||
|
||||
var stateDb = newAccountStateDB(captureTrieDB, parent.stateRoot, db.pruneTrie)
|
||||
var stateBefore = newAccountStateDB(captureTrieDB, parent.stateRoot, db.pruneTrie)
|
||||
# stateDb and stateBefore will not the same after transaction execution
|
||||
if header.txRoot == BLANK_ROOT_HASH: return newJNull()
|
||||
assert(body.transactions.calcTxRoot == header.txRoot)
|
||||
assert(body.transactions.len != 0)
|
||||
@ -85,6 +88,7 @@ proc traceTransaction*(db: BaseChainDB, header: BlockHeader,
|
||||
before.captureAccount(stateDb, sender, senderName)
|
||||
before.captureAccount(stateDb, recipient, recipientName)
|
||||
before.captureAccount(stateDb, header.coinbase, minerName)
|
||||
stateDiff["beforeRoot"] = %($vmState.blockHeader.stateRoot)
|
||||
|
||||
let txFee = processTransaction(stateDb, tx, sender, vmState)
|
||||
stateDb.addBalance(header.coinbase, txFee)
|
||||
@ -94,8 +98,16 @@ proc traceTransaction*(db: BaseChainDB, header: BlockHeader,
|
||||
after.captureAccount(stateDb, sender, senderName)
|
||||
after.captureAccount(stateDb, recipient, recipientName)
|
||||
after.captureAccount(stateDb, header.coinbase, minerName)
|
||||
stateDiff["afterRoot"] = %($vmState.blockHeader.stateRoot)
|
||||
break
|
||||
|
||||
# internal transactions:
|
||||
for idx, acc in tracedAccountsPairs(vmState):
|
||||
before.captureAccount(stateBefore, acc, internalTxName & $idx)
|
||||
|
||||
for idx, acc in tracedAccountsPairs(vmState):
|
||||
after.captureAccount(stateDb, acc, internalTxName & $idx)
|
||||
|
||||
result = vmState.getTracingResult()
|
||||
result["gas"] = %gasUsed
|
||||
result["statediff"] = stateDiff
|
||||
@ -105,20 +117,6 @@ proc traceTransaction*(db: BaseChainDB, header: BlockHeader,
|
||||
result.dumpMemoryDB(memoryDB)
|
||||
|
||||
proc dumpBlockState*(db: BaseChainDB, header: BlockHeader, body: BlockBody, dumpState = false): JsonNode =
|
||||
# TODO: scan tracing result and find internal transaction address
|
||||
# then do account dump as usual, before and after
|
||||
# cons: unreliable and prone to error.
|
||||
# pros: no need to map account secure key back to address.
|
||||
|
||||
# alternative: capture state trie using captureDB, and then dump every
|
||||
# account for this block.
|
||||
# cons: we need to map account secure key back to account address.
|
||||
# pros: no account will be missed, we will get all account touched by this block
|
||||
# we can turn this address capture/mapping only during dumping block state and
|
||||
# disable it during normal operation.
|
||||
# also the order of capture needs to be reversed, collecting addresses *after*
|
||||
# processing block then using that addresses to collect accounts from parent block
|
||||
|
||||
let
|
||||
parent = db.getParentHeader(header)
|
||||
memoryDB = newMemoryDB()
|
||||
@ -126,7 +124,7 @@ proc dumpBlockState*(db: BaseChainDB, header: BlockHeader, body: BlockBody, dump
|
||||
captureTrieDB = trieDB captureDB
|
||||
captureChainDB = newBaseChainDB(captureTrieDB, false)
|
||||
# we only need stack dump if we want to scan for internal transaction address
|
||||
vmState = newBaseVMState(parent, captureChainDB, {EnableTracing, DisableMemory, DisableStorage})
|
||||
vmState = newBaseVMState(parent, captureChainDB, {EnableTracing, DisableMemory, DisableStorage, EnableAccount})
|
||||
|
||||
var
|
||||
before = newJArray()
|
||||
@ -158,6 +156,13 @@ proc dumpBlockState*(db: BaseChainDB, header: BlockHeader, body: BlockBody, dump
|
||||
for idx, uncle in body.uncles:
|
||||
after.captureAccount(stateAfter, uncle.coinbase, uncleName & $idx)
|
||||
|
||||
# internal transactions:
|
||||
for idx, acc in tracedAccountsPairs(vmState):
|
||||
before.captureAccount(stateBefore, acc, internalTxName & $idx)
|
||||
|
||||
for idx, acc in tracedAccountsPairs(vmState):
|
||||
after.captureAccount(stateAfter, acc, internalTxName & $idx)
|
||||
|
||||
result = %{"before": before, "after": after}
|
||||
|
||||
if dumpState:
|
||||
|
@ -122,3 +122,7 @@ proc peek*(stack: Stack): UInt256 =
|
||||
proc `$`*(stack: Stack): string =
|
||||
let values = stack.values.mapIt(&" {$it}").join("\n")
|
||||
&"Stack:\n{values}"
|
||||
|
||||
proc `[]`*(stack: Stack, i: BackwardsIndex, T: typedesc): T =
|
||||
# This should be used only for tracer/test/debugging
|
||||
fromStackElement(stack.values[i], result)
|
||||
|
@ -18,6 +18,7 @@ proc initTracer*(tracer: var TransactionTracer, flags: set[TracerFlags] = {}) =
|
||||
|
||||
tracer.trace["structLogs"] = newJArray()
|
||||
tracer.flags = flags
|
||||
tracer.accounts = @[]
|
||||
|
||||
proc traceOpCodeStarted*(tracer: var TransactionTracer, c: BaseComputation, op: Op) =
|
||||
if unlikely tracer.trace.isNil:
|
||||
@ -48,6 +49,17 @@ proc traceOpCodeStarted*(tracer: var TransactionTracer, c: BaseComputation, op:
|
||||
mem.add(%c.memory.bytes.toOpenArray(i * chunkLen, (i + 1) * chunkLen - 1).toHex())
|
||||
j["memory"] = mem
|
||||
|
||||
if TracerFlags.EnableAccount in tracer.flags:
|
||||
case op
|
||||
of Call, CallCode, DelegateCall, StaticCall:
|
||||
assert(c.stack.values.len > 2)
|
||||
tracer.accounts.add c.stack[^2, EthAddress]
|
||||
of SelfDestruct:
|
||||
assert(c.stack.values.len > 1)
|
||||
tracer.accounts.add c.stack[^1, EthAddress]
|
||||
else:
|
||||
discard
|
||||
|
||||
proc traceOpCodeEnded*(tracer: var TransactionTracer, c: BaseComputation, op: Op) =
|
||||
let j = tracer.trace["structLogs"].elems[^1]
|
||||
|
||||
|
@ -134,3 +134,11 @@ proc enableTracing*(vmState: BaseVMState) =
|
||||
|
||||
proc disableTracing*(vmState: BaseVMState) =
|
||||
vmState.tracingEnabled = false
|
||||
|
||||
iterator tracedAccounts*(vmState: BaseVMState): EthAddress =
|
||||
for acc in vmState.tracer.accounts:
|
||||
yield acc
|
||||
|
||||
iterator tracedAccountsPairs*(vmState: BaseVMState): (int, EthAddress) =
|
||||
for idx, acc in vmState.tracer.accounts:
|
||||
yield (idx, acc)
|
||||
|
@ -34,11 +34,13 @@ type
|
||||
DisableMemory
|
||||
DisableStack
|
||||
DisableState
|
||||
EnableAccount
|
||||
|
||||
TransactionTracer* = object
|
||||
trace*: JsonNode
|
||||
gasRemaining*: GasInt
|
||||
flags*: set[TracerFlags]
|
||||
accounts*: seq[EthAddress]
|
||||
|
||||
OpcodeExecutor* = proc(computation: var BaseComputation)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user