Data & method
Where every number on this site comes from, how it is kept current, and what could not be established at all. The short version: anything describing the live network is read from a Rootstock mainnet node by a script; anything else is quoted and linked.
The rules this site follows
- Current data is never typed by hand. Any figure that describes the live network is produced by a script that reads it from its source. Hand-written numbers go stale silently; a script's output is dated and diffable.
- Every non-obvious claim carries a source link. Where the source is the chain, the page says which call or event it came from.
- Derived values are labelled as derived. The historical signing thresholds, for instance, follow from a consensus rule rather than from a per-federation reading, and the PowPeg page says so at the point of use.
- Gaps are published as gaps. If a primary source could not be found, the page says that instead of filling it in.
- Conflicts are shown, not resolved. Where two sources disagree — PowHSM release dates, the emergency multisig threshold — both are printed with their origins.
The nine data feeds
Each collector writes one JSON file. Those files are committed to the repository, so the site builds without a node and without network access, and a week in which nothing changed produces an empty diff.
| File | Contents | Source | Last collected |
|---|---|---|---|
| data/chain.json | Chain head, block time, peg parameters | mainnet node | 8 Nov 2026 22:00 UTC |
| data/powpeg.json | Federation history and live federation | mainnet node | 8 Nov 2026 07:02 UTC |
| data/mining.json | Block production, client builds, proof checks | mainnet node | 8 Nov 2026 07:02 UTC |
| data/upgrades.json | Network upgrades and activation heights | node GitHub | 8 Nov 2026 07:02 UTC |
| data/powhsm.json | PowHSM firmware versions | GitHub API | 8 Nov 2026 07:02 UTC |
| data/rskips.json | RSKIPs, and which release activated each | node GitHub | 8 Nov 2026 07:02 UTC |
| data/links.json | Press and reading lists, with every link re-checked | curated + link check | 8 Nov 2026 22:06 UTC |
| data/clients.json | Node implementations: licence, language, latest release | GitHub API | 8 Nov 2026 07:20 UTC |
| data/ecosystem.json | The ecosystem directory, with every project link checked | curated + link check | 8 Nov 2026 07:13 UTC |
Hand-maintained data, and how it survives a re-run
One file in data/ is not generated: rskip-overlay.json. It
holds activations the RSKIP repository does not record — chiefly the five proposals that
activated on testnet in Reed 8.1.0, which are knowable only from that release's notes.
The collector reads it and never writes it, so re-running collection any number of times preserves everything entered by hand. Two rules keep it honest: every entry must carry a source URL or the run is refused, and where the upgrade RSKIP does state a height for the same release and network, a disagreement fails the run rather than publishing either value. The overlay can add what the documents lack; it cannot quietly contradict them.
The same file records what could not be established — which RSKIPs shipped in Wasabi, Bamboo and Ginger — so that a gap stays visible instead of looking like an oversight. Those notes are rendered on the RSKIPs page.
How collection works
One command refreshes everything:
node tools/collect.js
It is run manually, about weekly. It is deliberately boring:
- Read-only against the node. The RPC client carries an allow-list of ten query methods and refuses anything outside it, so a future collector cannot sign, submit or administer anything even by mistake. The node is shared infrastructure that this project is only a guest on.
- Host-restricted off the node. The two collectors that read GitHub can
reach
api.github.comandraw.githubusercontent.comand nothing else. - Atomic writes. Each file is written to a temporary name and renamed, so an interrupted run cannot leave truncated JSON that the build would publish.
- A failing collector changes nothing. If a collector throws, its previous file is left exactly as it was. Data that is a week old and labelled with its date is recoverable; data silently replaced by a half-written file is not.
- Incremental where it matters. The PowPeg collector records how far it scanned. A weekly run sweeps only the blocks since, which is a couple of calls rather than a scan of nine million blocks.
Collecting and building are separate
Nothing is collected when the site is built. build.js reads the JSON in
data/ and nothing else — no node, no network — so publishing a wording change is
a build and a copy, taking well under a second. The collectors run on their own schedule,
about weekly, and the only thing that connects them is a committed file.
That separation is why a figure here can be trusted to be the figure that was collected: rebuilding cannot silently change a number, and re-collecting shows up as a diff before anything is published.
Links are checked, not assumed
Two sections of this site are lists of other people's writing, and such lists fail in two ways: a link is wrong the day it is added, or it rots afterwards. Both look the same to a reader, and neither is visible without asking.
So every curated link is re-checked on each collection run and the result is published beside it. Three states are kept distinct, because conflating them misleads: the page loaded; the host would not serve this server (CoinDesk, Bloomberg, The Block and others answer 403 here — see where this site looks from, which is not a broken link); or it genuinely did not load. Failures are counted across runs, so one bad night does not condemn a citation and a link that has been dead for weeks is visibly stale. Nothing is deleted automatically — a citation that has rotted is still a record of what was published.
tools/checklinks.js goes further and checks every external link in
the built site, including the couple of hundred inline citations in the prose. That check is
also how a fact about the RSKIP repository surfaced: nine proposals referenced by upgrade
documents have no document in it at all, so no URL for them
can resolve.
No dependencies
There is no node_modules here. The collectors, the build and the server use
only the Node.js standard library — including a keccak-256 implementation written for this
repository, because Node's built-in SHA3 is the NIST variant and would silently produce
event topics that match no log. That implementation
self-tests against known vectors before it is used, and one of those
vectors is the commit_federation topic the PowPeg history depends on.
How the PowPeg history is verified
The 17-row federation table is the one piece of this site that exists nowhere else, so it is worth being explicit about why it should be believed.
The Bridge emits commit_federation on every handover. Crucially the event
carries both key sets — the one being replaced and the one taking over —
plus the height the new one activates at. That redundancy makes the history
self-checking:
for each handover i > 0:
assert handover[i].outgoingKeys == handover[i-1].incomingKeys
If any event were decoded wrongly, the chain would not close, and the collector fails rather than publishing. All 16 handovers close.
Two encodings have to be read to see the whole history, which is the part that is easy to get wrong. Before RSKIP146 the event used a literal ASCII topic and RLP-encoded its payload, with the activation height as a decimal ASCII string; from RSKIP146 onward it uses a keccak topic and ABI encoding. A reader that knows only the modern form silently loses the first three federations and reports a history that begins in 2020.
Finally the reconstruction is cross-checked against the live Bridge: the size, threshold
and Bitcoin address of the last row must equal what
getFederationSize(), getFederationThreshold() and
getFederationAddress() return right now. They do —
5 of 9 at
3GX89qzyQVaJqUJjq5noZbLJEHuYDvVrHq.
What this does not establish: who holds any of these keys. The chain records 45 distinct functionary public keys and no names at all. Any mapping from a key to an organisation would have to come from elsewhere, and Rootstock does not publish one.
Where this site looks from
Every link check on this site is a measurement taken from one machine, and which machine turns out to matter more than it sounds.
At the last run that machine appeared to be in Helsinki, FI, in a hosting provider's datacentre. That is recorded automatically on each run rather than written here, so it stays true if the site is ever collected from somewhere else.
The consequence: when a site answers this server with a refusal, there is no way from here to tell why. At least three causes are indistinguishable:
- Geofencing. Plenty of publishers restrict the EU for data-protection reasons, and crypto services geofence whole jurisdictions as a matter of course — exchanges especially, and this site lists thirty of them.
- Datacentre blocking. Many sites refuse all hosting-provider addresses regardless of where they are.
- Bot filtering proper, triggered by an honest non-browser client.
All three return 401 or 403, and none of them means a page is gone. A refusal is therefore reported as exactly what was observed — that this machine could not reach the page — with no cause attributed to it.
DNS is the exception, and that is why it carries the weight. A domain either has nameservers and address records or it does not, and that answer is the same everywhere. The ecosystem entries marked no DNS were checked against public resolvers as well as this machine's, so those findings do not depend on where the question was asked. The refusals do, and are labelled differently for that reason.
One deliberate non-solution: the checker identifies itself honestly and does not pretend to be a browser. Spoofing a user agent would convert some of these refusals into successes, but it would be both rude and self-defeating — a figure obtained by circumventing a site's stated wishes is not one this site could stand behind. The cost is a handful of links marked unverifiable, which seems the better trade.
What could not be verified
None of these could be established from a primary source. They are listed so that their absence is a documented finding rather than an unexplained silence.
| Not established | Why | Where |
|---|---|---|
| Founders and founding year | rootstock.io/about/ returns 404 and no Wikipedia article exists. No citable primary source was found. | in context |
| RSK Labs → IOV Labs → Rootstock Labs rename dates | Visible in repository and copyright changes, but not documented anywhere citable. | in context |
| Which firmware version each pegnatory runs | Not published. The attestation landing page lists member names with placeholder links and no attestation files. | in context |
| When each pegnatory joined or left | No published announcement accompanies any of the federation handovers. | in context |
| Historical signing thresholds | Derivable from the consensus rule but not readable per federation: the Bridge exposes the threshold only for the current federation, and the historical state is pruned. | in context |
| Emergency multisig timelock value | RSKIP201 says the value is "TBD"; the deployed value is not stated there. | in context |
| Emergency multisig threshold | RSKIP201 says 3-of-4 in prose and shows a 2-of-3 script. Unresolved in the document. | in context |
| Why a site refused this server | Geofencing, datacentre blocking and bot filtering all return 403 and cannot be told apart from one vantage point. Such links are marked unverifiable rather than guessed at. | in context |
| Which RSKIPs shipped in Wasabi, Bamboo and Ginger | Those upgrades have no network-upgrade RSKIP and their release notes cite no RSKIP numbers. 28 Adopted proposals are in force with no release on record. | in context |
| mnr_* RPC request and response shapes | Not covered by either part of the official JSON-RPC method reference. | in context |
| Bitcoin hashrate share merge-mining Rootstock | Cannot be derived from a Rootstock node, which cannot see Bitcoin blocks that carried no tag. Quoted from Rootstock with its source. | in context |
If you can close any of these with a primary source, the suggestion form is the fastest route.
Running it yourself
Everything on this page can be reproduced against any Rootstock mainnet node:
# point at a node (defaults to 127.0.0.1:4444)
export RSK_RPC_HOST=127.0.0.1
export RSK_RPC_PORT=4444
node tools/collect.js # refresh every feed
node tools/collect.js powpeg # just the federation history
node build.js # render the site into public/
The PowPeg collector's first run needs the whole chain's worth of
commit_federation events. Sweeping for those with eth_getLogs
takes hours, so where the node exposes its Bridge event index the collector bootstraps from
that instead and finishes in seconds. Every run after the first is incremental and needs
neither.
Primary sources used across the site
- dev.rootstock.io — developer documentation
- rootstock.io — product and marketing pages
- rsksmart/rskj — the reference client and its release notes
- rsksmart/RSKIPs — consensus change proposals
- rsksmart/rsk-powhsm — PowHSM firmware and attestation docs
- rsksmart/rootstock-brand-system — the logomark, MIT licensed