xOne has four clients: xOneRS (Rust), xOneTS (TypeScript), xOnePy (Python) and xOneC (C++). The xOneTS, xOnePy and xOneC repositories are private, so their links need access. This post describes what is on main today.

The modes at a glance

REFERENCE TABLEScroll to explore all columns →
Mode Flag Starts from Keeps afterwards
full --syncmode full (default) genesis state of a recent window only
snap --syncmode snap an empty datadir state from the pivot, plus a window of headers, bodies and receipts
fast --syncmode fast an empty datadir the same as snap
minimal --minimal a snapshot file the same window as snap

fast is an alias of snap, as in geth-XDC. All four clients accept it. Archive mode (--gcmode archive) has its own post.

Full

The node asks peers for blocks from genesis. Each block goes through one function, Chain::insert. It checks header and body, executes the block on the parent's own state, and checks receipts, bloom, gas and state root. There is no "trusted" or "skip" path (stages).

The xOneRS net2040 follow notes record one full sync from genesis to block 762,846 in about 95 minutes.

Snap and fast

Snap sync needs an empty datadir. A datadir that holds a chain continues that chain. The steps, from the pivot rule:

  1. Connect to a peer that shares snap/1. After 120 seconds without one, the start fails. The node never falls back to full sync.
  2. Download headers up to the peer's head. Each must link to its parent.
  3. Pick the pivot: the head minus 64 blocks, lowered to the first block with a valid anchor. The anchor is the epoch-switch header's masternode list, the quorum certificates of the next three blocks, and the 3-chain that commits the pivot.
  4. Pin the switch header. Use --snap.pins <file> (recommended beyond test networks), or let at least two peers serve the same header.
  5. Download the window of bodies and receipts. Each is checked against its header.
  6. Read the state of the gap blocks below the pivot. It comes from an xOne peer, or from an archive RPC given with --snap.gap-rpc. Every proof is checked against the header, so the RPC is not trusted.
  7. Download the state with proven ranges. The root rebuilt from the rows must equal the pivot's state root.
  8. Install everything in one write, then execute from the pivot plus one.

No block below the pivot is executed. Trust rests on the pin and the peers' header chain. Every block above the pivot is verified and executed.

The window is derived from the rules that read below a block, not fixed (retention). In the net2040 runs it was 1,799 bodies and receipts. Below the window, RPC answers with a typed unsupported history error. It never returns an empty result.

Minimal

Minimal mode keeps the same retention as a snap node. It gets there from a file, not from peers:

xone snapshot export --network net2040 --datadir <src> --out net2040.xsnap
xone snapshot import --network net2040 --datadir <dst> --in net2040.xsnap --pins pins.txt
xone --network net2040 --datadir <dst> --minimal

The pins file holds <number> <0x hash> lines. The import checks the anchor against it.

A minimal node never syncs from genesis. After each imported block it prunes below the window (minimal mode). The other three clients use xonets, xonepy and xonec with the same snapshot export, snapshot import and --minimal.

Differences between the clients

  • xOneRS: the snap download is held in memory. With --state.disk the head state is read from MDBX, and such a node serves no snap/1 or snapshot export (flags). The spec does not cover resuming an interrupted download. Issue #145 tracks disk-backed state.
  • xOneTS: slots and codes are staged on disk, so a stop before the install resumes from them (source).
  • xOnePy: downloaded ranges are written to SQLite as they arrive. A snapshot export needs a preimage for every row. A node that synced from geth refuses with a typed Preimage error (notes).
  • xOneC: the root of the download stands 32 blocks below the tip. The final pivot stands 16 blocks below it. The node then heals the trie with GetTrieNodes. Its Apothem notes describe snap sync from geth, nethermind and besu peers, with --snap.gap-rpc (net2040, Apothem).

What runs on net2040 today

The latest tracker comment on xOneRS#140 is from 2026-11-14 18:30 UTC, with the net2040 tip at block 840762.

REFERENCE TABLEScroll to explore all columns →
Client full snap fast minimal
xOneRS lag 0 lag 0 lag 0 lag 0
xOneTS lag 1 two nodes, both down two nodes: one at lag 0, one down two nodes, lag 0
xOnePy lag 0 lag 2 not built lag 0
xOneC lag 0 lag 0 not built lag 0

Lag is the number of blocks behind the archive node. For xOnePy and xOneC the tracker says "not built" and "alias of snap, not deployed". The flag still works and maps to snap. The tracker also lists archive nodes for all four clients. The xOneTS one was still syncing from genesis.

The xOnePy and xOneC snap nodes hold block-producer seats. The tracker shows 314 seals for xOnePy and 908 for xOneC, 0 misses each.

Measured on net2040

These numbers come from each client's ops notes, from different builds on 2026-11-12 and 2026-11-13. The net2040 state is small (9,532 accounts in the xOneRS run), so they do not predict mainnet or Apothem.

REFERENCE TABLEScroll to explore all columns →
Client Snap, start to tip Data moved Datadir at tip
xOneRS 10 s 2 MB 72 MB
xOneTS 17.8 s 1.7 MB 15,881,704 B
xOnePy 34.1 s 8.9 MB 20,687,035 B
xOneC not recorded (download 4.569889 s) 8.121088 MB not recorded for that run

Sources