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
WHOAREYOUor a response with no pending request. - Check
FINDNODEdistances and validate every returned ENR before insertion. - Do not treat auxiliary ENRs in
NODESas topic advertisements. - Return
TALKRESPfor everyTALKREQ; 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.