fix traceTransaction
This commit is contained in:
parent
5509c66cce
commit
2552d6452a
|
@ -1,24 +1,44 @@
|
||||||
import
|
import
|
||||||
db/[db_chain, state_db], eth_common, utils, json,
|
db/[db_chain, state_db, capturedb], eth_common, utils, json,
|
||||||
constants, vm_state, vm_types, transaction, p2p/chain
|
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,
|
proc traceTransaction*(db: BaseChainDB, header: BlockHeader,
|
||||||
body: BlockBody, txIndex: int, tracerFlags: set[TracerFlags]): JsonNode =
|
body: BlockBody, txIndex: int, tracerFlags: set[TracerFlags]): JsonNode =
|
||||||
let head = db.getCanonicalHead()
|
let parent = db.getParentHeader(header)
|
||||||
assert(head.blockNumber == header.blockNumber - 1)
|
var stateDb = newAccountStateDB(db.db, parent.stateRoot, db.pruneTrie)
|
||||||
var stateDb = newAccountStateDB(db.db, head.stateRoot, db.pruneTrie)
|
|
||||||
assert(body.transactions.calcTxRoot == header.txRoot)
|
assert(body.transactions.calcTxRoot == header.txRoot)
|
||||||
if header.txRoot == BLANK_ROOT_HASH: return
|
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)
|
assert(body.transactions.len != 0)
|
||||||
|
|
||||||
|
var gasUsed: GasInt
|
||||||
for idx, tx in body.transactions:
|
for idx, tx in body.transactions:
|
||||||
var sender: EthAddress
|
var sender: EthAddress
|
||||||
if tx.getSender(sender):
|
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
|
if idx == txIndex: break
|
||||||
else:
|
else:
|
||||||
assert(false, "Could not get sender")
|
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:
|
else:
|
||||||
result = c.gasMeter.gasRemaining
|
result = c.gasMeter.gasRemaining
|
||||||
|
|
||||||
template tracingEnabled*(c: BaseComputation): bool =
|
proc tracingEnabled*(c: BaseComputation): bool =
|
||||||
c.vmState.tracingEnabled
|
c.vmState.tracingEnabled
|
||||||
|
|
||||||
template traceOpCodeStarted*(c: BaseComputation, op: string) =
|
proc traceOpCodeStarted*(c: BaseComputation, op: string) =
|
||||||
traceOpCodeStarted(c.vmState.tracer, c, op)
|
traceOpCodeStarted(c.vmState.tracer, c, op)
|
||||||
|
|
||||||
proc traceOpCodeEnded*(c: BaseComputation) =
|
proc traceOpCodeEnded*(c: BaseComputation) =
|
||||||
c.vmState.tracer.traceOpCodeEnded(c)
|
c.vmState.tracer.traceOpCodeEnded(c)
|
||||||
|
|
||||||
|
proc traceError*(c: BaseComputation) =
|
||||||
|
c.vmState.tracer.traceError(c)
|
||||||
|
|
|
@ -1,10 +1,19 @@
|
||||||
import
|
import
|
||||||
json, strutils,
|
json, strutils,
|
||||||
eth_common, stint, byteutils,
|
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] = {}) =
|
proc initTracer*(tracer: var TransactionTracer, flags: set[TracerFlags] = {}) =
|
||||||
tracer.trace = newJObject()
|
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.trace["structLogs"] = newJArray()
|
||||||
tracer.flags = flags
|
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())
|
mem.add(%c.memory.bytes.toOpenArray(i * chunkLen, (i + 1) * chunkLen - 1).toHex())
|
||||||
j["memory"] = mem
|
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:
|
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
|
j["storage"] = storage
|
||||||
|
|
||||||
proc traceOpCodeEnded*(tracer: var TransactionTracer, c: BaseComputation) =
|
proc traceOpCodeEnded*(tracer: var TransactionTracer, c: BaseComputation) =
|
||||||
let j = tracer.trace["structLogs"].elems[^1]
|
let j = tracer.trace["structLogs"].elems[^1]
|
||||||
j["gasCost"] = %(tracer.gasRemaining - c.gasMeter.gasRemaining)
|
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.setCode(contractAddress, ByteRange())
|
||||||
db.addBalance(sender, (t.gasLimit.u256 - gasUsed2 - codeCost.u256)*t.gasPrice.u256)
|
db.addBalance(sender, (t.gasLimit.u256 - gasUsed2 - codeCost.u256)*t.gasPrice.u256)
|
||||||
return (gasUsed2 + codeCost.u256) * t.gasPrice.u256
|
return (gasUsed2 + codeCost.u256) * t.gasPrice.u256
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# FIXME: don't do this revert, but rather only subBalance correctly
|
# FIXME: don't do this revert, but rather only subBalance correctly
|
||||||
# the if transactionfailed at end is what is supposed to pick it up
|
# the if transactionfailed at end is what is supposed to pick it up
|
||||||
# especially when it's cross-function, it's ugly/fragile
|
# especially when it's cross-function, it's ugly/fragile
|
||||||
db.addBalance(sender, t.value)
|
db.addBalance(sender, t.value)
|
||||||
echo "isError: ", c.isError
|
echo "isError: ", c.isError
|
||||||
|
if c.tracingEnabled:
|
||||||
|
c.traceError()
|
||||||
return t.gasLimit.u256 * t.gasPrice.u256
|
return t.gasLimit.u256 * t.gasPrice.u256
|
||||||
|
|
||||||
method executeTransaction(vmState: BaseVMState, transaction: Transaction): (BaseComputation, BlockHeader) {.base.}=
|
method executeTransaction(vmState: BaseVMState, transaction: Transaction): (BaseComputation, BlockHeader) {.base.}=
|
||||||
|
|
Loading…
Reference in New Issue