# Week 14 — Update ## TL;DR Implemented gossipsub topic membership (JOIN / LEAVE) in zig-libp2p. PR: https://github.com/zen-eth/eth-p2p-z/pull/83/commits/eb84618eeeb6242a736be147d5e2e743aebf5ac0 --- ## High-level behavior - The pubsub RPC (SUBSCRIBE / UNSUBSCRIBE) announces subscription changes to all peers. We assume a pubsub framework sends those RPCs. - Gossipsub must additionally maintain its topic mesh state locally. JOIN(topic) and LEAVE(topic) perform mesh-specific actions on top of the RPCs. - On JOIN(topic), the router builds mesh[topic] by moving peers from fanout[topic] (if any) and selecting peers from peers.gossipsub[topic] up to D; then it informs those peers with GRAFT messages. - On LEAVE(topic), the router sends PRUNE to peers in mesh[topic] and removes mesh[topic] from local state. --- ## JOIN(topic) — explicit steps When application calls JOIN(topic): 1. Ensure the pubsub framework sends SUBSCRIBE(topic) RPC (assumed). 2. Prepare mesh[topic]: - If fanout[topic] exists and contains peers: - Move as many peers from fanout[topic] into mesh[topic] as possible (up to D). - If mesh[topic] is still smaller than D: - Select peers from peers.gossipsub[topic] (excluding self and already-chosen peers) to fill mesh[topic] up to D. 3. For each peer newly added to mesh[topic], send a GRAFT control message indicating we added them to the mesh. 4. Persist mesh[topic] and begin mesh maintenance (heartbeat, mesh trimming/expansion as per gossipsub maintenance rules). Notes: - If fanout[topic] had more than D peers, take up to D into mesh and leave the rest (or prune depending on policy). - Only send GRAFT to peers that are not already known to be in the mesh on the remote side (avoid redundant grafts when possible). - Do not re-populate fanout[topic] from mesh during JOIN; fanout is for when we are not subscribed. --- ## LEAVE(topic) — explicit steps When application calls LEAVE(topic): 1. Ensure the pubsub framework sends UNSUBSCRIBE(topic) RPC (assumed). 2. If mesh[topic] exists: - For each peer in mesh[topic], send a PRUNE control message. - Remove mesh[topic] from local state (forget mesh membership). 3. Optionally preserve or clear fanout[topic] depending on policy: - If you want to publish later without joining, keep fanout; otherwise delete fanout[topic]. Notes: - PRUNE instructs peers to remove the link from their own mesh; follow-up mesh maintenance on their side will act accordingly. - After LEAVE, the router should stop treating topic as "subscribed" for publish behavior. --- ## Sequence diagram ```mermaid sequenceDiagram participant App participant Router participant Fanout as fanout[T] participant Gossip as peers.gossipsub[T] participant Mesh as mesh[T] App->>Router: JOIN(T) Router->>Fanout: take up to D peers -> move to mesh[T] alt mesh[T] < D Router->>Gossip: select peers to fill mesh[T] up to D end Router->>Mesh: send GRAFT to newly added peers ``` --- ## Pseudocode ```pseudo function join(topic): // pubsub framework should SUBSCRIBE(topic) externally mesh = mesh[topic] or empty set added = empty set if fanout[topic] exists: take = min(D - size(mesh), size(fanout[topic])) move_any(take, fanout[topic], mesh) added += those moved if size(mesh) < D: candidates = peers.gossipsub[topic] - mesh - {self} select = choose_up_to(D - size(mesh), candidates) mesh += select added += select mesh[topic] = mesh for p in added: send_graft(p, topic) ``` ```pseudo function leave(topic): // pubsub framework should UNSUBSCRIBE(topic) externally if mesh[topic] exists: for p in mesh[topic]: send_prune(p, topic) delete mesh[topic] ``` --- ## Next Start refactoring topic memory management: implement fanout lifecycle (TTL and replacements), make selection policy pluggable and testable, add unit tests above, and wire JOIN/LEAVE into the existing mesh maintenance heartbeat. --- ## References - Gossipsub v1.0 — Topic membership: https://github.com/libp2p/specs/blob/master/pubsub/gossipsub/gossipsub-v1.0.md#topic-membership