Support Gossipsub partial messages - #210
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds opt-in support for the Gossipsub v1.3 Partial Messages extension to the Pubsub router, exposing a topic-level application API to send/receive partial payloads and integrating capability advertisement and per-peer gating into subscription handling and gossip flow.
Changes:
- Introduces
IPartialMessagesTopic+PartialMessage/PartialMessagesTopicOptionsand wires partial-message delivery throughTopic/PubsubRouter. - Adds router support for advertising/processing the Partial Messages extension (including per-topic subscription flags and a new
OnPartialGossipcallback path). - Adds unit tests covering opt-in requirements and basic advertisement/gating behavior.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/libp2p/Libp2p.Protocols.Pubsub/Topic.cs | Implements IPartialMessagesTopic, wires partial-message events, adds publish/send APIs for partial payloads. |
| src/libp2p/Libp2p.Protocols.Pubsub/PubSubSettings.cs | Adds EnablePartialMessages opt-in setting. |
| src/libp2p/Libp2p.Protocols.Pubsub/PubsubRouter.Topics.cs | Adds GetPartialMessagesTopic, subscription capability flags, and partial publish/send routing APIs. |
| src/libp2p/Libp2p.Protocols.Pubsub/PubsubRouter.Rpc.cs | Parses incoming partial-message extension payloads and tracks per-peer partial subscription flags. |
| src/libp2p/Libp2p.Protocols.Pubsub/PubsubRouter.cs | Adds extension advertisement and heartbeat logic to swap some IHAVE gossip for OnPartialGossip callbacks. |
| src/libp2p/Libp2p.Protocols.Pubsub/PartialMessage.cs | Adds PartialMessage and PartialMessagesTopicOptions public API types. |
| src/libp2p/Libp2p.Protocols.Pubsub/IPartialMessagesTopic.cs | Adds the public partial-messages topic interface. |
| src/libp2p/Libp2p.Protocols.Pubsub.Tests/PartialMessagesTests.cs | Adds unit tests for opt-in, advertisement, and per-peer gating. |
Suppressed comments (1)
src/libp2p/Libp2p.Protocols.Pubsub/Topic.cs:82
- Topic.Unsubscribe() currently calls router.Unsubscribe() only when IsSubscribed is false, which prevents unsubscribing when the topic is actually subscribed and can cause subscription state to get stuck.
public void Unsubscribe()
{
if (!IsSubscribed) router.Unsubscribe(topicName);
}
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
273d3ac to
c03196f
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.
Suppressed comments (3)
src/libp2p/Libp2p.Protocols.Pubsub/Topic.cs:82
- Topic.Unsubscribe() currently calls router.Unsubscribe(topicName) only when the topic is not subscribed, which makes Unsubscribe a no-op for subscribed topics (and can trigger an unnecessary unsubscribe call when already unsubscribed). Flip the condition so subscribed topics are actually unsubscribed.
public void Unsubscribe()
{
if (!IsSubscribed) router.Unsubscribe(topicName);
}
src/libp2p/Libp2p.Protocols.Pubsub/PubsubRouter.Topics.cs:64
- CreateSubscription() sets RequestsPartial/SupportsSendingPartial whenever partial messages are enabled and the local Topic has flags, but the resulting SubOpts are sent to all peers (including non-v1.3 streams) via OutboundConnection() and AnnounceSubscription(). This contradicts the PR description constraint to advertise capabilities only on v1.3 streams. Consider constructing per-peer subscription updates so these fields are only populated when sending over Gossipsub v1.3 (SupportsExtensions), otherwise leave them unset/false.
private Rpc.Types.SubOpts CreateSubscription(string topicId, bool subscribe)
{
Rpc.Types.SubOpts subscription = new() { Subscribe = subscribe, Topicid = topicId };
if (subscribe && _settings.EnablePartialMessages && topicState.TryGetValue(topicId, out Topic? topic))
{
subscription.RequestsPartial = topic.RequestsPartialMessages;
subscription.SupportsSendingPartial = topic.SupportsSendingPartialMessages;
}
src/libp2p/Libp2p.Protocols.Pubsub/PartialMessage.cs:42
- PartialMessagesTopicOptions uses the name SupportSendingPartialMessages, while other related APIs use SupportsSendingPartialMessages (plural) (e.g., IPartialMessagesTopic.SupportsSendingPartialMessages). This inconsistency makes the public API harder to discover and can lead to confusion. Consider renaming the option to SupportsSendingPartialMessages while the API is still new.
/// <summary>
/// Signals that this topic can send partial data and receive parts metadata.
/// </summary>
public bool SupportSendingPartialMessages { get; init; }
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.
Suppressed comments (2)
Previously missed (1) — in code that hasn't changed since the last review.
src/libp2p/Libp2p.Protocols.Pubsub/Topic.cs:82
- Topic.Unsubscribe() calls router.Unsubscribe() when IsSubscribed is false. This is inverted logic and can trigger KeyNotFoundException in PubsubRouter.Unsubscribe(topicId) (it indexes fPeers[topicId]) when called on an already-unsubscribed topic.
public void Unsubscribe()
{
if (!IsSubscribed) router.Unsubscribe(topicName);
}
src/libp2p/Libp2p.Protocols.Pubsub/PubsubRouter.Rpc.cs:254
- Partial-messages subscription flags are not being honored as sent by the peer: SupportsSendingPartialMessages is stored as (RequestsPartial || SupportsSendingPartial). This causes the router to treat a peer that only set RequestsPartial as also supporting the metadata flow, and may send PartsMetadata contrary to the peer's advertised capability.
if (_settings.EnablePartialMessages && state.SupportsPartialMessagesExtension)
{
bool requestsPartialMessages = sub.RequestsPartial;
state.UpdatePartialMessagesSubscription(
sub.Topicid,
requestsPartialMessages,
sub.SupportsSendingPartial);
}
6c14089 to
f1fa49d
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.
Suppressed comments (1)
src/libp2p/Libp2p.Protocols.Pubsub/Topic.cs:37
OnRouterPartialMessageforwards partial payloads even when the topic is not subscribed and even when the topic was never configured for partial messages. This makes partial-message delivery inconsistent withOnRouterMessageand undermines the intended opt-in behavior (topics created viaGetTopiccan still receive partial messages if the event is hooked via an interface cast). Gate partial-message delivery onIsSubscribedand on the topic having partial-message capabilities enabled.
private void OnRouterPartialMessage(string topicName, PeerId peerId, PartialMessage message)
{
if (this.topicName != topicName)
{
return;
}
f1fa49d to
c9a37f8
Compare
36a5fe2 to
63c375a
Compare
Summary
Validation