|
| 1 | +ETH 2.0 Networking Spec - RPC Interface |
| 2 | +=== |
| 3 | + |
| 4 | +# Abstract |
| 5 | + |
| 6 | +The Ethereum 2.0 networking stack uses two modes of communication: a broadcast protocol that gossips information to interested parties via GossipSub, and an RPC protocol that retrieves information from specific clients. This specification defines the RPC protocol. |
| 7 | + |
| 8 | +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL", NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119. |
| 9 | + |
| 10 | +# Dependencies |
| 11 | + |
| 12 | +This specification assumes familiarity with the [Messaging](./messaging.md), [Node Identification](./node-identification), and [Beacon Chain](../core/0_beacon-chain.md) specifications. |
| 13 | + |
| 14 | +# Specification |
| 15 | + |
| 16 | +## Message Schemas |
| 17 | + |
| 18 | +Message body schemas are notated like this: |
| 19 | + |
| 20 | +``` |
| 21 | +( |
| 22 | + field_name_1: type |
| 23 | + field_name_2: type |
| 24 | +) |
| 25 | +``` |
| 26 | + |
| 27 | +Embedded types are serialized as SSZ Containers unless otherwise noted. |
| 28 | + |
| 29 | +All referenced data structures can be found in the [0-beacon-chain](https://github.com/ethereum/eth2.0-specs/blob/dev/specs/core/0_beacon-chain.md#data-structures) specification. |
| 30 | + |
| 31 | +## `libp2p` Protocol Names |
| 32 | + |
| 33 | +A "Protocol ID" in `libp2p` parlance refers to a human-readable identifier `libp2p` uses in order to identify sub-protocols and stream messages of different types over the same connection. Peers exchange supported protocol IDs via the `Identify` protocol upon connection. When opening a new stream, peers pin a particular protocol ID to it, and the stream remains contextualised thereafter. Since messages are sent inside a stream, they do not need to bear the protocol ID. |
| 34 | + |
| 35 | +## RPC-Over-`libp2p` |
| 36 | + |
| 37 | +To facilitate RPC-over-`libp2p`, a single protocol name is used: `/eth/serenity/beacon/rpc/1`. The version number in the protocol name is neither backwards or forwards compatible, and will be incremented whenever changes to the below structures are required. |
| 38 | + |
| 39 | +Remote method calls are wrapped in a "request" structure: |
| 40 | + |
| 41 | +``` |
| 42 | +( |
| 43 | + id: uint64 |
| 44 | + method_id: uint16 |
| 45 | + body: Request |
| 46 | +) |
| 47 | +``` |
| 48 | + |
| 49 | +and their corresponding responses are wrapped in a "response" structure: |
| 50 | + |
| 51 | +``` |
| 52 | +( |
| 53 | + id: uint64 |
| 54 | + response_code: uint16 |
| 55 | + result: bytes |
| 56 | +) |
| 57 | +``` |
| 58 | + |
| 59 | +If an error occurs, a variant of the response structure is returned: |
| 60 | + |
| 61 | +``` |
| 62 | +( |
| 63 | + id: uint64 |
| 64 | + response_code: uint16 |
| 65 | + result: bytes |
| 66 | +) |
| 67 | +``` |
| 68 | + |
| 69 | +The details of the RPC-Over-`libp2p` protocol are similar to [JSON-RPC 2.0](https://www.jsonrpc.org/specification). Specifically: |
| 70 | + |
| 71 | +1. The `id` member is REQUIRED. |
| 72 | +2. The `id` member in the response MUST be the same as the value of the `id` in the request. |
| 73 | +3. The `id` member MUST be unique within the context of a single connection. Monotonically increasing `id`s are RECOMMENDED. |
| 74 | +4. The `method_id` member is REQUIRED. |
| 75 | +5. The `result` member is REQUIRED on success. |
| 76 | +6. The `result` member is OPTIONAL on errors, and MAY contain additional information about the error. |
| 77 | +7. `response_code` MUST be `0` on success. |
| 78 | + |
| 79 | +Structuring RPC requests in this manner allows multiple calls and responses to be multiplexed over the same stream without switching. Note that this implies that responses MAY arrive in a different order than requests. |
| 80 | + |
| 81 | +The "method ID" fields in the below messages refer to the `method` field in the request structure above. |
| 82 | + |
| 83 | +The first 1,000 values in `response_code` are reserved for system use. The following response codes are predefined: |
| 84 | + |
| 85 | +1. `0`: No error. |
| 86 | +2. `10`: Parse error. |
| 87 | +2. `20`: Invalid request. |
| 88 | +3. `30`: Method not found. |
| 89 | +4. `40`: Server error. |
| 90 | + |
| 91 | +### Alternative for Non-`libp2p` Clients |
| 92 | + |
| 93 | +Since some clients are waiting for `libp2p` implementations in their respective languages. As such, they MAY listen for raw TCP messages on port `9000`. To distinguish RPC messages from other messages on that port, a byte prefix of `ETH` (`0x455448`) MUST be prepended to all messages. This option will be removed once `libp2p` is ready in all supported languages. |
| 94 | + |
| 95 | +## Messages |
| 96 | + |
| 97 | +### Hello |
| 98 | + |
| 99 | +**Method ID:** `0` |
| 100 | + |
| 101 | +**Body**: |
| 102 | + |
| 103 | +``` |
| 104 | +( |
| 105 | + network_id: uint8 |
| 106 | + chain_id: uint64 |
| 107 | + latest_finalized_root: bytes32 |
| 108 | + latest_finalized_epoch: uint64 |
| 109 | + best_root: bytes32 |
| 110 | + best_slot: uint64 |
| 111 | +) |
| 112 | +``` |
| 113 | + |
| 114 | +Clients exchange `hello` messages upon connection, forming a two-phase handshake. The first message the initiating client sends MUST be the `hello` message. In response, the receiving client MUST respond with its own `hello` message. |
| 115 | + |
| 116 | +Clients SHOULD immediately disconnect from one another following the handshake above under the following conditions: |
| 117 | + |
| 118 | +1. If `network_id` belongs to a different chain, since the client definitionally cannot sync with this client. |
| 119 | +2. If the `latest_finalized_root` shared by the peer is not in the client's chain at the expected epoch. For example, if Peer 1 in the diagram below has `(root, epoch)` of `(A, 5)` and Peer 2 has `(B, 3)`, Peer 1 would disconnect because it knows that `B` is not the root in their chain at epoch 3: |
| 120 | + |
| 121 | +``` |
| 122 | + Root A |
| 123 | +
|
| 124 | + +---+ |
| 125 | + |xxx| +----+ Epoch 5 |
| 126 | + +-+-+ |
| 127 | + ^ |
| 128 | + | |
| 129 | + +-+-+ |
| 130 | + | | +----+ Epoch 4 |
| 131 | + +-+-+ |
| 132 | +Root B ^ |
| 133 | + | |
| 134 | ++---+ +-+-+ |
| 135 | +|xxx+<---+--->+ | +----+ Epoch 3 |
| 136 | ++---+ | +---+ |
| 137 | + | |
| 138 | + +-+-+ |
| 139 | + | | +-----------+ Epoch 2 |
| 140 | + +-+-+ |
| 141 | + ^ |
| 142 | + | |
| 143 | + +-+-+ |
| 144 | + | | +-----------+ Epoch 1 |
| 145 | + +---+ |
| 146 | +``` |
| 147 | + |
| 148 | +Once the handshake completes, the client with the higher `latest_finalized_epoch` or `best_slot` (if the clients have equal `latest_finalized_epoch`s) SHOULD request beacon block roots from its counterparty via `beacon_block_roots` (i.e., RPC method `10`). |
| 149 | + |
| 150 | +### Goodbye |
| 151 | + |
| 152 | +**Method ID:** `1` |
| 153 | + |
| 154 | +**Body:** |
| 155 | + |
| 156 | +``` |
| 157 | +( |
| 158 | + reason: uint64 |
| 159 | +) |
| 160 | +``` |
| 161 | + |
| 162 | +Client MAY send `goodbye` messages upon disconnection. The reason field MAY be one of the following values: |
| 163 | + |
| 164 | +- `1`: Client shut down. |
| 165 | +- `2`: Irrelevant network. |
| 166 | +- `3`: Fault/error. |
| 167 | + |
| 168 | +Clients MAY define custom goodbye reasons as long as the value is larger than `1000`. |
| 169 | + |
| 170 | +### Get Status |
| 171 | + |
| 172 | +**Method ID:** `2` |
| 173 | + |
| 174 | +**Request Body:** |
| 175 | + |
| 176 | +``` |
| 177 | +( |
| 178 | + sha: bytes32 |
| 179 | + user_agent: bytes |
| 180 | + timestamp: uint64 |
| 181 | +) |
| 182 | +``` |
| 183 | + |
| 184 | +**Response Body:** |
| 185 | + |
| 186 | +``` |
| 187 | +( |
| 188 | + sha: bytes32 |
| 189 | + user_agent: bytes |
| 190 | + timestamp: uint64 |
| 191 | +) |
| 192 | +``` |
| 193 | + |
| 194 | +Returns metadata about the remote node. |
| 195 | + |
| 196 | +### Request Beacon Block Roots |
| 197 | + |
| 198 | +**Method ID:** `10` |
| 199 | + |
| 200 | +**Request Body** |
| 201 | + |
| 202 | +``` |
| 203 | +( |
| 204 | + start_slot: uint64 |
| 205 | + count: uint64 |
| 206 | +) |
| 207 | +``` |
| 208 | + |
| 209 | +**Response Body:** |
| 210 | + |
| 211 | +``` |
| 212 | +# BlockRootSlot |
| 213 | +( |
| 214 | + block_root: bytes32 |
| 215 | + slot: uint64 |
| 216 | +) |
| 217 | +
|
| 218 | +( |
| 219 | + roots: []BlockRootSlot |
| 220 | +) |
| 221 | +``` |
| 222 | + |
| 223 | +Requests a list of block roots and slots from the peer. The `count` parameter MUST be less than or equal to `32768`. The slots MUST be returned in ascending slot order. |
| 224 | + |
| 225 | +### Beacon Block Headers |
| 226 | + |
| 227 | +**Method ID:** `11` |
| 228 | + |
| 229 | +**Request Body** |
| 230 | + |
| 231 | +``` |
| 232 | +( |
| 233 | + start_root: HashTreeRoot |
| 234 | + start_slot: uint64 |
| 235 | + max_headers: uint64 |
| 236 | + skip_slots: uint64 |
| 237 | +) |
| 238 | +``` |
| 239 | + |
| 240 | +**Response Body:** |
| 241 | + |
| 242 | +``` |
| 243 | +( |
| 244 | + headers: []BeaconBlockHeader |
| 245 | +) |
| 246 | +``` |
| 247 | + |
| 248 | +Requests beacon block headers from the peer starting from `(start_root, start_slot)`. The response MUST contain no more than `max_headers` headers. `skip_slots` defines the maximum number of slots to skip between blocks. For example, requesting blocks starting at slots `2` a `skip_slots` value of `1` would return the blocks at `[2, 4, 6, 8, 10]`. In cases where a slot is empty for a given slot number, the closest previous block MUST be returned. For example, if slot `4` were empty in the previous example, the returned array would contain `[2, 3, 6, 8, 10]`. If slot three were further empty, the array would contain `[2, 6, 8, 10]` - i.e., duplicate blocks MUST be collapsed. A `skip_slots` value of `0` returns all blocks. |
| 249 | + |
| 250 | +The function of the `skip_slots` parameter helps facilitate light client sync - for example, in [#459](https://github.com/ethereum/eth2.0-specs/issues/459) - and allows clients to balance the peers from whom they request headers. Clients could, for instance, request every 10th block from a set of peers where each per has a different starting block in order to populate block data. |
| 251 | + |
| 252 | +### Beacon Block Bodies |
| 253 | + |
| 254 | +**Method ID:** `12` |
| 255 | + |
| 256 | +**Request Body:** |
| 257 | + |
| 258 | +``` |
| 259 | +( |
| 260 | + block_roots: []HashTreeRoot |
| 261 | +) |
| 262 | +``` |
| 263 | + |
| 264 | +**Response Body:** |
| 265 | + |
| 266 | +``` |
| 267 | +( |
| 268 | + block_bodies: []BeaconBlockBody |
| 269 | +) |
| 270 | +``` |
| 271 | + |
| 272 | +Requests the `block_bodies` associated with the provided `block_roots` from the peer. Responses MUST return `block_roots` in the order provided in the request. If the receiver does not have a particular `block_root`, it must return a zero-value `block_body` (i.e., a `block_body` container with all zero fields). |
| 273 | + |
| 274 | +### Beacon Chain State |
| 275 | + |
| 276 | +**Note:** This section is preliminary, pending the definition of the data structures to be transferred over the wire during fast sync operations. |
| 277 | + |
| 278 | +**Method ID:** `13` |
| 279 | + |
| 280 | +**Request Body:** |
| 281 | + |
| 282 | +``` |
| 283 | +( |
| 284 | + hashes: []HashTreeRoot |
| 285 | +) |
| 286 | +``` |
| 287 | + |
| 288 | +**Response Body:** TBD |
| 289 | + |
| 290 | +Requests contain the hashes of Merkle tree nodes that when merkelized yield the block's `state_root`. |
| 291 | + |
| 292 | +The response will contain the values that, when hashed, yield the hashes inside the request body. |
0 commit comments