2018-12-03 10:54:19 +00:00
|
|
|
import
|
2018-12-03 16:22:08 +00:00
|
|
|
db/[db_chain, state_db, capturedb], eth_common, utils, json,
|
2018-12-04 11:42:55 +00:00
|
|
|
constants, vm_state, vm_types, transaction, p2p/executor,
|
2018-12-03 16:22:08 +00:00
|
|
|
eth_trie/db, nimcrypto
|
|
|
|
|
|
|
|
proc getParentHeader(self: BaseChainDB, header: BlockHeader): BlockHeader =
|
|
|
|
self.getBlockHeader(header.parentHash)
|
|
|
|
|
|
|
|
proc prefixHex(x: openArray[byte]): string =
|
|
|
|
"0x" & toHex(x, true)
|
2018-12-03 10:54:19 +00:00
|
|
|
|
|
|
|
proc traceTransaction*(db: BaseChainDB, header: BlockHeader,
|
2018-12-04 11:42:55 +00:00
|
|
|
body: BlockBody, txIndex: int, tracerFlags: set[TracerFlags] = {}): JsonNode =
|
2018-12-03 16:22:08 +00:00
|
|
|
let
|
2018-12-04 01:53:21 +00:00
|
|
|
parent = db.getParentHeader(header)
|
2018-12-04 02:01:56 +00:00
|
|
|
# we add a memory layer between backend/lower layer db
|
2018-12-04 01:53:21 +00:00
|
|
|
# and capture state db snapshot during transaction execution
|
2018-12-03 16:22:08 +00:00
|
|
|
memoryDB = newMemoryDB()
|
|
|
|
captureDB = newCaptureDB(db.db, memoryDB)
|
|
|
|
captureTrieDB = trieDB captureDB
|
2018-12-04 02:01:56 +00:00
|
|
|
captureChainDB = newBaseChainDB(captureTrieDB, false) # prune or not prune?
|
2018-12-04 01:53:21 +00:00
|
|
|
vmState = newBaseVMState(parent, captureChainDB, tracerFlags + {TracerFlags.EnableTracing})
|
2018-12-04 02:01:56 +00:00
|
|
|
|
2018-12-04 01:53:21 +00:00
|
|
|
var stateDb = newAccountStateDB(captureTrieDB, parent.stateRoot, db.pruneTrie)
|
|
|
|
if header.txRoot == BLANK_ROOT_HASH: return
|
|
|
|
assert(body.transactions.calcTxRoot == header.txRoot)
|
2018-12-03 10:54:19 +00:00
|
|
|
assert(body.transactions.len != 0)
|
|
|
|
|
2018-12-03 16:22:08 +00:00
|
|
|
var gasUsed: GasInt
|
2018-12-03 10:54:19 +00:00
|
|
|
for idx, tx in body.transactions:
|
|
|
|
var sender: EthAddress
|
|
|
|
if tx.getSender(sender):
|
2018-12-03 16:22:08 +00:00
|
|
|
let txFee = processTransaction(stateDb, tx, sender, vmState)
|
|
|
|
gasUsed = (txFee div tx.gasPrice.u256).truncate(GasInt)
|
2018-12-03 10:54:19 +00:00
|
|
|
if idx == txIndex: break
|
|
|
|
else:
|
|
|
|
assert(false, "Could not get sender")
|
|
|
|
|
2018-12-03 16:22:08 +00:00
|
|
|
result = vmState.getTracingResult()
|
|
|
|
result["gas"] = %gasUsed
|
|
|
|
|
2018-12-04 01:53:21 +00:00
|
|
|
# now we dump captured state db
|
2018-12-04 02:01:56 +00:00
|
|
|
if TracerFlags.DisableState notin tracerFlags:
|
|
|
|
var n = newJObject()
|
|
|
|
for k, v in pairsInMemoryDB(memoryDB):
|
|
|
|
n[k.prefixHex] = %v.prefixHex
|
|
|
|
result["state"] = n
|