fix traceTransaction
This commit is contained in:
parent
5509c66cce
commit
2552d6452a
|
@ -1,24 +1,44 @@
|
|||
import
|
||||
db/[db_chain, state_db], eth_common, utils, json,
|
||||
constants, vm_state, vm_types, transaction, p2p/chain
|
||||
db/[db_chain, state_db, capturedb], eth_common, utils, json,
|
||||
constants, vm_state, vm_types, transaction, p2p/chain,
|
||||
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)
|
||||
|
||||
proc traceTransaction*(db: BaseChainDB, header: BlockHeader,
|
||||
body: BlockBody, txIndex: int, tracerFlags: set[TracerFlags]): JsonNode =
|
||||
let head = db.getCanonicalHead()
|
||||
assert(head.blockNumber == header.blockNumber - 1)
|
||||
var stateDb = newAccountStateDB(db.db, head.stateRoot, db.pruneTrie)
|
||||
let parent = db.getParentHeader(header)
|
||||
var stateDb = newAccountStateDB(db.db, parent.stateRoot, db.pruneTrie)
|
||||
assert(body.transactions.calcTxRoot == header.txRoot)
|
||||
if header.txRoot == BLANK_ROOT_HASH: return
|
||||
|
||||
let vmState = newBaseVMState(head, db, tracerFlags + {EnableTracing})
|
||||
let
|
||||
memoryDB = newMemoryDB()
|
||||
captureDB = newCaptureDB(db.db, memoryDB)
|
||||
captureTrieDB = trieDB captureDB
|
||||
captureChainDB = newBaseChainDB(captureTrieDB, false) # prune or not prune?
|
||||
|
||||
let vmState = newBaseVMState(parent, captureChainDB, tracerFlags + {TracerFlags.EnableTracing})
|
||||
assert(body.transactions.len != 0)
|
||||
|
||||
var gasUsed: GasInt
|
||||
for idx, tx in body.transactions:
|
||||
var sender: EthAddress
|
||||
if tx.getSender(sender):
|
||||
discard processTransaction(stateDb, tx, sender, vmState)
|
||||
let txFee = processTransaction(stateDb, tx, sender, vmState)
|
||||
gasUsed = (txFee div tx.gasPrice.u256).truncate(GasInt)
|
||||
if idx == txIndex: break
|
||||
else:
|
||||
assert(false, "Could not get sender")
|
||||
|
||||
vmState.getTracingResult()
|
||||
result = vmState.getTracingResult()
|
||||
result["gas"] = %gasUsed
|
||||
|
||||
var n = newJObject()
|
||||
for k, v in pairsInMemoryDB(memoryDB):
|
||||
n[k.prefixHex] = %v.prefixHex
|
||||
result["snapshot"] = n
|
||||
|
|
|
@ -286,11 +286,14 @@ proc getGasRemaining*(c: BaseComputation): GasInt =
|
|||
else:
|
||||
result = c.gasMeter.gasRemaining
|
||||
|
||||
template tracingEnabled*(c: BaseComputation): bool =
|
||||
proc tracingEnabled*(c: BaseComputation): bool =
|
||||
c.vmState.tracingEnabled
|
||||
|
||||
template traceOpCodeStarted*(c: BaseComputation, op: string) =
|
||||
proc traceOpCodeStarted*(c: BaseComputation, op: string) =
|
||||
traceOpCodeStarted(c.vmState.tracer, c, op)
|
||||
|
||||
proc traceOpCodeEnded*(c: BaseComputation) =
|
||||
c.vmState.tracer.traceOpCodeEnded(c)
|
||||
|
||||
proc traceError*(c: BaseComputation) =
|
||||
c.vmState.tracer.traceError(c)
|
||||
|
|
|
@ -1,10 +1,19 @@
|
|||
import
|
||||
json, strutils,
|
||||
eth_common, stint, byteutils,
|
||||
../vm_types, memory, stack
|
||||
../vm_types, memory, stack,
|
||||
../db/[db_chain, state_db],
|
||||
eth_trie/hexary, ./message,
|
||||
ranges/typedranges
|
||||
|
||||
proc initTracer*(tracer: var TransactionTracer, flags: set[TracerFlags] = {}) =
|
||||
tracer.trace = newJObject()
|
||||
|
||||
# make appear at the top of json object
|
||||
tracer.trace["gas"] = %0
|
||||
tracer.trace["failed"] = %false
|
||||
tracer.trace["returnValue"] = %""
|
||||
|
||||
tracer.trace["structLogs"] = newJArray()
|
||||
tracer.flags = flags
|
||||
|
||||
|
@ -37,11 +46,32 @@ proc traceOpCodeStarted*(tracer: var TransactionTracer, c: BaseComputation, op:
|
|||
mem.add(%c.memory.bytes.toOpenArray(i * chunkLen, (i + 1) * chunkLen - 1).toHex())
|
||||
j["memory"] = mem
|
||||
|
||||
# TODO: log storage
|
||||
# TODO: this seems very inefficient
|
||||
# could we improve it?
|
||||
# TODO: figure out how to get storage
|
||||
# when contract excecution interrupted by exception
|
||||
if TracerFlags.DisableStorage notin tracer.flags:
|
||||
let storage = newJArray()
|
||||
var storage = newJObject()
|
||||
var stateDB = c.vmState.chaindb.getStateDb(c.vmState.blockHeader.stateRoot, readOnly = true)
|
||||
let storageRoot = stateDB.getStorageRoot(c.msg.storageAddress)
|
||||
var trie = initHexaryTrie(c.vmState.chaindb.db, storageRoot)
|
||||
for k, v in trie:
|
||||
var key = k.toOpenArray.toHex
|
||||
if key.len != 0:
|
||||
storage[key] = %(v.toOpenArray.toHex)
|
||||
j["storage"] = storage
|
||||
|
||||
proc traceOpCodeEnded*(tracer: var TransactionTracer, c: BaseComputation) =
|
||||
let j = tracer.trace["structLogs"].elems[^1]
|
||||
j["gasCost"] = %(tracer.gasRemaining - c.gasMeter.gasRemaining)
|
||||
|
||||
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
|
||||
|
|
|
@ -102,13 +102,14 @@ proc applyCreateTransaction*(db: var AccountStateDB, t: Transaction, vmState: Ba
|
|||
db.setCode(contractAddress, ByteRange())
|
||||
db.addBalance(sender, (t.gasLimit.u256 - gasUsed2 - codeCost.u256)*t.gasPrice.u256)
|
||||
return (gasUsed2 + codeCost.u256) * t.gasPrice.u256
|
||||
|
||||
else:
|
||||
# FIXME: don't do this revert, but rather only subBalance correctly
|
||||
# the if transactionfailed at end is what is supposed to pick it up
|
||||
# especially when it's cross-function, it's ugly/fragile
|
||||
db.addBalance(sender, t.value)
|
||||
echo "isError: ", c.isError
|
||||
if c.tracingEnabled:
|
||||
c.traceError()
|
||||
return t.gasLimit.u256 * t.gasPrice.u256
|
||||
|
||||
method executeTransaction(vmState: BaseVMState, transaction: Transaction): (BaseComputation, BlockHeader) {.base.}=
|
||||
|
|
Loading…
Reference in New Issue