-
Notifications
You must be signed in to change notification settings - Fork 1.2k
feat: a Gossipsub control plane with topic abstractions, a peer crawler and a peer controller #16036
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
feat: a Gossipsub control plane with topic abstractions, a peer crawler and a peer controller #16036
Conversation
…and-refactor-fork-watcher
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR refactors Gossipsub subscription management into a more modular and maintainable architecture by introducing a controller pattern with topic family abstractions, a peer crawler for discovering peers subscribed to specific topics, and a dialer for maintaining peer connections.
Key changes:
- Introduces
GossipsubControllerto manage topic subscriptions across fork boundaries with lifecycle management - Adds
GossipsubPeerCrawlerto discover and index peers by gossipsub topics using discv5 - Implements
GossipsubPeerDialerto maintain minimum peer counts per topic
Reviewed Changes
Copilot reviewed 39 out of 39 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| changelog/aarshkshah1992-gossipsub-peer-crawler.md | Adds changelog entry for discV5 peer crawler |
| changelog/aarshkshah1992-gossipsub-control-pane.md | Documents new Gossipsub controller with topic abstractions |
| beacon-chain/sync/topic_families_without_subnets.go | Implements topic families for non-subnetted topics (blocks, exits, slashings, etc.) |
| beacon-chain/sync/topic_families_static_subnets.go | Implements blob topic family with static subnet assignments |
| beacon-chain/sync/topic_families_dynamic_subnets.go | Implements topic families with dynamic subnet subscriptions (attestations, sync committees, data columns) |
| beacon-chain/sync/gossipsub_topic_family.go | Defines topic family interfaces and fork-aware scheduling logic |
| beacon-chain/sync/gossipsub_controller.go | Implements main controller for managing topic family lifecycle across forks |
| beacon-chain/sync/gossipsub_base.go | Provides base implementation for topic subscription and message handling |
| beacon-chain/sync/service.go | Integrates gossipsub controller into sync service startup |
| beacon-chain/sync/fork_watcher.go | Updates fork watcher to focus on RPC handlers only |
| beacon-chain/sync/subscriber.go | Removes old subscription management code now handled by controller |
| beacon-chain/p2p/gossipsubcrawler/interface.go | Defines interfaces for crawler and dialer components |
| beacon-chain/p2p/gossipsub_peer_crawler.go | Implements peer discovery and indexing by gossipsub topics |
| beacon-chain/p2p/gossipsub_peer_controller.go | Implements dialer to maintain minimum peers per topic |
| beacon-chain/p2p/service.go | Initializes crawler and dialer in p2p service |
| beacon-chain/p2p/subnets.go | Refactors subnet peer management to use new crawler/dialer |
| beacon-chain/p2p/broadcaster.go | Updates broadcasting to use new topic helpers and dialer |
| Test files | Adds comprehensive test coverage for new components |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
09d886c to
8c3ecc4
Compare
8c3ecc4 to
09d886c
Compare
…-crawler-peer-controller' into feat/gossipsub-control-pane-peer-crawler-peer-controller
| // Collect topics from dynamic families only, de-duplicated. | ||
| topicSet := make(map[string]struct{}) | ||
| for _, df := range families { | ||
| topics, err := df.ExtractTopicsForNode(node) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we have a struct that extracts part of an enode needed for topic abstraction ?
| topics map[gossipsubcrawler.Topic]struct{} | ||
| } | ||
|
|
||
| type crawledPeers struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
need feedback on packaging/layout as this is started in the sync package.
| go func(node *enode.Node) { | ||
| defer g.pingSemaphore.Release(1) | ||
|
|
||
| if err := g.dv5.Ping(node); err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we have multiple instances with different timeouts ?
|
|
||
| func (g *GossipsubPeerDialer) dialLoop() { | ||
| ticker := time.NewTicker(time.Second) | ||
| defer ticker.Stop() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we bump up
// P2PMaxPeers defines a flag to specify the max number of peers in libp2p.
P2PMaxPeers = &cli.IntFlag{
Name: "p2p-max-peers",
Usage: "The max number of p2p peers to maintain.",
Value: 70,
}
| var peersToDial []*enode.Node | ||
|
|
||
| for _, topic := range topics { | ||
| newPeers := g.peersForTopic(topic, peerPerTopic) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kasey has some good ideas on how to prioritise topics to dial to and how to rank peers based on their CGC scores. He will elaborate during review.
| defer s.subnetLocker(subnet).Unlock() | ||
|
|
||
| if err := s.FindAndDialPeersWithSubnets(ctx, AttestationSubnetTopicFormat, forkDigest, minimumPeersPerSubnetForBroadcast, map[uint64]bool{subnet: true}); err != nil { | ||
| if err := s.gossipsubDialer.DialPeersForTopicBlocking(ctx, topic, minimumPeersPerSubnetForBroadcast); err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kasey has some good ideas on how to do async broadcast for data column topics which are starved of peers.
What type of PR is this?
Feature
What does this PR do? Why is it needed?
This PR overhauls the beacon node's Gossipsub management system to make it more testable, maintainable and readable. It also introduces proactive peer discovery and connection management for gossipsub peers that advertise subnets we're interested in.
This PR introduces four major components:
Topic abstractions and a declarative fork based schedule
Adds topic interfaces and implementations for all topics (without subnets, with static subnets and dynamic subnets) that the beacon-node should subscribe to/publish to. It also implements a declarative fork/epoch based schedule for subscribing/unsubscribing to these topics.
A Gossipsub controller
This controller is the heartbeat of the system and is responsible for ensuring that the beacon-node is subscribed to the right set of topics across forks and across slots & epochs within a fork. It manages subscriptions for topics without subnets, topics with static subnets and topics with dynamic subnets. It ensures we subscribe and unsubscribe from topics based on a pre-determined declarative fork based subscription schedule. It also ensures we unsubscribe from subnetted topics when we leave a subnet and subscribe to a
A DiscV5 peer crawler for indexing gossipsub peers
This crawler periodically does random walks on the discv5 network to index peers that advertise subnets we're a part of/we want to publish to. It also pings them to ensure they are reachable and discards unreachable peers.
A peer controller
This component proactively and periodically looks up the crawler for peers that subscribe to topics we want to subscribe to or publish to for a given slot and connects to them. It ensures that the mesh for each of this topics has enough high score peers in it.
This PR pushes details about identifying topics from subnets into the topic abstractions so that the rest of the system only has to work with topics which are strings. This simplifies a lot of code that deals with discovering and dialing to peers that are parts of specific subnets and for subscribing to topic based subnets.
It also removes a bunch of legacy code in subscriber.go and subnets.go that we no longer need after this overhaul.
Which issues(s) does this PR fix?
Fixes #
Other notes for review
Acknowledgements