feat(#80 part 2, #97): head-source corroboration + per-topic gossipsub scoring#101
Merged
Conversation
…-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.
33 tasks
This was referenced Jul 1, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
RawTracersees every copy.blockpub.CorroborationTrackerrecords the forwarding peer of the first delivery + every duplicate, per block header CID. No new protocol, no re-plumbing of the ingest path.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.--head-corroboration-peers(-1 auto), embeddedConfig.HeadCorroborationPeers.held_uncorrobstat on the dashboard dev page (plusrejected_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/msgsnow carry Lotus's exactTopicScoreParams(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
-shortsuite green (one pre-existing state/cache badger flake observed once, passes standalone, untouched by this PR).Closes #80. Closes #97.