Step through a transaction

This page steps through real transactions in this browser tab, offline, from saved files. At each EVM step, it highlights the source range. A debugger engine does the debugging, in the browser. Each tab names its engine. The page only shows what the engine reports.

Part of the ethdebug post appendix, with Storage, by name and ethdebug in depth.

Engine: soldb, Walnut's debugger

Keys: ← → into, Shift+← → over, Shift+↑ ↓ out. Click a source line to run to its next step.

Loading...

Call stack

Innermost first, from invoke and return contexts.

    Variables

    Contract state, from ethdebug alone: solc's pointers for storage. No storage layout.

    A trace holds only the storage that the transaction touches. A value shows as unknown until the transaction reads or writes it.

    Inlining

    Every tab steps the same contract, Arcade (Arcade.sol), and the same transaction. In Arcade, players join with a name, then call play(), and a roll from the block gives a hit or a miss. A hit raises the player's combo by one and scores 10 × combo (up to 5×); a miss resets the combo. The story: alice, bob and carol join; alice hits twice, bob hits, carol hits four times, then misses. The transaction is alice's third play(), a hit at combo 3: _applyCombo(10, 3) is 30, and totalScore goes from 140 to 170. Each call ran on a local anvil node. anvil cannot set the block's randomness, so the script replays a play() from a snapshot until it rolls the story's outcome.

    soldb and this page step through Solidity and Fe with the same code. Both compilers write ethdebug.

    Compiler: Walnut's solc fork (walnuthq/solidity PR #10, head c434b2ea), with ethdebug output. Its pointers let soldb read the contract's state. solc writes ethdebug only with the optimizer off, so this build is via-IR without the optimizer. The trace is soldb's saved trace of the transaction (1.5 MB, 2,228 EVM steps). soldb parses the trace (Trace.fromJson) and reads the ethdebug (attachEthdebug). Then it maps each step to its source (step(i)) and reads the contract's state (state(i)).

    The page computes each step from two fields that soldb reports: the source span and the EVM call depth. "into" goes to the next new span. "over" goes to the next new span at the same or a lower depth. "out" goes to the first span after the depth drops. The EVM depth does not count internal calls. Every step in these transactions is at depth 1, so "over" and "out" are off here. soldb's own step over and out (soldb-debugger) follow internal calls. Its WebAssembly build does not expose them yet.

    Details: timings, offline replay, requests

    Each engine runs in a Web Worker, so the page stays responsive. The workers measure the times below.

    Each tab, and each check below, loads its files when it first opens. Once the Solidity tab is ready, the page loads the other tabs, one at a time, when the browser is idle, and fetches the replay build. It does not on a connection that asks to save data or is 2G.

    Solidity: lean build, saved trace

    Running...

    Fe: lean build, node responses

    Loads with the Fe tab.

    BUG: ethdebug's reference implementation

    The BUG tab's engine (ref-worker.js) is ethdebug/format's packages, bundled in vendor/ethdebug-ref.js (make-ref-vendor.sh). When it loads, it maps each step and builds its call stack. It reads variables and call arguments when the page shows a step.

    Loads with the BUG tab.

    The old way: a source map stepper

    The old way's engine (srcmap-worker.js, about 150 lines) reads solc's bytecode, source map and AST, and the node's trace. It reads no ethdebug.

    Loads with the tab "The old way".

    BUG: soldb check, lean build, node responses

    A saved transaction of Tally (tally.bug, bugc at -O2). soldb gets it as on the Fe tab (Trace.fromTransaction, then attachEthdebug). Two changes: bugc writes no resources file, so the page gives metadata as {compilation: {sources: [{id, path}]}}. bugc's source id is the string "tally.bug", and soldb reads numeric ids only, so the second row gives the id as 0.

    Runs when this section opens.

    Replay build: re-run a transaction offline

    The replay module (1,092 KB) contains an EVM. It re-runs a Token.transfer transaction from a 6.5 KB replay file. It contacts no node: soldb requests only static files from this server.

    Runs when this section opens.

    Requests from this page

    From the browser's resource timing list. Each entry must be a static file on this server.