xone-replay re-executes recorded net2040 blocks on xOneRS's own state, block after block, and stops at the first block whose result differs from the canonical header. The latest baseline, on main at commit 156fbc9, replayed blocks 0 to 20,000 with 0 mismatches in 116.7 s on a release build. A pull request that changes the chain spec, consensus, EVM or state code must show such a result, so the replay is the gate for consensus changes.

What the replay compares and its earlier ranges are in the conformance and replay gate and the replay gate in numbers. This post is the how-to.

What are the two steps?

xone-replay has two working commands (conformance/harness/src/main.rs):

xone-replay fetch [--network apothem|net2040] [--to N] [--cache PATH]
xone-replay run --network apothem|net2040 --to N [--source PATH] [--state-dir DIR] [--divergences DIR]

fetch reads blocks 0..=N from a geth-XDC archive with debug_getRawBlock into a cache file. run is offline: it executes from the cache and needs no network.

How do I build and fetch?

Build the release binary of the harness:

cargo build --locked --release -p xone-harness --bin xone-replay

The committed fetch reads the team's own geth-XDC archive, read-only, at 4 requests per second and at most 5 calls per request (RUNS.md). An outside reader cannot use that archive; the cache file is what run needs. The net2040 cache for blocks 0 to 20,000 is 825,332,663 bytes, and its fetch took about 3 minutes (issue #10, comment of 2026-11-15).

How do I run the replay?

xone-replay run --network net2040 --to 20000 \
  --source <cache>/net2040.jsonl \
  --state-dir <tmp>/state-net2040 \
  --divergences <tmp>/divergences

Use a fresh --state-dir for each run: the runner persists its own state there and builds genesis from the chain spec. --divergences is where a mismatch record goes.

What does a clean run print?

One line with the range, 0 mismatches, the blocks executed, the archive hash checks and the checkpoint lists derived, and, for V2, a line with the epoch switches, the gap snapshots and the 3-chain commits. The baseline of 2026-11-15 recorded: 20,000 blocks executed, 200 archive hash checks, 11 V2 epoch switches with Validators and Penalties equal to the header, 10 gap snapshots from state, 116.7 s wall time.

What does a mismatch look like?

The run stops at the first difference and exits 1. It writes a record to --divergences:

# net2040 block <n>

last matching block: <n-1>

- <field>: expected (canonical) <value>, actual (replay) <value>
- execution or validation error: <error>

The fields compared per block are gasUsed, receiptsRoot, logsBloom, transactionsRoot and stateRoot, the block hash on every 100th block and the last, and the masternode list at V1 checkpoints. In diagnosis mode, a stateRoot mismatch adds a state diagnosis from the archive's proofs and prestate tracer.

Why does it gate consensus changes?

CONTRIBUTING.md requires it: a pull request that changes xone-chainspec, xone-consensus, xone-evm or xone-state links its specification page and shows the differential result: range, mismatches and commit. The replay executes each block on the state the replay itself built, so one wrong rule changes a root and stops the run at the first block it affects. Replay mutants (rules switched off on purpose) must stop it; RUNS.md records them.

Frequently asked questions

How long does a 20,000-block net2040 replay take?

The baseline of 2026-11-15 took 116.7 s of wall time on a release build, with 0 mismatches.

Do I need network access to run the replay?

Only for fetch. run is offline and reads the cache file given with --source.

What does exit code 1 mean?

The run found a block whose result differs from the canonical header. The record in --divergences names the block, the last matching block and each differing field.

Is the oracle-prestate mode a gate too?

No. The diagnostic-prestate and pivot subcommands are labelled diagnostic. Only run on the runner's own state counts for the gate.

Sources