EIP-8 devp2p Forward Compatibility Requirements (devp2p Forward Compatibility Requirements for Homestead)

Final · Networking & nodes · EIP status Final · created 2015-12-18

Adds forward-compatibility rules to devp2p, the network protocol Ethereum nodes use to connect to each other, so that connections are not dropped when a peer's version differs and unknown data is simply ignored.

Why it is needed

Ethereum nodes connect to one another using a network protocol called devp2p. Existing clients would refuse a connection if the version number or structure of a peer's hello packet differed from what they expected. This made it essentially impossible to add new versions or new fields to the protocol, since nodes running older versions would reject every new packet outright. To coincide with the Homestead consensus upgrade, this EIP applies Postel's Law, "be conservative in what you send, be liberal in what you accept," across the protocol as a whole. This ensures that, as long as backward compatibility is maintained, every client in use on the network can withstand future network protocol upgrades.

What changes

Today

After EIP-8

Who is affected

In depth

devp2p Wire Protocol: Removing the hello Version Check

Implementations must ignore the version number in the hello packet, and when sending, put the highest devp2p version they support into the version field. They must also ignore any extra list elements at the end of the hello packet. Existing clients, as in the pydevp2p example, had a check that dropped the connection with reason incompatible_p2p_version when versions differed; removing this check lets newer clients simply send packets with a higher version and extra elements. A lower-version node assumes the peer is backward compatible and responds with the old handshake, a same-version node uses the new features, and a higher-version node can either enable backward-compatibility logic or drop the connection.

RLPx Discovery Protocol: Relaxing Decoding Rules

The version number in ping packets is no longer validated, extra list elements in all packets are ignored, and data following the first RLP value is also ignored. Discovery packets of an unknown packet type are silently dropped. The maximum discovery packet size remains 1280 bytes. This relaxation mostly codifies what was already common practice at the time; with the exception of go-ethereum, most implementations already did not count list elements strictly or reject nodes with mismatched versions. It simply changes this behavior from unguaranteed to guaranteed by the specification.

New Encoding for the RLPx TCP Handshake

auth-vsn = 4, and auth-size is the size of enc-auth-body encoded as a big-endian 16-bit integer. auth-body = rlp.list(sig, initiator-pubk, initiator-nonce, auth-vsn), enc-auth-body = ecies.encrypt(recipient-pubk, auth-body, auth-size), and auth-packet = auth-size || enc-auth-body. The ack side follows the same structure, with ack-vsn = 4 and ack-body = rlp.list(recipient-ephemeral-pubk, recipient-nonce, ack-vsn). Here, auth-size and ack-size are AUTHDATA: they are not included in the ciphertext, but they do go into generating the HMAC-256 message tag. When decoding the RLP of auth-body and ack-body, mismatches between auth-vsn and ack-vsn, extra list elements, and trailing data after the list are all ignored.

Transition-Period Padding and Distinguishing Old from New Format

During the transition period before the old format retires, implementations must pad auth-body with at least 100 bytes of meaningless (junk) data. To vary packet sizes, it is recommended to add a random amount in the range [100, 300]. Extra data after the RLP list is allowed, and in fact necessary, because the new-format handshake packet needs to be larger in order to be distinguished from the old format. The receiving side can handle both formats at once using pseudocode that first reads 307 bytes and attempts old-format decryption, and if that fails, interprets the first 2 bytes as a size, reads the remaining bytes, and decrypts using the new format.

Fields Added and Removed in the Handshake

There are four changes. Add the length of the ciphertext as a plaintext header, encode the handshake body in RLP, place a version number where the unused token flag used to be, and remove the hash of the ephemeral public key since it is redundant. The background for these changes was the RLPx v5 discussion (chunked packets, changes to key derivation). The v4 handshake encoding had no in-band way to add a version number other than shrinking the random portion of the nonce, and because the ECIES ciphertext has a fixed size with known layout, future upgrades were difficult. Since this is the first change to the handshake packet, all unused fields were cleaned up at the same time.

The plaintext size header debate

The most contentious part of this document is the plaintext size header. There was a counterargument that it helps attackers filter and identify RLPx connections at the network level. The source treats this as a matter of attacker effort. If the recommended length randomization is followed, pure pattern based packet recognition becomes difficult to pull off successfully. For a typical firewall operator, blocking every connection whose first two bytes form an integer in the range [300, 600] is overly invasive, and port based blocking is more effective anyway. An attacker capable of correlating multiple signals does get one more identifying signal from the size header, but such an attacker can already read or participate in RLPx discovery traffic and block RLPx TCP connections regardless of the framing.

Backwards compatibility, implementation, test vectors

This EIP is backwards compatible. Every valid version 4 packet continues to be accepted. Implementations exist in go-ethereum, libweb3core, and pydevp2p. The test vectors include a devp2p hello packet with version 22 and an extra list element, discovery packets with ping messages at version 4 and version 555 (including pong, findnode, and neighbours), RLPx handshake packets in both the old format (Auth1, Ack1) and the EIP-8 format (version 4 Auth2 and Ack2, and version 56 Auth3 and version 57 Ack3 each carrying three extra elements), and the aes-secret and mac-secret values derived from Auth2 and Ack2. Since the status is Final, the specification is settled.

Original EIP · ← EIPs