Skip to main content

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}