Skip to main content
netspecsEthereum networking

3.1.3.discv5

Stage
Current
Validity
Active non-fork protocol.
Sources
5 pinned sources

discv5.1 is an encrypted UDP protocol for finding nodes and application services. It uses signed Ethereum node records as both address and identity objects. Execution and consensus clients can share the wire protocol while applying different ENR fields and service rules.

This page owns the common wire protocol. Execution discovery and consensus discovery own fork, capability, and peer-selection checks. Portal overlays use the same discv5 transport for their application messages.

Node IDs and distance

An ENR identity scheme derives a 32-byte node ID. The distance between IDs is the XOR of the two big-endian values. logdistance is the base-2 logarithm of that value. A node record must have an IP address and UDP port before it can be relayed in the routing table.

UDP limits and request timing

discv5 sends one protocol packet per UDP datagram. A packet is at least 63 bytes and at most 1280 bytes. Implementations must reject packets outside this range and must not generate a packet larger than 1280 bytes. NODES splits a result when 16 ENRs and their headers do not fit in one packet.

The wire specification gives 500 ms as a good request/response timeout and 1 s as a good handshake timeout. UDP loss or reordering is normal. An implementation should not resend a packet only because its peer did not reply. Responses go to the UDP envelope address of the request.

Packet envelope

Every packet has a masked header and, for ordinary and handshake packets, an encrypted message:

packet        = masking-iv || masked-header || message
masked-header = aesctr_encrypt(masking-key, masking-iv, header)
masking-key   = dest-id[:16]
masking-iv    = uint128, random and unique for the packet
header        = static-header || authdata
static-header = "discv5" || 0x0001 || flag || nonce || authdata-size
nonce         = uint96, unique for every message packet

The flag identifies the packet form. authdata-size is a uint16 byte count. The unmasked header and masking IV are additional authenticated data:

message    = aesgcm_encrypt(initiator-key, nonce, message-pt, message-ad)
message-pt = message-type || message-data
message-ad = masking-iv || header
Flag Form Authdata
0 Ordinary message src-id (32 bytes).
1 WHOAREYOU challenge id-nonce (16 bytes) followed by the requester's ENR sequence (8 bytes).
2 Handshake message `src-id

WHOAREYOU has no encrypted message. Its nonce copies the nonce of the ordinary packet that caused the challenge. The v4 identity scheme uses a 64-byte identity signature and a 33-byte compressed ephemeral public key.

Message inventory

Every message-data value is an RLP list. Its first element is a request ID of at most 8 bytes. A response mirrors that ID.

Core messages

Type Payload Behavior
PING (0x01) [request-id, enr-seq] Checks liveness and sends the sender's ENR sequence.
PONG (0x02) [request-id, enr-seq, recipient-ip, recipient-port] Replies to PING and reports the observed UDP endpoint.
FINDNODE (0x03) [request-id, [distance1, distance2, ...]] Requests records at logarithmic distances. Distance 0 requests the recipient's current ENR.
NODES (0x04) [request-id, total, [ENR, ...]] Returns records. Multiple packets can carry one response.
TALKREQ (0x05) [request-id, protocol, request] Sends opaque bytes to an application protocol.
TALKRESP (0x06) [request-id, response] Returns opaque bytes. An unknown protocol gets an empty response.

The receiver limits a FINDNODE result. The wire document recommends at most 16 ENRs. It sends the complete result over one or more NODES messages and sets total to the number of response packets. A requester checks that returned ENRs match the distances it asked for and ignores packets after its local limit for total.

TALKREQ always receives TALKRESP, even when the protocol is unknown. Portal overlays use these messages with an application protocol identifier.

Topic-discovery messages

The pinned wire specification also defines TopDisc messages:

Type Payload or purpose
REGTOPIC (0x07) Registers an ENR for a 32-byte topic with a ticket and topic-distance hints.
REGCONFIRMATION (0x08) Returns admission, a retry ticket, and a wait time.
TOPICQUERY (0x09) Requests advertisements for a topic.
TOPICNODES (0x0a) Returns registered advertiser ENRs.

NODES packets that accompany a topic response carry auxiliary routing ENRs; they are not topic advertisements. The registrar must not return expired advertisements. A requester validates every returned ENR before it updates its service table.

Session establishment

When a node has no usable session key, it sends an ordinary packet with random message content. The recipient replies with WHOAREYOU, stores the challenge and the sender's record for a short time, and includes the sender's ENR sequence or zero when it has no record.

The sender must answer the challenge by resending the triggering message in a handshake packet. For the v4 identity scheme, it performs these steps:

challenge-data = masking-iv || static-header || authdata
secret         = ecdh(recipient-static-public-key, ephemeral-private-key)
prk            = HKDF-Extract(challenge-data, secret)
key-data       = HKDF-Expand(
                   prk,
                   "discovery v5 key agreement" || node-id-A || node-id-B,
                   32)
initiator-key  = key-data[:16]
recipient-key  = key-data[16:]

The sender signs:

"discovery v5 identity proof" || challenge-data || eph-pubkey || node-id-B

The receiver validates the supplied ENR, checks the identity signature with the ENR key, derives the same keys with its static private key, and authenticates the encrypted message. If the challenge's ENR sequence is lower than the sender's current sequence, the sender includes its newer ENR in the handshake.

WHOAREYOU is valid only as a response to a pending request. If several requests are pending, the packet named by the challenge nonce is retried first; other requests can be retried after the new session is established. A node that receives another undecryptable ordinary packet while it waits for the handshake can issue a new challenge for that packet.

Session cache and endpoint binding

Implementations can keep a bounded in-memory LRU cache of session keys. The cache key includes the peer node ID and its IP and port. This binds a session to the endpoint that completed the challenge and prevents an address-spoofed packet from using a key learned at another endpoint.

When a peer changes endpoint, the old session is not reused. The recipient rejects the undecryptable packet and starts a new WHOAREYOU exchange. Each AES-GCM packet uses a unique 96-bit nonce; an implementation must track its outgoing nonce state for each session.

Routing table and lookup

The routing table has one k-bucket for each logarithmic distance from 0 through 255. Each bucket holds at most 16 entries ordered by last contact. A full bucket can retain replacement entries. Before a node returns an ENR in a FINDNODE response, it must have checked that the endpoint in that ENR is live.

A lookup starts with the closest known nodes and sends FINDNODE to a small concurrent set. The theory document uses 3 as a typical concurrency value. The lookup adds valid records, selects closer unqueried nodes, and ends after responses from the 16 closest nodes it has seen. Implementations can use multiple disjoint lookup paths to reduce dependence on one adversarial route.

Validation and failure handling

  • Reject a packet smaller than 63 bytes or larger than 1280 bytes.
  • Reject or ignore a packet whose unmasked protocol ID is not discv5; do not answer it.
  • Require a unique message nonce and authenticate the GCM tag before processing the message type.
  • Match every response to a pending request ID.
  • Ignore an unsolicited WHOAREYOU or a response with no pending request.
  • Check FINDNODE distances and validate every returned ENR before insertion.
  • Do not treat auxiliary ENRs in NODES as topic advertisements.
  • Return TALKRESP for every TALKREQ; return empty response bytes for an unsupported application protocol.

The handshake proves control of the identity key named by the sender's ENR and binds the proof to one challenge. The packet format encrypts discovery messages after session setup. The key schedule in the pinned specification uses an ephemeral initiator key and a static recipient key; it does not state a separate forward-secrecy guarantee.