Skip to content

[W6.4] gossipsub v1.1 (gate) #23

Closed

Description

@leolara

Unit W6.4 of docs/PLAN.md.

Gossipsub v1.1: the RPC codec, mesh, scoring, and the heartbeat as one pure step with time as an Event (§3.3), the signing policies, and the bounded queues of base/conc.

Where the spec lives

  • The unit row: root docs/PLAN.md — the deliverable, the dependencies, the priority.
  • The frozen interfaces: root docs/ARCHITECTURE.md, §3 (the mechanisms) and §8 (this package).
  • The package's own docs: packages/libp2p/protocols/docs/ARCHITECTURE.md and its PLAN.md — read them first; they refine the root docs and never contradict them.
  • The reference: the spike branch, none — new work, the largest component (ARCHITECTURE §7). Read it before you implement. Port its tests, keep the wire bytes; the code shape follows §3, not the spike's internals (§7 preamble, §9).

Your freedom, and its cost

The docs govern, and they are yours to change. Where a better design exists, change it — and change the documents in the same pull request. A contract change starts at the root docs/ARCHITECTURE.md; the package docs follow it in the same change. Code that disagrees with the docs, or package docs that disagree with the root, does not merge.

Definition of done

  • The public surface follows ARCHITECTURE §4; the owned contracts hold.
  • The wire suite, the scoring and trickle regressions, and the interop gate: go and rust peers with no behavior difference.
  • The carried vector and property tests pass through the Tests suite.
  • lake build, lake test, and lake test -- +RTS -N1 -RTS are green; scripts/lint-imports.sh is green.
  • No sorry, no build warnings (CLAUDE.md, "Strict checking").
  • First submodule under your leaf? Widen the lib's globs in lakefile.toml in the same commit.

Depends on

Every issue is claimable from day one; you build ahead of open dependencies against mocks of their frozen interfaces (RULES.md, "Working ahead of the tree").

Ground rules

  • Comment claim to take the issue; an organiser assigns it. One issue at a time.
  • A pull request within 8 hours of the assignment; drafts count. Link the issue (Closes #N). Miss the window, lose the claim.
  • Target the hackathon26 branch.
  • The license-acceptance line of the PR description stays ticked; commits carry no AI co-author trailers. Two guards fail the PR otherwise.
  • Prose register everywhere: CLAUDE.md, "Writing Style".
  • A contract question the docs do not settle: ask on this issue before you code past it.

Activity

  1. IvanAnishchuk commented on Nov 2, 2026

    @IvanAnishchuk
    Contributor

    W1.1 (#27) changes frozen signatures this unit builds on, so I'm posting here as RULES.md asks ("Working ahead of the tree"). The change is approved on the PR: #27 (comment)

    Everything that can park now runs in Conc.Async, since a parked Async holds no OS thread (5000 parked receivers: 12 threads, against 5005 with a blocking IO.wait; scripts/park-threads.lean).

    What gossipsub will see:

    • Chan.send and Chan.recv are Async. send answers .error .closed on a closed channel, and trySend never parks.
    • Chan.new wants a proof of 0 < capacity, so a queue can't end up with capacity 0 by accident. Chan.newUnbounded is the named exception, and it needs its reason in the docstring.
    • select is Async and takes a proof that its array of parks isn't empty.
    • Alarm is new: the task that wakes a loop at the due time its core asked for last. I think the heartbeat fits on it.
    • The protocols package doc lists Async with its other base/conc imports now.

    Until #27 merges, build against a mock of it (RULES.md); once it merges, rebase.

  2. IvanAnishchuk commented on Nov 4, 2026

    @IvanAnishchuk
    Contributor

    The W4.2 pull request (#47) changes the TCP close discipline of root ARCHITECTURE §4.7, which the Connection of net/streams carries to every layer above it.

    • close sends a FIN when no write is in flight, and an RST when one is. On v4.34, a write to a peer that stops reading never completes. libuv's shutdown waits behind it, and the write request holds the socket and its descriptor. A C shim in net/streams ends such a connection, and the peer gets an RST. A failed write follows the same rule.
    • A read that meets the peer's RST answers none, the end-of-stream channel of §3.5. go-libp2p closes every TCP connection with an RST (linger 0, vendor/go-libp2p/p2p/transport/tcp/tcp.go, lines 278 to 281), so a session with a go node ends this way.

    The Connection type and its fields stay the same. The net/streams ARCHITECTURE, "Decisions", records both rules with their sources.

  3. Wenbobobo commented on Nov 4, 2026

    @Wenbobobo
    Contributor

    claim

  4. IvanAnishchuk commented on Nov 5, 2026

    @IvanAnishchuk
    Contributor

    #60 (W5.9) adds newStream to the host's public surface (packages/libp2p/host/docs/ARCHITECTURE.md), the call that opens an outbound stream: newStream (h : Host) (peer : PeerId) (protocols : List ProtocolId), answered with the selected id and the stream. With no live session, it dials the peer first. It is go-libp2p's host.NewStream (vendor/go-libp2p/core/host/host.go, lines 61 to 65). A client of this unit that opens its own stream reaches it through this call. No existing host signature changes.

  5. IvanAnishchuk commented on Nov 5, 2026

    @IvanAnishchuk
    Contributor

    #61 (W5.6) touches the docs of two packages this unit builds on, through the chain of root PLAN.

    • packages/libp2p/core/docs/ARCHITECTURE.md fixes the policy shapes, which the core surface left to the host: the gater's allowDial, allowInbound, and allowSecured; ResourceManager.openConnection with its ConnectionScope; and AddressRanker.rank over go-libp2p's AddrDelay schedule. No seam of SecurityProtocol, Muxer, MuxSession, or StreamHandler changes.
    • packages/libp2p/negotiate/docs/ARCHITECTURE.md gains upgradeWith, the upgrade with a checkpoint after the handshake, and negotiateStream, multistream-select over one muxed stream. upgrade keeps its signature.

    The host surface also has newStream (#60 posted it). A unit that holds a Host opens its streams through it, and one that serves streams registers a StreamHandler, unchanged.

  6. IvanAnishchuk commented on Nov 5, 2026

    @IvanAnishchuk
    Contributor

    #62 (W4.3, yamux) touches docs this unit builds on. No existing signature changes.

    • Root ARCHITECTURE §3.3: "The loop blocks on one channel" now reads "The loop blocks only on channels its shutdown closes".
    • base/bytes gains Bytes.take? (with sliceAt?), which moves out of Streams.Framing, and Bytes.Blob, the wrapper that gives core data a Repr for its bytes.
    • net/streams gains Streams.readLoop, the reader task of a session: a credit from the loop before each read, a post per chunk, and a post for the end of the connection.
    • net/yamux lands its session: Session.new role conn leftover clock keepalive, openStream, acceptStream, close, and join, serving the Stream seam.
  7. IvanAnishchuk commented on Nov 5, 2026

    @IvanAnishchuk
    Contributor

    #63 (W5.1) lands libp2p/identity and touches docs and types this unit builds on. No existing signature changes.

    • Libp2p.Identity exports KeyType, PubKey, PrivKey, PeerId, and Identity.Error. The entry points are PubKey.unmarshal?, PrivKey.unmarshal?, PubKey.marshal, PubKey.verify, PrivKey.sign : ByteArray → ExceptT Error IO ByteArray, PrivKey.toPublic, PeerId.ofPubKey, PeerId.ofBytes?, PeerId.toBytes, and PeerId.ofString?.
    • PeerId derives BEq, DecidableEq, Hashable, Ord, and Repr, as root §3.2 asks. ToString prints the parsed text form. The derived == also compares that form, so code that asks "same peer?" compares a.hash == b.hash.
    • To make those classes derivable, Multiformats.Multihash now derives Hashable and Ord, and the generated multiformats enums (HashCode, ContentCodec, Protocol, Multibase.Base) derive Ord.
    • The peer shape rule stays Multiformats.Multiaddr.validPeerHash; PeerId carries its proof.
  8. IvanAnishchuk commented on Nov 6, 2026

    @IvanAnishchuk
    Contributor

    Interface change from W5.2: StreamHandler.handle now takes a StreamContext (the proved remotePeer and the connection's remoteAddr) before the stream. The reason and the full shape are on #15.

    A handler value or a core mock in this unit's PR needs the new argument. A handler that needs neither field writes fun _ s => ….

  9. leolara commented on Nov 9, 2026

    @leolara
    ContributorAuthor

    The gate closed with PR #59. The review verified the recorded Go+Lean and Rust+Lean cells on a binary built from the head the body names, with the full SHA verifiable on the fork, seed 1, reach 1.0, and the branch resolved onto the reviewed seam versions of the tip. The wire suite and the scoring and trickle regressions run in Tests.Gossipsub, and the merged tip passes the four gates.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions