Portal is a family of content-addressed overlays carried through discv5
TALKREQ and TALKRESP. Portal wire version 2 is the current version in the
pinned specification.
Identity and negotiation
Portal uses the discv5 ENR and node ID. ENR key p contains the RLP list
[minimum_version, maximum_version, chain_id]. Peers use the highest shared
version and should not communicate across chain IDs.
Each overlay has a two-byte TALK protocol ID. The first byte is 0x50. The
History Network uses 0x5000. Other assigned IDs in the pinned document are
legacy or reserved.
Wire inventory
All Portal messages form one SSZ union. A request is the SSZ serialization of
one union member in the TALKREQ.request field. Its response uses the matching
union member in TALKRESP.response.
Ping checks reachability and exchanges an extension payload. Its container is
(enr_seq: uint64, payload_type: uint16, payload: ByteList[1100]).
Pong returns the peer's ENR sequence and extension payload, with the same
container and limits as Ping.
FindNodes carries a sorted, unique list of at most 256 uint16 distances.
Every distance is in the inclusive range 0..256; distance zero requests the
recipient's own ENR.
Nodes carries total: uint8 and up to 32 RLP-encoded ENRs, each at most 2,048
bytes. The records must match requested distances and have unique node IDs.
The current protocol sends one response (total = 1) and should omit the
requester's own record.
FindContent carries one encoded content key, at most 2,048 bytes.
Content returns one of three SSZ union values: a two-byte uTP connection ID,
inline content up to 2,048 bytes, or up to 32 closer ENRs. Inline content is
used when it fits the response. If the node has neither content nor eligible
closer records, it returns an empty ENR list. A connection-ID response asks the
sender to listen and the receiver to open the uTP stream.
Offer announces up to 64 encoded content keys, each at most 2,048 bytes.
Accept carries a two-byte uTP connection ID and one status byte for each
offered key. Status 0 accepts; 1 is a generic decline; 2 means content is
already stored; 3 means it is outside the node's radius; 4 means the node
is rate-limited; 5 means the content is protected from an inbound herd; and
6 means the key is not verifiable. Values 7..255 are unspecified declines.
An accepted offer sends up to 64 content items over uTP, each prefixed by an
unsigned LEB128 length no greater than uint32.
Routing and lookup
Each overlay derives a 256-bit content ID from its content key and defines a
distance function. The common XOR distance is a XOR b; the common SHA-256
derivation is sha256(encoded_content_key). Nodes keep a Kademlia-style table
for each overlay. A content lookup asks the closest known nodes and repeats
with closer records until it finds valid content or no closer record remains.
Nodes store content within the overlay's announced radius. A node is interested in content when its node-ID distance to the content ID is at most that radius. Neighborhood gossip offers content to nearby nodes; a node may decline an offer and the wire protocol does not guarantee storage.
Failure handling
An unsupported message should receive an empty TALKRESP. A receiver rejects
malformed SSZ, duplicate node IDs, records at an unrequested distance, invalid
ENRs, or content that fails the sub-protocol's checks. Inline content remains
limited by the discv5 packet size. Larger content uses the uTP transport.
Design rationale
Portal reuses authenticated discovery sessions and adds overlay-specific content addressing. Small control messages stay in one UDP exchange.