Skip to main content
netspecsEthereum networking

2.2.libp2p stack

Stage
Current
Validity
In force since Phase 0.
Sources
1 pinned source

Consensus clients use libp2p for authenticated connections, gossip, and request streams. discv5 finds candidates, but it does not carry consensus messages. The libp2p stack is fork-independent; fork-specific types are selected by the gossip digest or the Req/Resp context.

Transport and identity

Every implementation MUST support libp2p QUIC over UDP and TCP for both dialling and listening. Both transports MUST work with IPv4 and IPv6 addresses. QUIC is the preferred address when both transports are available. A client MUST listen on at least one address family and MUST be able to dial both. Every listening endpoint MUST be publicly diallable. Relay, AutoNAT, and AutoRelay are not substitutes for those endpoints.

QUIC uses TLS 1.3 through the libp2p TLS profile. TCP uses the libp2p Noise secure channel with secp256k1 identities and MUST support the XX handshake. The authenticated libp2p Peer ID is the identity used by all later streams.

Negotiation and multiplexing

Peers use multistream-select 1.0 and exact protocol-ID equality. A client MAY prefer a higher version when both sides offer it, but it MUST NOT treat a prefix match as a negotiated protocol. QUIC multiplexes streams itself. A TCP client MUST support /mplex/6.7.0; it MAY also support /yamux/1.0.0, and yamux takes precedence when both are offered.

One connection carries independent gossip and Req/Resp streams. A stream failure does not corrupt other streams. A client closes the connection when the secure-channel or protocol negotiation fails, and resets only the faulty stream for a local framing or payload error.

SSZ and Snappy

Consensus objects use SSZ. Gossip topics and Req/Resp IDs end in ssz_snappy. Gossip uses Snappy block compression. Req/Resp uses Snappy framing over an SSZ byte-length prefix. A one-field request is encoded as that field, not as a one-field SSZ container.

The profile sets MAX_PAYLOAD_SIZE to 10 MiB for an uncompressed gossip payload or Req/Resp chunk. For an SSZ length n, the worst-case compressed bound is 32 + n + n / 6; the complete gossipsub RPC frame adds 1,024 bytes and has a minimum bound of 1 MiB. Readers MUST validate the declared SSZ length and reject early EOF, trailing bytes, or compressed input above that bound before allocating the object.

Shared limits

MAX_CONCURRENT_REQUESTS is 2 per protocol ID, and MAXIMUM_GOSSIP_CLOCK_DISPARITY is 500 milliseconds. The profile also defines 64 attestation subnets, two persistent subnets per node, and a 256-epoch persistent-subnet subscription. Block and sidecar request pages define their fork-specific bounds.

Failure outcomes

Malformed SSZ, invalid Snappy, a length assertion that exceeds the global or type bound, and an unknown protocol ID are protocol failures. In Req/Resp they produce an InvalidRequest or bad-response result as appropriate. A peer may be downscored for violating framing or size rules. Application validators then return ACCEPT, IGNORE, or REJECT; only ACCEPT enters forwarding.

Scope and status

This page defines the common libp2p transport, security, negotiation, and encoding envelope. Fork-scoped message types, contexts, and metadata fields are defined on their topic pages.