To bootstrap an XDC node from a snapshot with xOne, you export a snapshot file from a stopped, synced node. You then import it into an empty datadir with a pins file and start the new node with --minimal. The xOneTS, xOnePy and xOneC repositories are private, so their links need access. This post describes what is on main today.
How do I export a snapshot?
Stop the synced node, then run xone snapshot export on its datadir (operator page):
xone snapshot export --datadir <datadir> --out snap.xsnap [--at N] [--max-age SECONDS] [--network apothem]
--atis the block. The default is the latest committed V2 epoch switch at or below the head. On V1 chains it is the highest block with a seal proof.- The state of
--atmust be inside the node's state window of 1,024 blocks below its head. - The command writes
snap.xsnap.partand renames it when complete. A file with its final name is whole. --max-ageis how long the creator says the file stays usable. The default is one day (code).
What is the pins file?
The pins file is the one fact you give the importer. It holds one <block number> 0x<block hash> line per pin. A # starts a comment.
# Apothem, epoch switch from a source you trust
85000100 0x<block hash>
A pin is the checkpoint of the snapshot, or the epoch-switch header that lists its validators. The import does not print either one. Read them from a node you trust.
How do I import it?
xone snapshot import --datadir <new-datadir> --in snap.xsnap --pins pins.txt [--max-age-cap SECONDS] [--network apothem]
The new datadir must hold no chain. --max-age-cap is your limit on the age of a manifest. The default is 7 days.
If the run stops, or the file is cut, run the same command again. The importer keeps the checked chunks in <new-datadir>/xone/snapshot.part and reads on from there.
To check a file and install nothing, run xone snapshot verify --in snap.xsnap --pins pins.txt --network apothem. Exit code 0 means every check passed.
How does the node check the anchor and the pins?
The node checks the pins first, then the manifest, then the content. The first failure is the error. A snapshot that fails leaves no chain in the datadir (import order).
- Pins. No pins file gives
NoPins, before the file is opened. - Manifest. Format version, chain id, genesis hash, freshness, pin, binding, then certificates (V2) or seals (V1). A V2 proof is a quorum certificate chain plus the 3-chain that commits the checkpoint. A V1 proof needs
ceil(2n/3)distinct sealers. - Chunks and content. Headers link to the checkpoint. Bodies and receipts match their headers. The state root rebuilt from the rows equals the manifest's.
- Write.
head.jsonis written last. The datadir exists when it does.
A file hash proves bytes, not the chain. A chain built with its own keys passes every manifest check. Only the pin, which comes from outside the manifest, catches it (anchor spec).
Three items are not authenticated: the V1 signer snapshot, the sign transactions and the gap pools. A forged item makes the node refuse a true block at the first block that reads it. It does not make the node accept a false block.
How do I start the node?
xone --datadir <new-datadir> --apothem --minimal
--minimal is required for an imported datadir and refused for any other. A datadir with an anchor and no --minimal fails with Anchored. A minimal node never syncs from genesis and never calls an archive. Its only block source is its peers, and it verifies and executes every block (minimal mode).
What does the node keep afterwards?
A minimal node keeps one state checkpoint and a window of recent data. As the head moves, it deletes headers, bodies and receipts below the derived window. The files are rewritten every 256 blocks.
A request for data below the window gets -32000 unsupported history. It never gets an empty answer. If a newer binary needs a longer window than the datadir holds, the node refuses to start with Shrunk. Import a new snapshot. For other modes, see sync modes, archive mode and storage.
| Client | What it says about history below the sync point | xOne |
|---|---|---|
| ethrex | A snap-synced node keeps headers only below the pivot. Pre-pivot history reads return empty (docs). | Typed unsupported history error |
| XDC geth fork | --syncmode {full|fast|snap}. Snap is marked experimental, as stated in its SYNC_MODES.md, commit 2026-11-09 (file). |
Snap and minimal are on main |
One measured run on net2040, on 2026-11-12 (build 8fe27572): the snapshot was 4,956,408 bytes, the import took 0.9 s, and the node reached the tip in 7 s. The datadir was 72 MB (net2040 notes). On Apothem, the 15-minute import target and the datadir size after 7 days are not measured yet.
Can I import from an HTTPS URL?
Yes, on builds from main after PR #1054 (2026-11-15, issue #185). xone snapshot import and verify accept an https:// URL for --in; plain http:// only on loopback. A remote file needs --checksum sha256:<hex>, and a wrong checksum is refused before import. An interrupted download keeps the partial file, and the next run resumes with HTTP Range. The pins check still applies, because the mirror is not trusted. The v0.1.0 release reads only a local file: download it with any tool first. ADR-006 is still Proposed. Issue #14 (authenticated bootstrap anchors) was closed on 2026-11-15 as already on main.
What are the commands in xOneTS, xOnePy and xOneC?
All three have snapshot export and snapshot import, and all three start with --minimal. They take --network and --datadir. None has snapshot verify. xOneC has snapshot inspect --in <file>, which prints what the manifest claims.
xonets snapshot export --network <name> --datadir <dir> --out <file> [--at <block>]
xonets snapshot import --network <name> --datadir <dir> --in <file> --pins <file> [--max-age-cap <seconds>]
Replace xonets with xonepy for xOnePy. xOneC uses xonec and the same flags, except that its import has no --max-age-cap.
xOneTS accepts mainnet, apothem, devnet and net2040 for --network. The default network of xonepy snapshot is net2040. Sources: xOneTS, xOnePy, xOneC.
Frequently asked questions
Can I import a snapshot without a pins file?
No. The import is refused with NoPins before the file is opened.
What happens if my download is cut?
Run the same import command again. The importer keeps the whole chunks it has checked and continues after them.
Can a minimal node answer old block queries?
Not below its window. It returns -32000 unsupported history, never an empty answer.
Sources
- xOneRS: operator page, snapshot format, import order, minimal mode, bootstrap anchor, ADR-006, net2040 sync modes, CLI definition
- Issues: #185, #14
- xOneTS (private): snapshot.ts
- xOnePy (private): snapshot.py
- xOneC (private): main.cpp
This article describes the source and evidence at its review date. Check the linked repository for current implementation and qualification status.
Explore the engineering evidenceEdit this page on GitHub opens the Markdown source (content/blog/snapshot-bootstrap-howto/index.md). GitHub may ask you to sign in. Report a correction opens a prefilled GitHub issue for this page.