This repository has been archived by the owner on Feb 26, 2024. It is now read-only.
Several bugs in debug_traceTransaction
#3214
Labels
debug_traceTransaction
#3214
There are several bugs causing strange behavior of
debug_traceTransaction
.I'll briefly enumerate the issues below, then dig into the root cause. Here is a gist with a script that demonstrates the issues: https://gist.github.com/robmcl4/164d02de04c8708817c5c32a9c325843
Summary
gas
returned does not include the gas refund, so it is over the true amount of gas spent (as an aside, I would like to see structLogs to also contain the propertyrefund
with the current gas refund -- this is the behavior of the current geth release,1.10.18
.)SSTORE
operations in the deeper call don't modify thestorage
property of the structLogs when the outer call resumes (after the inner call completes). This improperly leads the web3 user to believe the outer call sees stale storage.debug_traceTransaction
on a transaction which occurred before the fork block, and a contract attempts to set a storage slot to0x0
when its value prior to the transaction was nonnull (ie, you attempt to delete the slot), then the delete is not persisted and the EVM will continue to execute performing stale reads on that slotDeeper discussion
Issue (1)
This one is simple. On
blockchain.ts:1366
,runTx
returns aRunTxResult
... the actual gas consumed is found in the propertygasUsed
.Issue (2)
This is because at
blockchain.ts:1287
, onlystorageStack[eventDepth]
is modified. However, stale copies of the storage may exist at higher depths, further up in the call stack. This can be fixed by iterating overstorageStack
and updating storage whenever the same contract is seen further up the stack.Issue (3)
The core issue is because of the conditional statement at
trie.ts:167
andtrie.ts:275
.Consider that we are tracing a pre-fork transaction, and a contract attempts to delete storage (set it to
0x0
). Eventually, we calltrie.del(..)
. The conditional on line 167 evaluates tofalse
, and theelse
block is taken on line 177. Critically, this means that the storage is never 'marked' as deleted. Subsequent reads will then notice that the slot is not available locally, query the fallback, and a stale read is observed in the EVM.Demonstration
I run this on ubuntu 20.04, python 3.8.10, node 16.15.1, npm 8.11.0, and geth 1.10.18. I have geth running as a full archive node running on
ws://127.0.0.1:8546
. Before running, I install web3:python3 -m pip install web3==5.29.2
I invoke ganache using:
Then, I run the linked script:
The script traces transaction
0xf514259f185019704004b241cb4c6e31ed5e6e474a998b99c4b89209e304f417
, both on geth and on ganache. This immediately demonstrates bugs (1), mismatched gas, and (3), stale read of0x1
after slot...f014
was deleted. Bug (2) appears after issue (3) is addressed. It's also important to point out that (1) cannot be addressed without (3) -- as the gas usage ofSSTORE
is computed incorrectly because of stale reads.If you need a json dump of geth's trace, I can supply that as well.
Work-Arounds
My current fixes are on my fork's branch
robmcl4/severalBugFixes
.With patches applied, the file outputs:
The text was updated successfully, but these errors were encountered: