Skip to content

Conversation

@jxs
Copy link
Member

@jxs jxs commented Sep 16, 2025

Description

This is a draft implementation of partial messages for gossipsub following the spec PR and based on the Go implementation. Still WIP but should give a good idea of the direction we're heading.

{
// Return err if trying to publish the same partial message state we currently have.
if existing.available_parts() == partial_message.available_parts() {
return Err(PublishError::Duplicate);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is correct.

  • Imagine you have parts 1,2,3.
  • You tell your peers about those parts.
  • A peer comes back and says I want part 2.
  • You republish with the same parts in order to respond.
  • You get this error and fail to respond.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for explaining Marco, updated as we spoke

data_transform: D,

/// Partial messages received.
partial_messages: HashMap<TopicHash, HashMap<Vec<u8>, P>>,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you need to store P here? I think it's better if P is owned solely by the application.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup, you are right, thanks Marco!

pub(crate) struct PartialData {
pub(crate) ihave: Vec<u8>,
pub(crate) iwant: Vec<u8>,
pub(crate) message: Vec<u8>,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it useful to store the message here? It seems like wasted space, you only use it to check if the peer is sending you a duplicate.

Might be simpler to let the application handle dupes.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks Marco, I only left wanted and has wanted to avoid sending the same message and has to avoid notifying the application layer of duplicates.
Thanks!

@jxs jxs force-pushed the gossipsub-partial-messages branch 5 times, most recently from cb0e925 to e6f1ae4 Compare September 26, 2025 11:35
@jxs jxs force-pushed the gossipsub-partial-messages branch from e6f1ae4 to 69c2d95 Compare September 26, 2025 14:24
/// 5. Received partial data is integrated using `extend_from_encoded_partial_message()`
/// 6. The `group_id()` ties all parts of the same logical message together
pub trait Partial {
type Metadata: Metadata;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should parts_metadata return this?

Copy link
Member

@dknopik dknopik Oct 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After discussion, I think the way to go is to remove the assoc type and keep parts_metadata the way it is for now :)

pub fn publish_partial<P: Partial>(
&mut self,
topic: impl Into<TopicHash>,
partial_message: P,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

&P? 🙏

@jxs jxs changed the title Gossipsub partial messages feat: implement gossipsub partial messages extension Oct 15, 2025
jxs and others added 8 commits October 15, 2025 11:56
I noticed two issues during testing.

1.  We allow our mesh to grow greater than `mesh_n_high`, intentionally
2.  There is a potential underflow in the heartbeat that can cause a panic

For the first 1. This looks like its intentional but I can't recall why we would have added it. I think its counter-intuitive to allow our mesh to grow larger than the specified parameter. I suspect we added it to prevent our mesh from being filled with inbound peers and potentially being eclipsed. I suspect the best approach here is to remove inbound peers in the mesh maintenance rather than exceeding the mesh_n_high configuration.

For 2. There is an underflow which this PR prevents. It can be triggered for low mesh_n_high values, i.e 0. This shouldn't be a concern for regular users, but we shouldn't have code that can panic based on user configuration.

Pull-Request: libp2p#6183.
Adds links to related tech mentioned in examples/README.
This is useful to people new to the field, like me.

Pull-Request: libp2p#6016.
Split off from libp2p#6183, to quote:
>I noticed two issues during testing.
>
>We allow our mesh to grow greater than mesh_n_high, intentionally
>This looks like its intentional but I can't recall why we would have added it. I think its counter-intuitive to allow our mesh to grow larger than the specified parameter. I suspect we added it to prevent our mesh from being filled with inbound peers and potentially being eclipsed. I suspect the best approach here is to remove inbound peers in the mesh maintenance rather than exceeding the mesh_n_high configuration.

Pull-Request: libp2p#6184.
.connected_peers
.iter()
.filter(|(_, p)| p.topics.contains(&topic_hash))
.filter(|(_, peer)| {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additionally, I think we need a filter like this here:

            .filter(|(_, p)| p.topics.contains(&topic_hash))

/// Helper function to get a subset of random gossipsub peers for a `topic_hash`
/// filtered by the function `f`. The number of peers to get equals the output of `n_map`
/// that gets as input the number of filtered peers.
#[allow(unused, reason = "partial is used with partial_messages feature")]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#[allow(unused, reason = "partial is used with partial_messages feature")]
#[allow(unused, reason = "exclude_partial is used with partial_messages feature")]


/// Helper function to get a set of `n` random gossipsub peers for a `topic_hash`
/// filtered by the function `f`.
#[allow(unused, reason = "partial is used with partial_messages feature")]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#[allow(unused, reason = "partial is used with partial_messages feature")]
#[allow(unused, reason = "exclude_partial is used with partial_messages feature")]

let mut gossip_peers = connected_peers
.iter()
.filter(|(_, p)| p.topics.contains(topic_hash))
.filter_map(|(peer_id, peer)| {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additionally, I think we need a filter like this here:

            .filter(|(_, p)| p.topics.contains(&topic_hash))

## Description

Changelog was incorrect as we didn't release version `0.5.1`
cc @RolandSherwin
@jxs jxs force-pushed the gossipsub-partial-messages branch from 9efdb00 to f728315 Compare October 28, 2025 09:55
@jxs jxs force-pushed the gossipsub-partial-messages branch 3 times, most recently from 58d211b to c256ac6 Compare October 29, 2025 14:13
@jxs jxs force-pushed the gossipsub-partial-messages branch from c256ac6 to 9545140 Compare October 29, 2025 14:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants