eth is the protocol execution clients use to exchange blocks, receipts and
transactions. It runs as a capability on top of an RLPx
connection. RLPx has already authenticated the peer and agreed that both sides
speak eth, but not whether they follow the same chain. The eth session
starts by settling that:
- RLPx connects, and the
Helloexchange picks the highestethversion both sides support. - Each side sends
Status, stating its network, genesis block, fork state and the block range it can serve. - Each side checks the other’s
Status. If anything is incompatible, it disconnects. - Otherwise the session is open. Either side may send any
ethmessage, and sendsBlockRangeUpdatefrom time to time as its range moves.
This page covers those steps and the rules that apply to every message in the session. The messages themselves are covered on Chain data and Transactions.
Session activation and limits
No other eth message may come before Status. Once both sides have sent
theirs, the session carries two independent kinds of traffic at once: chain
synchronization (headers, bodies, receipts) and transaction exchange. Neither
should starve the other. That is why each response has a recommended soft size
limit, well below the hard limit at which a peer is dropped.
Once a connection is established, a Status message must be sent. Following the reception of the peer’s Status message, the Ethereum session is active and any other message may be sent.
Within a session, two high-level tasks can be performed: chain synchronization and transaction exchange. These tasks use disjoint sets of protocol messages and clients typically perform them as concurrent activities on all peer connections.
Client implementations should enforce limits on protocol message sizes. The underlying RLPx transport limits the size of a single message to 16.7 MiB. The practical limits for the eth protocol are lower, typically 10 MiB. If a received message is larger than the limit, the peer should be disconnected.
In addition to the hard limit on received messages, clients should also impose ‘soft’ limits on the requests and responses which they send. The recommended soft limit varies per message type. Limiting requests and responses ensures that concurrent activity, e.g. block synchronization and transaction exchange work smoothly over the same peer connection.
Request identifiers
Requests and responses are matched by a request-id. The requester picks it
and the responder copies it, so several requests of the same type can be in
flight on one connection and their answers can come back in any order.
Status handshake
Status tells the other side which chain the node is on and how much of it the
node can serve. The receiver checks it field by field:
| Field | Receiver’s check |
|---|---|
vsn | Equals the version RLPx negotiated |
networkid | Equals ours; mainnet is 1 |
genesis | Equals our genesis block hash |
forkid | Compatible with ours, per the fork ID rules below |
earliest, latest, latestHash | Tell us which blocks we can ask this peer for; they are not a reason to disconnect |
Network ID and genesis hash only rule out peers on an entirely different network. The fork ID (EIP-2124) also catches peers on the same network that disagree about upgrades. It has two parts:
fork-hash: a CRC32 over the genesis hash and every fork block number or timestamp already passed.fork-next: the next fork this node expects, or0if none is scheduled.
The two fork IDs are not simply compared for equality. A peer that is still
syncing, and so is behind on forks, is accepted as long as its past forks are a
prefix of ours and its fork-next is the fork we passed next. A peer that has
passed a fork we don’t know about, or that expects a fork at a point we have
already passed without it, is rejected. The full rules and test vectors are on
Execution discovery. Discovery runs the same
check on the eth entry of a node’s record, so most incompatible peers are
filtered out before any connection is made.
[vsn: P, networkid: P, genesis: B_32, forkid, earliest: P, latest: P, latestHash: B_32]
This is the initial message, informing the peer about the local node state and configuration. This message should be sent just after the connection is established and prior to any other eth protocol messages.
vsn: the current protocol versionnetworkid: integer identifying the blockchain, see table belowgenesis: the hash of the genesis blockforkid: An EIP-2124 fork identifier, encoded as[fork-hash, fork-next].
The Status message also announces the available block range. See BlockRangeUpdate for more information.
earliest: number of the earliest available full blocklatest: number of the latest available full block numberlatestHash: hash of the latest available full block
This table lists common Network IDs and their corresponding networks. Other IDs exist which aren’t listed, i.e. clients should not require that any particular network ID is used. Note that the Network ID may or may not correspond with the EIP-155 Chain ID used for transaction replay prevention.
| ID | chain |
|---|---|
| 0 | Olympic (disused) |
| 1 | Frontier (now mainnet) |
| 2 | Morden testnet (disused) |
| 3 | Ropsten testnet (disused) |
| 4 | Rinkeby testnet (disused) |
| 5 | Goerli testnet |
For a community curated list of chain IDs, see https://chainid.network.
History range updates
Since eth/69, nodes no longer have to keep the whole chain. A node that has
pruned old history keeps headers from genesis, but only serves bodies and
receipts from earliest up to latest. It announces that range in Status
and updates it with BlockRangeUpdate, about every two minutes.
A peer uses the range to route requests: don’t ask for bodies or receipts
outside a peer’s range. It is also a health signal: if every peer’s latest
lags far behind our head, we are surrounded by syncing nodes. That still isn’t
a reason to drop them all, because a syncing node is a normal peer.
A block b is available when earliest <= b <= latest. The upstream text below
writes the inequality the other way round. The next rule makes the intended
reading clear: a peer that sends earliest > latest is dropped.
[earliest: P, latest: P, latestHash: B_32]
This is a notification about a change in the available block range on a peer.
With this message, the peer announces that all blocks b with earliest >= b >= latest
are available via GetBlockBodies, and also that receipts for these blocks are available
via GetReceipts. Headers are always assumed to be available for the full range of blocks
from genesis.
The notification doesn’t need to be sent for every update to the node’s head block. It is recommended to send an update about once every two minutes. Clients should validate received updates.
- If
earliest > latest, the peer should be disconnected. - Updates can be used to detect the condition where a node is surrounded by syncing peers. At the same time, client implementations must take care to not disconnect all syncing peers purely on the basis of their BlockRangeUpdate.
Versions
The current version is eth/72. Each version since eth/69 changed what a session can carry:
| Version | Change |
|---|---|
| eth/69 | Status carries the block range; BlockRangeUpdate added; bloom filters dropped from receipts |
| eth/70 | GetReceipts can ask for part of a block’s receipts, so a block’s receipts can be larger than one message |
| eth/71 | Block access lists for Amsterdam: GetBlockAccessLists and BlockAccessLists |
| eth/72 | Blob transaction announcements carry cell custody; GetCells and Cells added |