Skip to content

fix: mainnet bootstrap works out of the box (refresh peers from lotus v1.38.3, operator-aware quorum) - #176

Merged
Reiers merged 2 commits into
mainfrom
fix/mainnet-bootstrap-quorum
Oct 26, 2026
Merged

Reiers merged 2 commits into
mainfrom
fix/mainnet-bootstrap-quorum

Conversation

@Reiers

@Reiers Reiers commented Oct 26, 2026

Copy link
Copy Markdown
Owner

Problem (F10)

On a fresh machine, lantern init --filecoin-network mainnet on main (ecf21fa) fails out of the box:

9 sources assembled (libp2p=7, forest=2, user=0, gateway=0)
✗ Quorum NOT reached: best bucket has 3/5 sources
Error: bootstrap: quorum not reached: no single tipset reached 5 sources (countable=9, counted=3)

Reproduced live from the Mac mini today with the ecf21fa binary (exit 1). Of the 7 libp2p sources, devtty.eu was listed twice (same peer ID, tcp + quic) and times out, the Venus peer has no DNS record, and ChainSafe mainnet-0/-2 are Forest 0.39 nodes that refuse F3 cert-exchange. Lotus v1.38.3 mainnet.pi now lists only chain.love and /dnsaddr/bootstrap-mainnet.chainsafe-fil.io.

Worse than it looked: api.node.glif.io is served from chain.love infrastructure (same IP 46.229.170.7 as api.chain.love, x-chainlove-lb-* headers, the same non-release Lotus build 1.38.3+mainnet+git.eaea3cd, and a bare HEAD redirects to filecoin.chain.love). So the 4 sources that agreed were 2 operators (chain.love x3 + ChainSafe x1), and the --bootstrap-quorum 4 workaround meant trusting two organisations.

Fix

Operator-aware quorum (chain/bootstrap).

  • Count DISTINCT OPERATORS, not endpoints. Default: 3 operators on mainnet and calibration.
  • Zero conflicts: any responder (counted or not) that names a different tipset for an instance someone else answered fails the probe with ErrConflict. Never retried, never outvoted. Different-instance answers are lag, not conflict. After the threshold is met the probe listens 3 s more so a late conflict is still seen.
  • Attribution: RPC URL domain through an evidence-backed alias table (glif.io -> chain.love, chainsafe.dev -> chainsafe-fil.io); libp2p peers by the DNS domain of their bootstrap multiaddr (or the /dnsaddr root that published them); one source per peer ID.

Sources.

Guidance. init/doctor/repair print which sources failed (with operator), operators answered vs required, and the flags that help (--peer, --no-libp2p, --bootstrap-quorum N). Conflicts get a separate message that does not suggest lowering the quorum. Too-few-configured-operators is reported without a pointless retry. lantern doctor explains what a missing anchor means for the daemon.

F11 (added mid-task).

  • lantern daemon without an init-written bootstrap-anchor.json used to anchor silently via gateway+RPC agreement (which, with Glif = chain.love, was one operator). It now refuses and points at init/doctor; --allow-rpc-anchor restores the old path with a loud WARN. Devnet and --insecure-anchor unchanged. reset --chain-state and README now say to run lantern repair before restarting.
  • Stale F3: mainnet F3 is stuck at instance 466453 / epoch 5824156 (~231 days behind). init/repair: stale F3 finality (~203 days) breaks fresh installs; fall back to EC multi-source anchor #167 already refused to anchor on it; now the EC fallback also ignores it as a cross-check (it made the single-operator "F3-consistent heaviest" rule reachable). The fallback re-samples on disagreement and compares operators at a common epoch 5 below the lowest head when their heads straddle an epoch boundary (needed now that the voters are really different backends).

Reasoning and the source/operator table are in TRUST-MODEL.md section 2.9.

Live verification (this Mac, temp LANTERN_HOME, LANTERN_PASS='', deleted after)

# mainnet, defaults
8 sources assembled from 4 distinct operators (libp2p=4, rpc=4, user=0, gateway=0)
✓ Quorum reached: 4 distinct operators agree (need 3): instance=466453 epoch=5824156
  Operators: ankr.com, chain.love, chainsafe-fil.io, filfox.info
  Elapsed: 1.073s, sources answered: 6/8, distinct operators reachable: 4/4
  ⚠ F3 finality is stale ... ~231.4 days behind wall-clock head (#167)
  ✓ EC anchor: epoch 6490646 via multi-source-agreement-aligned (2 independent operators agree, f3-checked=false)
  ✓ Trust anchor written            (exit 0, source=ec-multi-source)

# calibration, defaults
7 sources assembled from 4 distinct operators (libp2p=4, rpc=3, user=0, gateway=0)
✓ Quorum reached: 4 distinct operators agree (need 3): instance=673501 epoch=4189981
  ✓ Trust anchor written            (exit 0, source=f3-quorum)

# daemon with no anchor
Error: no trust anchor at .../mainnet/bootstrap-anchor.json: `lantern init --filecoin-network mainnet` has not completed. ...  (exit 1)

go build ./... && go vet ./... && go test ./... green (CGO_ENABLED=0 locally).

Security tradeoffs

  • The number drops (5 -> 3) but the bar rises: 3 different organisations instead of "5 endpoints", which in practice was 2 operators.
  • No-conflict rule trades liveness for safety: one misbehaving default source can block bootstrap (fail closed), it cannot steer it.
  • When F3 is stale (mainnet today) the written anchor comes from the EC fallback, which requires 2 operators, not 3. That is the existing Security: boot trusted-root is accepted from gateway/Glif without weight or F3-finality verification #54 bar, now honest about stale F3 and with Glif no longer double-counted. Raising it to 3 is possible later (Ankr could be a third EC voter) but would make the fallback more brittle.
  • Ankr's backend independence cannot be proven from outside (different Lotus build than chain.love and Filfox); it is never needed alone.
  • Operator attribution is a heuristic: it collapses known duplicates (each alias carries evidence and a date), it cannot prove independence.
  • F11 is a behaviour change: deployments that ran lantern daemon without ever running init must run init/repair once or pass --allow-rpc-anchor. The installer already runs init. Embedded pkg/daemon is not changed in this PR.

… v1.38.3, operator-aware quorum)

F10: count distinct operators (default 3) with zero conflicting answers,
fold glif.io onto chain.love, refresh bootstrap peers from lotus v1.38.3
with /dnsaddr resolution, add Filfox/Ankr RPC sources, send a lantern
User-Agent, print operator-aware failure hints.

F11: the daemon refuses to boot without an init-written anchor unless
--allow-rpc-anchor; a stale F3 cert is ignored in the EC anchor fallback,
which now compares independent operators at a common epoch.
…-quorum

# Conflicts:
#	README.md
#	cmd/lantern/main.go
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant