Measuring the verification population

BSAHI — how we measure a population that cannot be counted. Produced: 2026-09-17 · Instruments: verification_population.py, seed_census.py, addrman_churn.py, inbound_census.py

The reframe

Not "how many Bitcoin nodes are there?" — the total population is not observable — but:

"How large is the independently reachable verification population, what is its composition, and what can we say about the part we cannot see?"

Four quantities are reported separately and never conflated:

#quantitywhat it islayergrade
Agossip-observed addressesaddresses peers have gossiped (addrman) — not nodesobservedC
Breachable nodesnodes that accept a connection from a crawlerobservedB
Cnon-listening / private nodesnever appear in a crawl; evidence only via inbound peersunobservableD
Dtotal populationnot observable by any method

Three independent views (triangulation)

We now measure the same neighbourhood three different ways, from three different mechanisms. Their disagreement is the uncertainty, and it is published rather than hidden.

viewmechanismsizewhat it seesgrade
Crawlerconnect to reachable nodes26,586 nodesnodes that accept inboundB
DNS seedsresolve the bootstrap seeds264 addresses (8 seeds)addresses the seeds recently servedB
Our node's addrmangetnodeaddresses 034,599 addressesgossip our peers sent usC

What agrees: the crawler and the subtree it can reach are stable and internally coherent; the seed and addrman views overlap the crawler's address space.

What disagrees, and why it matters: the three counts differ by an order of magnitude because they measure different objects — connectable nodes ({reach:,}) versus addresses ({seedunion:,}, {addr:,}) — and addresses accumulate stale, rotating and ephemeral entries. Reporting any one of them as "the number of Bitcoin nodes" is the error this page exists to prevent.

The address-manager number is a lower bound on gossip-observed addresses, not a node count. First measurement with an exact request (getnodeaddresses 0) returned 34,599 addresses — more than the 32,000 that an earlier request ceiling reported, which is exactly why the ceiling figure was retired.

The observable part, partitioned

Partitioning the 26,577 reachable nodes by signals a crawl can see:

tiernodessharegraderole
------:---:------
T1 serving + synced23,94990.1%Bfull/pruned validating validator, actively serving
T2 serving + lagging2,0817.8%Bintermittent / catching-up validator
T3 no service announced5472.1%Breachable but announces no serving capability — consumer, not infrastructure
T4 height unreported00.0%Cunclassifiable from this capture

Network: clearnet 9,601 (36%) · Tor 12,745 (48%) · I2P 4,231 (16%). Tor and I2P are reachable to a crawler that speaks those transports, which is why IP geography is unresolved for ~64% of the set.

The unobservable part — and the direction of the error

Non-listening, private and Tor-hidden validators cannot be audited. They are excluded from the index and reported as an explicit sensitivity band, because excluding them does not remove their cost:

NL_net (USD/block)SCCRexternality vs baseline
---:---:---:---:
26,586 (measured floor)$4,6760.36241.00×
50,000$8,7930.19271.88×
80,000$14,0700.12043.01×
100,000$17,5870.09633.76×
150,000$26,3800.06425.64×
200,000$35,1740.04827.52×
265,860 (Erlay 9:1)$46,7560.036210.00×

Literature bracket. Erlay: Efficient Transaction Relay for Bitcoin (CCS'19 / arXiv:1905.10518) reports private:public ≈ 9:1 for the network at the time. Applied to the measured public set (26,586) that implies a total of ~265,860. This is a Grade D topology prior, not a measurement — it brackets the externality and is never a revised N.

Direction: excluding hidden nodes makes L_net a lower bound and the SCCR an upper bound. The baseline is conservative.

First-party measurement of the hidden set

Two instruments aim at quantity C, which no crawler can see:

What would strengthen this

  1. Reachability for the node (port-forward or Tor) → the inbound census produces a genuine lower bound on non-listening nodes.
  2. Time — churn and seed views need repeated samples; the "missing" numbers accrue automatically.
  3. A healthy node — it is currently reindexing after a disk-full chainstate corruption.

Grades

leglayergrade
reachable nodes (crawler)observedB
gossip-observed addresses (addrman)observedC
seed-visible addressesobservedB
activity partition of the reachable setobservedB (T4 C)
non-listening / total populationunobservableD / —
inbound censusobservedB (once reachable)

Why this is the honest method

A census of Bitcoin's node population does not exist. What exists is a set of partial views with different biases. BSAHI publishes the views, the mechanisms behind them, the direction of their error, and the gap — instead of collapsing them into one confident number.

Data: `verification_population.json` · `seed_census.json` · `addrman_churn.json` · `inbound_census.json` · Methodology · Evidence Matrix

Data source: data/verification_population.json — deterministic, frozen-input instrument; re-runnable offline.

← All research · ← Back to Learn