fix(das): prevent bridge DASer from receiving gossip headers before EDS is stored#4820
Open
walldiss wants to merge 3 commits intocelestiaorg:mainfrom
Open
fix(das): prevent bridge DASer from receiving gossip headers before EDS is stored#4820walldiss wants to merge 3 commits intocelestiaorg:mainfrom
walldiss wants to merge 3 commits intocelestiaorg:mainfrom
Conversation
Wondertan
reviewed
Mar 4, 2026
380e6fa to
0f1cba4
Compare
…DS is stored Add WithTopicOpts(pubsub.FanoutOnly()) to the bridge node's p2p header subscriber so the bridge can broadcast headers but never receives incoming gossip messages. This eliminates the race condition where a bridge node's DASer would try to sample EDS for a gossiped header that the local core.Listener hasn't finished storing yet, causing spurious "requesting data from peer failed" WARN logs (issue celestiaorg#4802). Bumps go-header to v0.8.3-rc which introduces p2p.WithTopicOpts, and adds the celestiaorg/go-libp2p-pubsub replace directive required for pubsub.FanoutOnly() support. The fx.Decorate for the bridge's p2p.Subscriber uses fx.Annotate with fx.OnStart/fx.OnStop to ensure Start() is called on the decorated instance; without the lifecycle hooks s.topic remains nil and Broadcast panics. Closes celestiaorg#4802
0f1cba4 to
f1c205a
Compare
Wondertan
previously approved these changes
Mar 4, 2026
nodebuilder/header/module.go
Outdated
Comment on lines
+62
to
+67
| // Bridge nodes must not receive headers via p2p gossip: a remote peer | ||
| // can gossip the same header before the local core.Listener finishes | ||
| // storing EDS, causing the DASer to access EDS prematurely. | ||
| if tp == node.Bridge { | ||
| opts = append(opts, p2p.WithTopicOpts(pubsub.FanoutOnly())) | ||
| } |
Member
There was a problem hiding this comment.
i would also extract that in a separate func that returns fx.Option and take node type, but non blocking
The celestiaorg/go-libp2p-pubsub fork (required for FanoutOnly support) does not support subscription exchange over mocknet connections without the companion go-libp2p fork (which has incompatible quic-go deps). Replace mocknet with real libp2p hosts in the three affected tests so the pubsub protocol handshake completes correctly.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #4820 +/- ##
==========================================
- Coverage 44.83% 35.75% -9.09%
==========================================
Files 265 311 +46
Lines 14620 21460 +6840
==========================================
+ Hits 6555 7672 +1117
- Misses 7313 12792 +5479
- Partials 752 996 +244 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
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.
Summary
Fixes #4802
Bridge nodes subscribe to the p2p header gossip topic. Remote peers can gossip the same header before the local
core.Listenerfinishes storing EDS, causing the DASer to look up a header it just received, callHasByHeight, fall through toGetEDSover shrex, and log a flood of WARN messages at every block height:Fix: Add
p2p.WithTopicOpts(pubsub.FanoutOnly())to the bridge node'sp2p.Subscriber. WithFanoutOnly, the subscriber can still broadcast (gossip headers out), but it never receives incoming gossip messages. The DASer only processes headers that the localcore.Listenerproduced, guaranteeing EDS is already in the store.Implementation notes:
fx.Decoratefor the bridge'sp2p.Subscriberwraps withfx.Annotate(..., fx.OnStart, fx.OnStop)— without explicit lifecycle hooks the decorated instance'sStart()is never called, leavings.topic = niland causing a panic inBroadcast.go-headertov0.8.3-rcwhich introducesp2p.WithTopicOpts.replace github.com/libp2p/go-libp2p-pubsub => github.com/celestiaorg/go-libp2p-pubsubrequired forpubsub.FanoutOnly()support.closes https://linear.app/celestia/issue/DA-1072