mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-02-02 23:35:31 +00:00
implement debug_traceBlock
This commit is contained in:
parent
6dc4b0be9a
commit
3a355e0569
@ -14,7 +14,7 @@ import
|
|||||||
eth_common, ../tracer, ../vm_state, ../vm_types
|
eth_common, ../tracer, ../vm_state, ../vm_types
|
||||||
|
|
||||||
type
|
type
|
||||||
TraceTxOptions = object
|
TraceOptions = object
|
||||||
disableStorage: Option[bool]
|
disableStorage: Option[bool]
|
||||||
disableMemory: Option[bool]
|
disableMemory: Option[bool]
|
||||||
disableStack: Option[bool]
|
disableStack: Option[bool]
|
||||||
@ -23,13 +23,21 @@ type
|
|||||||
proc isTrue(x: Option[bool]): bool =
|
proc isTrue(x: Option[bool]): bool =
|
||||||
result = x.isSome and x.get() == true
|
result = x.isSome and x.get() == true
|
||||||
|
|
||||||
|
proc traceOptionsToFlags(options: Option[TraceOptions]): set[TracerFlags] =
|
||||||
|
if options.isSome:
|
||||||
|
let opts = options.get
|
||||||
|
if opts.disableStorage.isTrue: result.incl TracerFlags.DisableStorage
|
||||||
|
if opts.disableMemory.isTrue : result.incl TracerFlags.DisableMemory
|
||||||
|
if opts.disableStack.isTrue : result.incl TracerFlags.DisableStack
|
||||||
|
if opts.disableState.isTrue : result.incl TracerFlags.DisableState
|
||||||
|
|
||||||
proc setupDebugRpc*(chainDB: BaseChainDB, rpcsrv: RpcServer) =
|
proc setupDebugRpc*(chainDB: BaseChainDB, rpcsrv: RpcServer) =
|
||||||
|
|
||||||
proc getBlockBody(hash: Hash256): BlockBody =
|
proc getBlockBody(hash: Hash256): BlockBody =
|
||||||
if not chainDB.getBlockBody(hash, result):
|
if not chainDB.getBlockBody(hash, result):
|
||||||
raise newException(ValueError, "Error when retrieving block body")
|
raise newException(ValueError, "Error when retrieving block body")
|
||||||
|
|
||||||
rpcsrv.rpc("debug_traceTransaction") do(data: EthHashStr, options: Option[TraceTxOptions]) -> JsonNode:
|
rpcsrv.rpc("debug_traceTransaction") do(data: EthHashStr, options: Option[TraceOptions]) -> JsonNode:
|
||||||
## The traceTransaction debugging method will attempt to run the transaction in the exact
|
## The traceTransaction debugging method will attempt to run the transaction in the exact
|
||||||
## same manner as it was executed on the network. It will replay any transaction that may
|
## same manner as it was executed on the network. It will replay any transaction that may
|
||||||
## have been executed prior to this one before it will finally attempt to execute the
|
## have been executed prior to this one before it will finally attempt to execute the
|
||||||
@ -48,16 +56,7 @@ proc setupDebugRpc*(chainDB: BaseChainDB, rpcsrv: RpcServer) =
|
|||||||
blockHeader = chainDB.getBlockHeader(txDetails.blockNumber)
|
blockHeader = chainDB.getBlockHeader(txDetails.blockNumber)
|
||||||
blockHash = chainDB.getBlockHash(txDetails.blockNumber)
|
blockHash = chainDB.getBlockHash(txDetails.blockNumber)
|
||||||
blockBody = getBlockBody(blockHash)
|
blockBody = getBlockBody(blockHash)
|
||||||
|
flags = traceOptionsToFlags(options)
|
||||||
var
|
|
||||||
flags: set[TracerFlags]
|
|
||||||
|
|
||||||
if options.isSome:
|
|
||||||
let opts = options.get
|
|
||||||
if opts.disableStorage.isTrue: flags.incl TracerFlags.DisableStorage
|
|
||||||
if opts.disableMemory.isTrue: flags.incl TracerFlags.DisableMemory
|
|
||||||
if opts.disableStack.isTrue: flags.incl TracerFlags.DisableStack
|
|
||||||
if opts.disableState.isTrue: flags.incl TracerFlags.DisableState
|
|
||||||
|
|
||||||
traceTransaction(chainDB, blockHeader, blockBody, txDetails.index, flags)
|
traceTransaction(chainDB, blockHeader, blockBody, txDetails.index, flags)
|
||||||
|
|
||||||
@ -86,3 +85,33 @@ proc setupDebugRpc*(chainDB: BaseChainDB, rpcsrv: RpcServer) =
|
|||||||
body = getBlockBody(blockHash)
|
body = getBlockBody(blockHash)
|
||||||
|
|
||||||
dumpBlockState(chainDB, header, body)
|
dumpBlockState(chainDB, header, body)
|
||||||
|
|
||||||
|
rpcsrv.rpc("debug_traceBlockByNumber") do(quantityTag: string, options: Option[TraceOptions]) -> JsonNode:
|
||||||
|
## The traceBlock method will return a full stack trace of all invoked opcodes of all transaction
|
||||||
|
## that were included included in this block.
|
||||||
|
##
|
||||||
|
## quantityTag: integer of a block number, or the string "earliest",
|
||||||
|
## "latest" or "pending", as in the default block parameter.
|
||||||
|
## options: see debug_traceTransaction
|
||||||
|
let
|
||||||
|
header = chainDB.headerFromTag(quantityTag)
|
||||||
|
blockHash = chainDB.getBlockHash(header.blockNumber)
|
||||||
|
body = getBlockBody(blockHash)
|
||||||
|
flags = traceOptionsToFlags(options)
|
||||||
|
|
||||||
|
traceBlock(chainDB, header, body, flags)
|
||||||
|
|
||||||
|
rpcsrv.rpc("debug_traceBlockByHash") do(data: EthHashStr, options: Option[TraceOptions]) -> JsonNode:
|
||||||
|
## The traceBlock method will return a full stack trace of all invoked opcodes of all transaction
|
||||||
|
## that were included included in this block.
|
||||||
|
##
|
||||||
|
## data: Hash of a block.
|
||||||
|
## options: see debug_traceTransaction
|
||||||
|
let
|
||||||
|
h = data.toHash
|
||||||
|
header = chainDB.getBlockHeader(h)
|
||||||
|
blockHash = chainDB.getBlockHash(header.blockNumber)
|
||||||
|
body = getBlockBody(blockHash)
|
||||||
|
flags = traceOptionsToFlags(options)
|
||||||
|
|
||||||
|
traceBlock(chainDB, header, body, flags)
|
||||||
|
@ -165,3 +165,30 @@ proc dumpBlockState*(db: BaseChainDB, header: BlockHeader, body: BlockBody): Jso
|
|||||||
after.captureAccount(stateAfter, uncle.coinbase, uncleName & $idx)
|
after.captureAccount(stateAfter, uncle.coinbase, uncleName & $idx)
|
||||||
|
|
||||||
result = %{"before": before, "after": after}
|
result = %{"before": before, "after": after}
|
||||||
|
|
||||||
|
proc traceBlock*(db: BaseChainDB, header: BlockHeader, body: BlockBody, tracerFlags: set[TracerFlags] = {}): JsonNode =
|
||||||
|
let
|
||||||
|
parent = db.getParentHeader(header)
|
||||||
|
memoryDB = newMemoryDB()
|
||||||
|
captureDB = newCaptureDB(db.db, memoryDB)
|
||||||
|
captureTrieDB = trieDB captureDB
|
||||||
|
captureChainDB = newBaseChainDB(captureTrieDB, false)
|
||||||
|
vmState = newBaseVMState(parent, captureChainDB, tracerFlags + {EnableTracing})
|
||||||
|
|
||||||
|
var
|
||||||
|
stateDb = newAccountStateDB(captureTrieDB, parent.stateRoot, db.pruneTrie)
|
||||||
|
|
||||||
|
if header.txRoot == BLANK_ROOT_HASH: return
|
||||||
|
assert(body.transactions.calcTxRoot == header.txRoot)
|
||||||
|
assert(body.transactions.len != 0)
|
||||||
|
|
||||||
|
var gasUsed = GasInt(0)
|
||||||
|
|
||||||
|
for tx in body.transactions:
|
||||||
|
let
|
||||||
|
sender = tx.getSender
|
||||||
|
txFee = processTransaction(stateDb, tx, sender, vmState)
|
||||||
|
gasUsed = gasUsed + (txFee div tx.gasPrice.u256).truncate(GasInt)
|
||||||
|
|
||||||
|
result = vmState.getTracingResult()
|
||||||
|
result["gas"] = %gasUsed
|
Loading…
x
Reference in New Issue
Block a user