reth_rpc_api/engine.rs
1//! Server traits for the engine API
2//!
3//! This contains the `engine_` namespace and the subset of the `eth_` namespace that is exposed to
4//! the consensus client.
5
6use alloy_eips::{
7 eip4844::{BlobAndProofV1, BlobAndProofV2, BlobCellsAndProofsV1},
8 eip7685::RequestsOrHash,
9 eip7928::BlockAccessList,
10 BlockId, BlockNumberOrTag,
11};
12use alloy_json_rpc::RpcObject;
13use alloy_primitives::{Address, BlockHash, Bytes, B128, B256, U256, U64};
14use alloy_rpc_types_engine::{
15 ClientVersionV1, ExecutionPayloadBodiesV1, ExecutionPayloadBodiesV2, ExecutionPayloadInputV2,
16 ExecutionPayloadV1, ExecutionPayloadV3, ExecutionPayloadV4, ForkchoiceState, ForkchoiceUpdated,
17 ForkchoiceUpdatedResponseV2, PayloadId, PayloadStatus, PayloadStatusV2,
18};
19use alloy_rpc_types_eth::{
20 state::StateOverride, BlockOverrides, EIP1186AccountProofResponse, Filter, Index, SyncStatus,
21};
22use alloy_serde::JsonStorageKey;
23use jsonrpsee::{core::RpcResult, proc_macros::rpc, RpcModule};
24use reth_engine_primitives::EngineTypes;
25
26/// Helper trait for the engine api server.
27///
28/// This type-erases the concrete [`jsonrpsee`] server implementation and only returns the
29/// [`RpcModule`] that contains all the endpoints of the server.
30pub trait IntoEngineApiRpcModule {
31 /// Consumes the type and returns all the methods and subscriptions defined in the trait and
32 /// returns them as a single [`RpcModule`]
33 fn into_rpc_module(self) -> RpcModule<()>;
34}
35
36// NOTE: We can't use associated types in the `EngineApi` trait because of jsonrpsee, so we use a
37// generic here. It would be nice if the rpc macro would understand which types need to have serde.
38// By default, if the trait has a generic, the rpc macro will add e.g. `Engine: DeserializeOwned` to
39// the trait bounds, which is not what we want, because `Types` is not used directly in any of the
40// trait methods. Instead, we have to add the bounds manually. This would be disastrous if we had
41// more than one associated type used in the trait methods.
42
43#[rpc(server, namespace = "engine")]
44pub trait EngineApi<Engine: EngineTypes> {
45 /// See also <https://github.com/ethereum/execution-apis/blob/6709c2a795b707202e93c4f2867fa0bf2640a84f/src/engine/paris.md#engine_newpayloadv1>
46 /// Caution: This should not accept the `withdrawals` field
47 #[method(name = "newPayloadV1")]
48 async fn new_payload_v1(&self, payload: ExecutionPayloadV1) -> RpcResult<PayloadStatus>;
49
50 /// See also <https://github.com/ethereum/execution-apis/blob/584905270d8ad665718058060267061ecfd79ca5/src/engine/shanghai.md#engine_newpayloadv2>
51 #[method(name = "newPayloadV2")]
52 async fn new_payload_v2(&self, payload: ExecutionPayloadInputV2) -> RpcResult<PayloadStatus>;
53
54 /// Post Cancun payload handler
55 ///
56 /// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/cancun.md#engine_newpayloadv3>
57 #[method(name = "newPayloadV3")]
58 async fn new_payload_v3(
59 &self,
60 payload: ExecutionPayloadV3,
61 versioned_hashes: Vec<B256>,
62 parent_beacon_block_root: B256,
63 ) -> RpcResult<PayloadStatus>;
64
65 /// Post Prague payload handler
66 ///
67 /// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/prague.md#engine_newpayloadv4>
68 #[method(name = "newPayloadV4")]
69 async fn new_payload_v4(
70 &self,
71 payload: ExecutionPayloadV3,
72 versioned_hashes: Vec<B256>,
73 parent_beacon_block_root: B256,
74 execution_requests: RequestsOrHash,
75 ) -> RpcResult<PayloadStatus>;
76
77 /// Post Amsterdam payload handler
78 ///
79 /// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/amsterdam.md#engine_newpayloadv5>
80 #[method(name = "newPayloadV5")]
81 async fn new_payload_v5(
82 &self,
83 payload: ExecutionPayloadV4,
84 versioned_hashes: Vec<B256>,
85 parent_beacon_block_root: B256,
86 execution_requests: RequestsOrHash,
87 ) -> RpcResult<PayloadStatus>;
88
89 /// Post Bogota payload handler stub.
90 ///
91 /// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/bogota.md#engine_newpayloadv6>
92 #[method(name = "newPayloadV6")]
93 async fn new_payload_v6(
94 &self,
95 payload: ExecutionPayloadV4,
96 versioned_hashes: Vec<B256>,
97 parent_beacon_block_root: B256,
98 execution_requests: RequestsOrHash,
99 inclusion_list_transactions: Vec<Bytes>,
100 ) -> RpcResult<PayloadStatusV2>;
101
102 /// See also <https://github.com/ethereum/execution-apis/blob/6709c2a795b707202e93c4f2867fa0bf2640a84f/src/engine/paris.md#engine_forkchoiceupdatedv1>
103 ///
104 /// Caution: This should not accept the `withdrawals` field in the payload attributes.
105 #[method(name = "forkchoiceUpdatedV1")]
106 async fn fork_choice_updated_v1(
107 &self,
108 fork_choice_state: ForkchoiceState,
109 payload_attributes: Option<Engine::PayloadAttributes>,
110 ) -> RpcResult<ForkchoiceUpdated>;
111
112 /// Post Shanghai forkchoice update handler
113 ///
114 /// This is the same as `forkchoiceUpdatedV1`, but expects an additional `withdrawals` field in
115 /// the `payloadAttributes`, if payload attributes are provided.
116 ///
117 /// See also <https://github.com/ethereum/execution-apis/blob/6709c2a795b707202e93c4f2867fa0bf2640a84f/src/engine/shanghai.md#engine_forkchoiceupdatedv2>
118 ///
119 /// Caution: This should not accept the `parentBeaconBlockRoot` field in the payload
120 /// attributes.
121 #[method(name = "forkchoiceUpdatedV2")]
122 async fn fork_choice_updated_v2(
123 &self,
124 fork_choice_state: ForkchoiceState,
125 payload_attributes: Option<Engine::PayloadAttributes>,
126 ) -> RpcResult<ForkchoiceUpdated>;
127
128 /// Post Cancun forkchoice update handler
129 ///
130 /// This is the same as `forkchoiceUpdatedV2`, but expects an additional
131 /// `parentBeaconBlockRoot` field in the `payloadAttributes`, if payload attributes
132 /// are provided.
133 ///
134 /// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/cancun.md#engine_forkchoiceupdatedv3>
135 #[method(name = "forkchoiceUpdatedV3")]
136 async fn fork_choice_updated_v3(
137 &self,
138 fork_choice_state: ForkchoiceState,
139 payload_attributes: Option<Engine::PayloadAttributes>,
140 ) -> RpcResult<ForkchoiceUpdated>;
141
142 /// Post Amsterdam forkchoice update handler
143 ///
144 /// This is the same as `forkchoiceUpdatedV3`, but expects an additional
145 /// `slotNumber` field in the `payloadAttributes`, if payload attributes
146 /// are provided.
147 ///
148 /// `custody_columns` maps to the third positional JSON-RPC parameter, `custodyColumns`,
149 /// the custody-column bitmask used for [EIP-8070] sparse blobpool signaling. It is
150 /// `DATA|null` and must be 16 bytes when set. When calling `engine_forkchoiceUpdatedV4`
151 /// with custody columns but without payload attributes, the second parameter must still
152 /// be supplied as `null`, for example:
153 /// `[forkchoiceState, null, custodyColumns]`.
154 ///
155 /// [EIP-8070]: https://eips.ethereum.org/EIPS/eip-8070
156 ///
157 /// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/amsterdam.md#engine_forkchoiceupdatedv4>
158 #[method(name = "forkchoiceUpdatedV4")]
159 async fn fork_choice_updated_v4(
160 &self,
161 fork_choice_state: ForkchoiceState,
162 payload_attributes: Option<Engine::PayloadAttributes>,
163 custody_columns: Option<B128>,
164 ) -> RpcResult<ForkchoiceUpdated>;
165
166 /// Post Bogota forkchoice update stub.
167 ///
168 /// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/bogota.md#engine_forkchoiceupdatedv5>
169 #[method(name = "forkchoiceUpdatedV5")]
170 async fn fork_choice_updated_v5(
171 &self,
172 fork_choice_state: ForkchoiceState,
173 payload_attributes: Option<Engine::PayloadAttributes>,
174 custody_columns: Option<B128>,
175 ) -> RpcResult<ForkchoiceUpdatedResponseV2>;
176
177 /// See also <https://github.com/ethereum/execution-apis/blob/6709c2a795b707202e93c4f2867fa0bf2640a84f/src/engine/paris.md#engine_getpayloadv1>
178 ///
179 /// Returns the most recent version of the payload that is available in the corresponding
180 /// payload build process at the time of receiving this call.
181 ///
182 /// Caution: This should not return the `withdrawals` field
183 ///
184 /// Note:
185 /// > Provider software MAY stop the corresponding build process after serving this call.
186 #[method(name = "getPayloadV1")]
187 async fn get_payload_v1(
188 &self,
189 payload_id: PayloadId,
190 ) -> RpcResult<Engine::ExecutionPayloadEnvelopeV1>;
191
192 /// See also <https://github.com/ethereum/execution-apis/blob/6709c2a795b707202e93c4f2867fa0bf2640a84f/src/engine/shanghai.md#engine_getpayloadv2>
193 ///
194 /// Returns the most recent version of the payload that is available in the corresponding
195 /// payload build process at the time of receiving this call. Note:
196 /// > Provider software MAY stop the corresponding build process after serving this call.
197 #[method(name = "getPayloadV2")]
198 async fn get_payload_v2(
199 &self,
200 payload_id: PayloadId,
201 ) -> RpcResult<Engine::ExecutionPayloadEnvelopeV2>;
202
203 /// Post Cancun payload handler which also returns a blobs bundle.
204 ///
205 /// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/cancun.md#engine_getpayloadv3>
206 ///
207 /// Returns the most recent version of the payload that is available in the corresponding
208 /// payload build process at the time of receiving this call. Note:
209 /// > Provider software MAY stop the corresponding build process after serving this call.
210 #[method(name = "getPayloadV3")]
211 async fn get_payload_v3(
212 &self,
213 payload_id: PayloadId,
214 ) -> RpcResult<Engine::ExecutionPayloadEnvelopeV3>;
215
216 /// Post Prague payload handler.
217 ///
218 /// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/prague.md#engine_getpayloadv4>
219 ///
220 /// Returns the most recent version of the payload that is available in the corresponding
221 /// payload build process at the time of receiving this call. Note:
222 /// > Provider software MAY stop the corresponding build process after serving this call.
223 #[method(name = "getPayloadV4")]
224 async fn get_payload_v4(
225 &self,
226 payload_id: PayloadId,
227 ) -> RpcResult<Engine::ExecutionPayloadEnvelopeV4>;
228
229 /// Post Osaka payload handler.
230 ///
231 /// See also <https://github.com/ethereum/execution-apis/blob/15399c2e2f16a5f800bf3f285640357e2c245ad9/src/engine/osaka.md#engine_getpayloadv5>.
232 ///
233 /// Returns the most recent version of the payload that is available in the corresponding
234 /// payload build process at the time of receiving this call. Note:
235 /// > Provider software MAY stop the corresponding build process after serving this call.
236 #[method(name = "getPayloadV5")]
237 async fn get_payload_v5(
238 &self,
239 payload_id: PayloadId,
240 ) -> RpcResult<Engine::ExecutionPayloadEnvelopeV5>;
241
242 /// Post Amsterdam payload handler.
243 ///
244 /// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/amsterdam.md#engine_getpayloadv6>
245 ///
246 /// Returns the most recent version of the payload that is available in the corresponding
247 /// payload build process at the time of receiving this call. Note:
248 /// > Provider software MAY stop the corresponding build process after serving this call.
249 #[method(name = "getPayloadV6")]
250 async fn get_payload_v6(
251 &self,
252 payload_id: PayloadId,
253 ) -> RpcResult<Engine::ExecutionPayloadEnvelopeV6>;
254
255 /// Returns transactions selected from the local transaction pool for the FOCIL inclusion list.
256 ///
257 /// See also <https://github.com/ethereum/execution-apis/pull/609>.
258 #[method(name = "getInclusionListV1")]
259 async fn get_inclusion_list_v1(&self) -> RpcResult<Vec<Bytes>>;
260
261 /// See also <https://github.com/ethereum/execution-apis/blob/6452a6b194d7db269bf1dbd087a267251d3cc7f8/src/engine/shanghai.md#engine_getpayloadbodiesbyhashv1>
262 #[method(name = "getPayloadBodiesByHashV1")]
263 async fn get_payload_bodies_by_hash_v1(
264 &self,
265 block_hashes: Vec<BlockHash>,
266 ) -> RpcResult<ExecutionPayloadBodiesV1>;
267
268 /// Returns `ExecutionPayloadBodyV2` objects for the given block hashes.
269 ///
270 /// V2 includes the `block_access_list` field for EIP-7928 BAL support.
271 ///
272 /// See also <https://eips.ethereum.org/EIPS/eip-7928>
273 #[method(name = "getPayloadBodiesByHashV2")]
274 async fn get_payload_bodies_by_hash_v2(
275 &self,
276 block_hashes: Vec<BlockHash>,
277 ) -> RpcResult<ExecutionPayloadBodiesV2>;
278
279 /// See also <https://github.com/ethereum/execution-apis/blob/6452a6b194d7db269bf1dbd087a267251d3cc7f8/src/engine/shanghai.md#engine_getpayloadbodiesbyrangev1>
280 ///
281 /// Returns the execution payload bodies by the range starting at `start`, containing `count`
282 /// blocks.
283 ///
284 /// WARNING: This method is associated with the `BeaconBlocksByRange` message in the consensus
285 /// layer p2p specification, meaning the input should be treated as untrusted or potentially
286 /// adversarial.
287 ///
288 /// Implementers should take care when acting on the input to this method, specifically
289 /// ensuring that the range is limited properly, and that the range boundaries are computed
290 /// correctly and without panics.
291 #[method(name = "getPayloadBodiesByRangeV1")]
292 async fn get_payload_bodies_by_range_v1(
293 &self,
294 start: U64,
295 count: U64,
296 ) -> RpcResult<ExecutionPayloadBodiesV1>;
297
298 /// Returns `ExecutionPayloadBodyV2` objects for the given block range.
299 ///
300 /// V2 includes the `block_access_list` field for EIP-7928 BAL support.
301 ///
302 /// WARNING: This method is associated with the `BeaconBlocksByRange` message in the consensus
303 /// layer p2p specification, meaning the input should be treated as untrusted or potentially
304 /// adversarial.
305 ///
306 /// Implementers should take care when acting on the input to this method, specifically
307 /// ensuring that the range is limited properly, and that the range boundaries are computed
308 /// correctly and without panics.
309 ///
310 /// See also <https://eips.ethereum.org/EIPS/eip-7928>
311 #[method(name = "getPayloadBodiesByRangeV2")]
312 async fn get_payload_bodies_by_range_v2(
313 &self,
314 start: U64,
315 count: U64,
316 ) -> RpcResult<ExecutionPayloadBodiesV2>;
317
318 /// This function will return the [`ClientVersionV1`] object.
319 /// See also:
320 /// <https://github.com/ethereum/execution-apis/blob/03911ffc053b8b806123f1fc237184b0092a485a/src/engine/identification.md#engine_getclientversionv1>
321 ///
322 ///
323 /// - When connected to a single execution client, the consensus client **MUST** receive an
324 /// array with a single `ClientVersionV1` object.
325 /// - When connected to multiple execution clients via a multiplexer, the multiplexer **MUST**
326 /// concatenate the responses from each execution client into a single,
327 /// flat array before returning the response to the consensus client.
328 #[method(name = "getClientVersionV1")]
329 async fn get_client_version_v1(
330 &self,
331 client_version: ClientVersionV1,
332 ) -> RpcResult<Vec<ClientVersionV1>>;
333
334 /// See also <https://github.com/ethereum/execution-apis/blob/6452a6b194d7db269bf1dbd087a267251d3cc7f8/src/engine/common.md#capabilities>
335 #[method(name = "exchangeCapabilities")]
336 async fn exchange_capabilities(&self, capabilities: Vec<String>) -> RpcResult<Vec<String>>;
337
338 /// Report blob availability for the requested blob versioned hashes.
339 #[method(name = "hasBlobs")]
340 async fn has_blobs(&self, versioned_hashes: Vec<B256>) -> RpcResult<Vec<bool>>;
341
342 /// Fetch blobs for the consensus layer from the blob store.
343 #[method(name = "getBlobsV1")]
344 async fn get_blobs_v1(
345 &self,
346 versioned_hashes: Vec<B256>,
347 ) -> RpcResult<Vec<Option<BlobAndProofV1>>>;
348
349 /// Fetch blobs for the consensus layer from the blob store.
350 ///
351 /// Returns a response only if blobs and proofs are present for _all_ of the versioned hashes:
352 /// 2. Client software MUST return null in case of any missing or older version blobs.
353 #[method(name = "getBlobsV2")]
354 async fn get_blobs_v2(
355 &self,
356 versioned_hashes: Vec<B256>,
357 ) -> RpcResult<Option<Vec<BlobAndProofV2>>>;
358
359 /// Fetch blobs for the consensus layer from the blob store.
360 ///
361 /// Returns a response of the same length as the request. Missing or older-version blobs are
362 /// returned as `null` elements.
363 ///
364 /// Returns `null` if syncing.
365 #[method(name = "getBlobsV3")]
366 async fn get_blobs_v3(
367 &self,
368 versioned_hashes: Vec<B256>,
369 ) -> RpcResult<Option<Vec<Option<BlobAndProofV2>>>>;
370
371 /// Fetch blob cells for the consensus layer from the blob store.
372 ///
373 /// Returns a response of the same length as the request. Missing blobs are returned as `null`
374 /// elements; missing requested cells within an available blob are returned as `null` cell and
375 /// proof entries.
376 ///
377 /// Returns `null` if syncing.
378 #[method(name = "getBlobsV4")]
379 async fn get_blobs_v4(
380 &self,
381 versioned_hashes: Vec<B256>,
382 indices_bitarray: B128,
383 ) -> RpcResult<Option<Vec<Option<BlobCellsAndProofsV1>>>>;
384}
385
386/// A subset of the ETH rpc interface: <https://ethereum.github.io/execution-apis/api-documentation>
387///
388/// This also includes additional eth functions required by optimism.
389///
390/// Specifically for the engine auth server: <https://github.com/ethereum/execution-apis/blob/main/src/engine/common.md#underlying-protocol>
391#[rpc(server, namespace = "eth")]
392pub trait EngineEthApi<TxReq: RpcObject, B: RpcObject, R: RpcObject, L: RpcObject> {
393 /// Returns an object with data about the sync status or false.
394 #[method(name = "syncing")]
395 fn syncing(&self) -> RpcResult<SyncStatus>;
396
397 /// Returns the chain ID of the current network.
398 #[method(name = "chainId")]
399 async fn chain_id(&self) -> RpcResult<Option<U64>>;
400
401 /// Returns the number of most recent block.
402 #[method(name = "blockNumber")]
403 fn block_number(&self) -> RpcResult<U256>;
404
405 /// Executes a new message call immediately without creating a transaction on the block chain.
406 #[method(name = "call")]
407 async fn call(
408 &self,
409 request: TxReq,
410 block_id: Option<BlockId>,
411 state_overrides: Option<StateOverride>,
412 block_overrides: Option<Box<BlockOverrides>>,
413 ) -> RpcResult<Bytes>;
414
415 /// Returns code at a given address at given block number.
416 #[method(name = "getCode")]
417 async fn get_code(&self, address: Address, block_id: Option<BlockId>) -> RpcResult<Bytes>;
418
419 /// Returns information about a block by hash.
420 #[method(name = "getBlockByHash")]
421 async fn block_by_hash(&self, hash: B256, full: bool) -> RpcResult<Option<B>>;
422
423 /// Returns information about a block by number.
424 #[method(name = "getBlockByNumber")]
425 async fn block_by_number(&self, number: BlockNumberOrTag, full: bool) -> RpcResult<Option<B>>;
426
427 /// Returns all transaction receipts for a given block.
428 #[method(name = "getBlockReceipts")]
429 async fn block_receipts(&self, block_id: BlockId) -> RpcResult<Option<Vec<R>>>;
430
431 /// Returns the EIP-2718 encoded transaction by block hash and transaction index position.
432 #[method(name = "getRawTransactionByBlockHashAndIndex")]
433 async fn raw_transaction_by_block_hash_and_index(
434 &self,
435 hash: B256,
436 index: Index,
437 ) -> RpcResult<Option<Bytes>>;
438
439 /// Returns the EIP-2718 encoded transaction by block number and transaction index position.
440 #[method(name = "getRawTransactionByBlockNumberAndIndex")]
441 async fn raw_transaction_by_block_number_and_index(
442 &self,
443 number: BlockNumberOrTag,
444 index: Index,
445 ) -> RpcResult<Option<Bytes>>;
446
447 /// Sends signed transaction, returning its hash.
448 #[method(name = "sendRawTransaction")]
449 async fn send_raw_transaction(&self, bytes: Bytes) -> RpcResult<B256>;
450
451 /// Returns the receipt of a transaction by transaction hash.
452 #[method(name = "getTransactionReceipt")]
453 async fn transaction_receipt(&self, hash: B256) -> RpcResult<Option<R>>;
454
455 /// Returns logs matching given filter object.
456 #[method(name = "getLogs")]
457 async fn logs(&self, filter: Filter) -> RpcResult<Vec<L>>;
458
459 /// Returns the account and storage values of the specified account including the Merkle-proof.
460 /// This call can be used to verify that the data you are pulling from is not tampered with.
461 #[method(name = "getProof")]
462 async fn get_proof(
463 &self,
464 address: Address,
465 keys: Vec<JsonStorageKey>,
466 block_number: Option<BlockId>,
467 ) -> RpcResult<EIP1186AccountProofResponse>;
468
469 /// Returns the account and storage values of the specified targets including Merkle proofs.
470 #[method(name = "getMultiProof")]
471 async fn get_multi_proof(
472 &self,
473 targets: Vec<(Address, Vec<B256>)>,
474 block_number: Option<BlockId>,
475 ) -> RpcResult<Vec<EIP1186AccountProofResponse>>;
476
477 /// Returns the EIP-7928 block access list for a block by hash.
478 #[method(name = "getBlockAccessListByBlockHash")]
479 async fn block_access_list_by_block_hash(
480 &self,
481 hash: B256,
482 ) -> RpcResult<Option<BlockAccessList>>;
483
484 /// Returns the EIP-7928 block access list for a block by number.
485 #[method(name = "getBlockAccessListByBlockNumber")]
486 async fn block_access_list_by_block_number(
487 &self,
488 number: BlockNumberOrTag,
489 ) -> RpcResult<Option<BlockAccessList>>;
490
491 /// Returns the EIP-7928 block access list for a block by block id.
492 #[method(name = "getBlockAccessList")]
493 async fn block_access_list(&self, block_id: BlockId) -> RpcResult<Option<BlockAccessList>>;
494
495 /// Returns the EIP-7928 block access list bytes for a block by number.
496 #[method(name = "getBlockAccessListRaw")]
497 async fn block_access_list_raw(&self, block: BlockId) -> RpcResult<Option<Bytes>>;
498}