Skip to content

feat(#80 part 2, #97): head-source corroboration + per-topic gossipsub scoring#101

Merged
Reiers merged 2 commits into
mainfrom
feat/80-head-source-diversity
Jul 1, 2026
Merged

feat(#80 part 2, #97): head-source corroboration + per-topic gossipsub scoring#101
Reiers merged 2 commits into
mainfrom
feat/80-head-source-diversity

Conversation

@Reiers

@Reiers Reiers commented Jul 1, 2026

Copy link
Copy Markdown
Owner

What

The last two bricks in the running-head trust story (epic #100). Pre-soak hardening so the calibration dress rehearsal (sync + block production + PDP, snapshot-free) runs on a fully hardened head path.

#80 part 2 — head-source corroboration

  • The trick: gossipsub dedups messages before subscribers see them, but its RawTracer sees every copy. blockpub.CorroborationTracker records the forwarding peer of the first delivery + every duplicate, per block header CID. No new protocol, no re-plumbing of the ingest path.
  • Adoption rule (blockpub.CorroborationGate, wired at the same chokepoint as the Running-head fork choice: heaviest-ParentWeight + periodic re-quorum (not boot-only) #79 divergence gate): adopt head H only when ≥N distinct peers forwarded H, or a trusted floor peer did (super-vote). Requirement clamps to connected-peer count (floor 1): a small node never wedges.
  • Hold semantics: held block retries 3×1.5s (corroborating duplicates arrive within ~1s on a healthy mesh), then dropped; the polling Sync stays the safety net. Corroboration can delay adoption, never wedge it.
  • Defaults: Light/PDP off, Full tier 2. Standalone --head-corroboration-peers (-1 auto), embedded Config.HeadCorroborationPeers.
  • New held_uncorrob stat on the dashboard dev page (plus rejected_lighter/held_diverged, which existed but weren't exposed).

#97 — per-topic gossipsub score params

The per-topic score map was empty. /fil/blocks + /fil/msgs now carry Lotus's exact TopicScoreParams (first-delivery credit, invalid-message penalties). This is what makes "distinct scored peers" meaningful against Sybil swarms: fresh attacker peers have no delivery history, score ~0, and decay out of the mesh.

Honesty boundary

Unchanged: hardening, not a finality guarantee (that's F3's job). Peer IDs are Sybil-cheap; the combination (topic scoring + IP-colocation penalties + trusted floor + corroboration + heaviest-weight fork choice + divergence gate) is what raises the eclipse cost.

Verification

  • Full build + vet clean, CGO off. gofmt clean.
  • New tests: tracker (distinct-source counting, repeat dedup, topic filter, garbage rejection, FIFO eviction), gate (thresholds, super-vote, peer-count clamp, disabled), ingestor (hold, retry-adopt via seen-bypass, retry exhaustion + post-exhaustion dedup, nil-gate unchanged behavior).
  • Full -short suite green (one pre-existing state/cache badger flake observed once, passes standalone, untouched by this PR).
  • Live calibration behavior gated behind defaults (off on Light/PDP), so the soak can A/B it safely.

Closes #80. Closes #97.

Reiers added 2 commits July 1, 2026 22:27
…-floor plumbing

The per-topic score map was empty: a peer that never usefully delivered
anything scored the same as one that consistently delivered blocks first.
/fil/blocks + /fil/msgs (mainnet + calibration) now carry Lotus's exact
TopicScoreParams (first-delivery credit, invalid-message penalties), which
is what makes #80's distinct-SCORED-peers corroboration bite against
Sybil swarms.

Also plumbs (for #80 part 2):
- HostConfig.PubSubTracer -> pubsub.WithRawTracer at construction
- Host.IsTrustedPeer: is p in the connmgr-protected trusted floor
- trustedFloorTag const replaces the inline tag string
… head adoption

Part 2 of #80 (part 1 = un-evictable trusted floor, shipped v1.8.5).

Gossipsub dedups messages before subscribers see them, so corroboration
is counted where every copy IS visible: blockpub.CorroborationTracker
rides the pubsub RawTracer, recording the forwarding peer of the first
delivery + every duplicate, per block header CID (CID binds the header
bytes, so a peer cannot vote for block H without sending H).

Adoption rule (blockpub.CorroborationGate, wired into the ingestor as
SetHeadCorroboration at the same chokepoint as the #79 divergence gate):
adopt head H only when
  - forwarders(H) >= N distinct peers, OR
  - a trusted floor peer forwarded H (super-vote).
The requirement clamps to the connected-peer count (floor 1) so a small
node never wedges. A held block is retried 3x1.5s (duplicates arrive
within ~1s on a healthy mesh) then dropped - the polling Sync stays the
safety net, so corroboration can delay adoption but never wedge it.

Defaults: Light/PDP off; Full tier 2 distinct sources. Standalone:
--head-corroboration-peers (-1 auto). Embedded: Config.
HeadCorroborationPeers. New held_uncorrob stat (+ rejected_lighter /
held_diverged now exposed) on the dashboard dev page.

Honesty boundary (unchanged): peer IDs are Sybil-cheap; this bites in
combination with #97 topic scoring + the trusted floor. Not a finality
guarantee - that is F3's job. Tests: tracker distinct/dedup/topic-filter/
eviction, gate thresholds/super-vote/clamp/disabled, ingestor hold/
retry-adopt/exhaustion/nil-gate.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant