- full (
--from,--to): every ledger of the range. This is the audit path: it measures everything, including the unattributed look-alikes in every ledger of the range, from the public data lake alone. - registry (
--ledgers-from): only the ledgers a published Explorer manifest lists. The Explorer reads just the ledgers that hold transactions of the registry’s facilitator accounts and upto contracts, and its manifest lists each of them with its hash; this mode reproduces that manifest.
Run it
From a clone of the repository (Node.js 24.11 or later,pnpm install):
/api/v1/<network>/manifest) and rebuild the
ledgers it lists:
Where the ledgers come from
The default source is the public Stellar data lake athttps://aws-public-blockchain.s3.us-east-2.amazonaws.com/v1.1/stellar/ledgers/: one zstd-compressed
LedgerCloseMetaBatch per ledger, readable anonymously over HTTPS. Pubnet ledgers live under pubnet/,
each testnet epoch under testnet/<reset date>/. The reader refuses redirects and other hosts, caps object
sizes, and checks the folder’s .config.json and that each object holds exactly the ledger asked for.
Every ledger is verified before it is classified:
- its hash is the SHA-256 of its header;
- the header’s transaction set hash and result hash match the transactions and results in the object;
- in a full scan, its previous-ledger hash is the hash of the ledger before it, with no gap; in a registry scope, its hash is the one the manifest lists (listed ledgers are not consecutive, so they are checked one by one).
ledger_gap,
ledger_hash_mismatch, tx_set_hash_mismatch, result_set_hash_mismatch, anchor_mismatch,
range_incomplete). The manifest’s anchors lists only anchors that were checked. A rebuild is never shortened or patched.
Transaction metas, which carry the events, are not hashed by the header. The events the rules read are
still bound to consensus: a successful contract call’s result records the SHA-256 of its return value and
events, and the result is covered by the header’s result hash. Before reading a candidate’s events, the
classifier recomputes that hash from the meta and compares it with the result; a meta that was rewritten
stops the rebuild with events_unbound.
What it writes
The command prints the SHA-256 of
manifest.json. Two rebuilds of the same range with the same rules and
registry print the same hash, whatever machine or concurrency produced them.
Checking a published number
- Save the published
manifest.jsonand take its rules version and registry version. - Check out a commit whose
RULES_VERSION(packages/x402-index/src/types.ts) is that rules version and whosepackages/x402-index/registry/<network>.jsonhas thatregistryVersion, or check out one with that rules version and pass the registry file with--registry. - Run
pnpm explorer:rebuild --network <network> --ledgers-from manifest.jsonand compare the manifest hash. The rebuild reads the listed ledgers from the public data lake, whatever source served them to the Explorer (the data lake or an RPC; the bytes are the same, as each ledger’s hash shows), checks each one against its listed hash and the manifest’s anchors (the ledger hashes the Explorer’s indexer checked against a Horizon with full history before it committed them), and lists the same anchors, so equal inputs give the same hash.totalsSha256, thefileshashes and the partition hashes must match; if they differ, the partition hashes show the first partition that disagrees. - To check that discovery missed nothing, run the full scan of the same range
(
--from <range.from> --to <range.to>, printed on the report as the audit command). It reads every ledger, so it also counts the unattributed look-alikes and exclusions of every ledger; itsrail402,rail402-betaandfacilitatorrows must equal the report’s (rules §14).
rebuildCommand
(--from, --to and, when the window was anchored, --anchor-horizon) writes the manifest served at
/api/v1/<network>/network-window/manifest, so the two hashes are equal when nothing differs.
For a full scan, two things in the manifest describe how it was produced rather than what it found, and
change the hash on their own: the source (a directory of ledger files gives another hash than the data
lake) and the anchors (pass --anchor, --anchors-from or --anchor-horizon; only checked anchors are
listed).
The repository’s tests rebuild a committed testnet slice (ledgers 5,330,305 to 5,330,320) on every run and
compare it with the committed manifest, so a change to the rules or the reader cannot change results
silently. They also index that slice the way the Explorer does, from recorded discovery pages, and require
the report’s manifest to equal a --ledgers-from rebuild of it, anchors included, and its attributed rows
to equal the full scan’s.
A check of the published testnet report
On 26 October 2026 the testnet report’s manifest (/api/v1/testnet/manifest, scope registry, ledgers
1,420,378 to 5,405,037, rules v1, registry 2026-10-23.1) was saved and rebuilt from the public data lake
with pnpm explorer:rebuild --network testnet --ledgers-from manifest.json. The rebuild read the 24,989
listed ledgers in 874 s and wrote 30,763 settlements and 34 failed attempts; its manifest.json was
byte-identical to the published one (SHA-256
29f407e72e3528ff250f3059a2abcc743d2e455bfdfb80ad379396e80bb2e494, the report’s manifestSha256).
A full scan of the range’s last 720 ledgers (--from 5404318 --to 5405037 --anchor-horizon https://horizon-testnet.stellar.org/) found the same 89 attributed rows (72 rail402, 17 facilitator)
as the report in that window, and 52 unattributed look-alikes the registry scope does not read.