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    BlockId, BlockNumberOrTag,
10};
11use alloy_json_rpc::RpcObject;
12use alloy_primitives::{Address, BlockHash, Bytes, B128, B256, U256, U64};
13use alloy_rpc_types_engine::{
14    ClientVersionV1, ExecutionPayloadBodiesV1, ExecutionPayloadBodiesV2, ExecutionPayloadInputV2,
15    ExecutionPayloadV1, ExecutionPayloadV3, ExecutionPayloadV4, ForkchoiceState, ForkchoiceUpdated,
16    PayloadId, PayloadStatus,
17};
18use alloy_rpc_types_eth::{
19    state::StateOverride, BlockOverrides, EIP1186AccountProofResponse, Filter, Log, SyncStatus,
20};
21use alloy_serde::JsonStorageKey;
22use jsonrpsee::{core::RpcResult, proc_macros::rpc, RpcModule};
23use reth_engine_primitives::EngineTypes;
24use serde_json::Value;
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#[cfg_attr(not(feature = "client"), rpc(server, namespace = "engine"), server_bounds(Engine::PayloadAttributes: jsonrpsee::core::DeserializeOwned))]
44#[cfg_attr(feature = "client", rpc(server, client, namespace = "engine", client_bounds(Engine::PayloadAttributes: jsonrpsee::core::Serialize + Clone), server_bounds(Engine::PayloadAttributes: jsonrpsee::core::DeserializeOwned)))]
45pub trait EngineApi<Engine: EngineTypes> {
46    /// See also <https://github.com/ethereum/execution-apis/blob/6709c2a795b707202e93c4f2867fa0bf2640a84f/src/engine/paris.md#engine_newpayloadv1>
47    /// Caution: This should not accept the `withdrawals` field
48    #[method(name = "newPayloadV1")]
49    async fn new_payload_v1(&self, payload: ExecutionPayloadV1) -> RpcResult<PayloadStatus>;
50
51    /// See also <https://github.com/ethereum/execution-apis/blob/584905270d8ad665718058060267061ecfd79ca5/src/engine/shanghai.md#engine_newpayloadv2>
52    #[method(name = "newPayloadV2")]
53    async fn new_payload_v2(&self, payload: ExecutionPayloadInputV2) -> RpcResult<PayloadStatus>;
54
55    /// Post Cancun payload handler
56    ///
57    /// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/cancun.md#engine_newpayloadv3>
58    #[method(name = "newPayloadV3")]
59    async fn new_payload_v3(
60        &self,
61        payload: ExecutionPayloadV3,
62        versioned_hashes: Vec<B256>,
63        parent_beacon_block_root: B256,
64    ) -> RpcResult<PayloadStatus>;
65
66    /// Post Prague payload handler
67    ///
68    /// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/prague.md#engine_newpayloadv4>
69    #[method(name = "newPayloadV4")]
70    async fn new_payload_v4(
71        &self,
72        payload: ExecutionPayloadV3,
73        versioned_hashes: Vec<B256>,
74        parent_beacon_block_root: B256,
75        execution_requests: RequestsOrHash,
76    ) -> RpcResult<PayloadStatus>;
77
78    /// Post Amsterdam payload handler
79    ///
80    /// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/amsterdam.md#engine_newpayloadv5>
81    #[method(name = "newPayloadV5")]
82    async fn new_payload_v5(
83        &self,
84        payload: ExecutionPayloadV4,
85        versioned_hashes: Vec<B256>,
86        parent_beacon_block_root: B256,
87        execution_requests: RequestsOrHash,
88    ) -> RpcResult<PayloadStatus>;
89
90    /// See also <https://github.com/ethereum/execution-apis/blob/6709c2a795b707202e93c4f2867fa0bf2640a84f/src/engine/paris.md#engine_forkchoiceupdatedv1>
91    ///
92    /// Caution: This should not accept the `withdrawals` field in the payload attributes.
93    #[method(name = "forkchoiceUpdatedV1")]
94    async fn fork_choice_updated_v1(
95        &self,
96        fork_choice_state: ForkchoiceState,
97        payload_attributes: Option<Engine::PayloadAttributes>,
98    ) -> RpcResult<ForkchoiceUpdated>;
99
100    /// Post Shanghai forkchoice update handler
101    ///
102    /// This is the same as `forkchoiceUpdatedV1`, but expects an additional `withdrawals` field in
103    /// the `payloadAttributes`, if payload attributes are provided.
104    ///
105    /// See also <https://github.com/ethereum/execution-apis/blob/6709c2a795b707202e93c4f2867fa0bf2640a84f/src/engine/shanghai.md#engine_forkchoiceupdatedv2>
106    ///
107    /// Caution: This should not accept the `parentBeaconBlockRoot` field in the payload
108    /// attributes.
109    #[method(name = "forkchoiceUpdatedV2")]
110    async fn fork_choice_updated_v2(
111        &self,
112        fork_choice_state: ForkchoiceState,
113        payload_attributes: Option<Engine::PayloadAttributes>,
114    ) -> RpcResult<ForkchoiceUpdated>;
115
116    /// Post Cancun forkchoice update handler
117    ///
118    /// This is the same as `forkchoiceUpdatedV2`, but expects an additional
119    /// `parentBeaconBlockRoot` field in the `payloadAttributes`, if payload attributes
120    /// are provided.
121    ///
122    /// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/cancun.md#engine_forkchoiceupdatedv3>
123    #[method(name = "forkchoiceUpdatedV3")]
124    async fn fork_choice_updated_v3(
125        &self,
126        fork_choice_state: ForkchoiceState,
127        payload_attributes: Option<Engine::PayloadAttributes>,
128    ) -> RpcResult<ForkchoiceUpdated>;
129
130    /// Post Amsterdam forkchoice update handler
131    ///
132    /// This is the same as `forkchoiceUpdatedV3`, but expects an additional
133    /// `slotNumber` field in the `payloadAttributes`, if payload attributes
134    /// are provided.
135    ///
136    /// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/amsterdam.md#engine_forkchoiceupdatedv4>
137    #[method(name = "forkchoiceUpdatedV4")]
138    async fn fork_choice_updated_v4(
139        &self,
140        fork_choice_state: ForkchoiceState,
141        payload_attributes: Option<Engine::PayloadAttributes>,
142    ) -> RpcResult<ForkchoiceUpdated>;
143
144    /// See also <https://github.com/ethereum/execution-apis/blob/6709c2a795b707202e93c4f2867fa0bf2640a84f/src/engine/paris.md#engine_getpayloadv1>
145    ///
146    /// Returns the most recent version of the payload that is available in the corresponding
147    /// payload build process at the time of receiving this call.
148    ///
149    /// Caution: This should not return the `withdrawals` field
150    ///
151    /// Note:
152    /// > Provider software MAY stop the corresponding build process after serving this call.
153    #[method(name = "getPayloadV1")]
154    async fn get_payload_v1(
155        &self,
156        payload_id: PayloadId,
157    ) -> RpcResult<Engine::ExecutionPayloadEnvelopeV1>;
158
159    /// See also <https://github.com/ethereum/execution-apis/blob/6709c2a795b707202e93c4f2867fa0bf2640a84f/src/engine/shanghai.md#engine_getpayloadv2>
160    ///
161    /// Returns the most recent version of the payload that is available in the corresponding
162    /// payload build process at the time of receiving this call. Note:
163    /// > Provider software MAY stop the corresponding build process after serving this call.
164    #[method(name = "getPayloadV2")]
165    async fn get_payload_v2(
166        &self,
167        payload_id: PayloadId,
168    ) -> RpcResult<Engine::ExecutionPayloadEnvelopeV2>;
169
170    /// Post Cancun payload handler which also returns a blobs bundle.
171    ///
172    /// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/cancun.md#engine_getpayloadv3>
173    ///
174    /// Returns the most recent version of the payload that is available in the corresponding
175    /// payload build process at the time of receiving this call. Note:
176    /// > Provider software MAY stop the corresponding build process after serving this call.
177    #[method(name = "getPayloadV3")]
178    async fn get_payload_v3(
179        &self,
180        payload_id: PayloadId,
181    ) -> RpcResult<Engine::ExecutionPayloadEnvelopeV3>;
182
183    /// Post Prague payload handler.
184    ///
185    /// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/prague.md#engine_getpayloadv4>
186    ///
187    /// Returns the most recent version of the payload that is available in the corresponding
188    /// payload build process at the time of receiving this call. Note:
189    /// > Provider software MAY stop the corresponding build process after serving this call.
190    #[method(name = "getPayloadV4")]
191    async fn get_payload_v4(
192        &self,
193        payload_id: PayloadId,
194    ) -> RpcResult<Engine::ExecutionPayloadEnvelopeV4>;
195
196    /// Post Osaka payload handler.
197    ///
198    /// See also <https://github.com/ethereum/execution-apis/blob/15399c2e2f16a5f800bf3f285640357e2c245ad9/src/engine/osaka.md#engine_getpayloadv5>.
199    ///
200    /// Returns the most recent version of the payload that is available in the corresponding
201    /// payload build process at the time of receiving this call. Note:
202    /// > Provider software MAY stop the corresponding build process after serving this call.
203    #[method(name = "getPayloadV5")]
204    async fn get_payload_v5(
205        &self,
206        payload_id: PayloadId,
207    ) -> RpcResult<Engine::ExecutionPayloadEnvelopeV5>;
208
209    /// Post Amsterdam payload handler.
210    ///
211    /// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/amsterdam.md#engine_getpayloadv6>
212    ///
213    /// Returns the most recent version of the payload that is available in the corresponding
214    /// payload build process at the time of receiving this call. Note:
215    /// > Provider software MAY stop the corresponding build process after serving this call.
216    #[method(name = "getPayloadV6")]
217    async fn get_payload_v6(
218        &self,
219        payload_id: PayloadId,
220    ) -> RpcResult<Engine::ExecutionPayloadEnvelopeV6>;
221
222    /// See also <https://github.com/ethereum/execution-apis/blob/6452a6b194d7db269bf1dbd087a267251d3cc7f8/src/engine/shanghai.md#engine_getpayloadbodiesbyhashv1>
223    #[method(name = "getPayloadBodiesByHashV1")]
224    async fn get_payload_bodies_by_hash_v1(
225        &self,
226        block_hashes: Vec<BlockHash>,
227    ) -> RpcResult<ExecutionPayloadBodiesV1>;
228
229    /// Returns `ExecutionPayloadBodyV2` objects for the given block hashes.
230    ///
231    /// V2 includes the `block_access_list` field for EIP-7928 BAL support.
232    ///
233    /// See also <https://eips.ethereum.org/EIPS/eip-7928>
234    #[method(name = "getPayloadBodiesByHashV2")]
235    async fn get_payload_bodies_by_hash_v2(
236        &self,
237        block_hashes: Vec<BlockHash>,
238    ) -> RpcResult<ExecutionPayloadBodiesV2>;
239
240    /// See also <https://github.com/ethereum/execution-apis/blob/6452a6b194d7db269bf1dbd087a267251d3cc7f8/src/engine/shanghai.md#engine_getpayloadbodiesbyrangev1>
241    ///
242    /// Returns the execution payload bodies by the range starting at `start`, containing `count`
243    /// blocks.
244    ///
245    /// WARNING: This method is associated with the `BeaconBlocksByRange` message in the consensus
246    /// layer p2p specification, meaning the input should be treated as untrusted or potentially
247    /// adversarial.
248    ///
249    /// Implementers should take care when acting on the input to this method, specifically
250    /// ensuring that the range is limited properly, and that the range boundaries are computed
251    /// correctly and without panics.
252    #[method(name = "getPayloadBodiesByRangeV1")]
253    async fn get_payload_bodies_by_range_v1(
254        &self,
255        start: U64,
256        count: U64,
257    ) -> RpcResult<ExecutionPayloadBodiesV1>;
258
259    /// Returns `ExecutionPayloadBodyV2` objects for the given block range.
260    ///
261    /// V2 includes the `block_access_list` field for EIP-7928 BAL support.
262    ///
263    /// WARNING: This method is associated with the `BeaconBlocksByRange` message in the consensus
264    /// layer p2p specification, meaning the input should be treated as untrusted or potentially
265    /// adversarial.
266    ///
267    /// Implementers should take care when acting on the input to this method, specifically
268    /// ensuring that the range is limited properly, and that the range boundaries are computed
269    /// correctly and without panics.
270    ///
271    /// See also <https://eips.ethereum.org/EIPS/eip-7928>
272    #[method(name = "getPayloadBodiesByRangeV2")]
273    async fn get_payload_bodies_by_range_v2(
274        &self,
275        start: U64,
276        count: U64,
277    ) -> RpcResult<ExecutionPayloadBodiesV2>;
278
279    /// This function will return the [`ClientVersionV1`] object.
280    /// See also:
281    /// <https://github.com/ethereum/execution-apis/blob/03911ffc053b8b806123f1fc237184b0092a485a/src/engine/identification.md#engine_getclientversionv1>
282    ///
283    ///
284    /// - When connected to a single execution client, the consensus client **MUST** receive an
285    ///   array with a single `ClientVersionV1` object.
286    /// - When connected to multiple execution clients via a multiplexer, the multiplexer **MUST**
287    ///   concatenate the responses from each execution client into a single,
288    /// flat array before returning the response to the consensus client.
289    #[method(name = "getClientVersionV1")]
290    async fn get_client_version_v1(
291        &self,
292        client_version: ClientVersionV1,
293    ) -> RpcResult<Vec<ClientVersionV1>>;
294
295    /// See also <https://github.com/ethereum/execution-apis/blob/6452a6b194d7db269bf1dbd087a267251d3cc7f8/src/engine/common.md#capabilities>
296    #[method(name = "exchangeCapabilities")]
297    async fn exchange_capabilities(&self, capabilities: Vec<String>) -> RpcResult<Vec<String>>;
298
299    /// Fetch blobs for the consensus layer from the blob store.
300    #[method(name = "getBlobsV1")]
301    async fn get_blobs_v1(
302        &self,
303        versioned_hashes: Vec<B256>,
304    ) -> RpcResult<Vec<Option<BlobAndProofV1>>>;
305
306    /// Fetch blobs for the consensus layer from the blob store.
307    ///
308    /// Returns a response only if blobs and proofs are present for _all_ of the versioned hashes:
309    ///     2. Client software MUST return null in case of any missing or older version blobs.
310    #[method(name = "getBlobsV2")]
311    async fn get_blobs_v2(
312        &self,
313        versioned_hashes: Vec<B256>,
314    ) -> RpcResult<Option<Vec<BlobAndProofV2>>>;
315
316    /// Fetch blobs for the consensus layer from the blob store.
317    ///
318    /// Returns a response of the same length as the request. Missing or older-version blobs are
319    /// returned as `null` elements.
320    ///
321    /// Returns `null` if syncing.
322    #[method(name = "getBlobsV3")]
323    async fn get_blobs_v3(
324        &self,
325        versioned_hashes: Vec<B256>,
326    ) -> RpcResult<Option<Vec<Option<BlobAndProofV2>>>>;
327
328    /// Fetch blob cells for the consensus layer from the blob store.
329    ///
330    /// Returns a response of the same length as the request. Missing blobs are returned as `null`
331    /// elements; missing requested cells within an available blob are returned as `null` cell and
332    /// proof entries.
333    ///
334    /// Returns `null` if syncing.
335    #[method(name = "getBlobsV4")]
336    async fn get_blobs_v4(
337        &self,
338        versioned_hashes: Vec<B256>,
339        indices_bitarray: B128,
340    ) -> RpcResult<Option<Vec<Option<BlobCellsAndProofsV1>>>>;
341}
342
343/// A subset of the ETH rpc interface: <https://ethereum.github.io/execution-apis/api-documentation>
344///
345/// This also includes additional eth functions required by optimism.
346///
347/// Specifically for the engine auth server: <https://github.com/ethereum/execution-apis/blob/main/src/engine/common.md#underlying-protocol>
348#[cfg_attr(not(feature = "client"), rpc(server, namespace = "eth"))]
349#[cfg_attr(feature = "client", rpc(server, client, namespace = "eth"))]
350pub trait EngineEthApi<TxReq: RpcObject, B: RpcObject, R: RpcObject> {
351    /// Returns an object with data about the sync status or false.
352    #[method(name = "syncing")]
353    fn syncing(&self) -> RpcResult<SyncStatus>;
354
355    /// Returns the chain ID of the current network.
356    #[method(name = "chainId")]
357    async fn chain_id(&self) -> RpcResult<Option<U64>>;
358
359    /// Returns the number of most recent block.
360    #[method(name = "blockNumber")]
361    fn block_number(&self) -> RpcResult<U256>;
362
363    /// Executes a new message call immediately without creating a transaction on the block chain.
364    #[method(name = "call")]
365    async fn call(
366        &self,
367        request: TxReq,
368        block_id: Option<BlockId>,
369        state_overrides: Option<StateOverride>,
370        block_overrides: Option<Box<BlockOverrides>>,
371    ) -> RpcResult<Bytes>;
372
373    /// Returns code at a given address at given block number.
374    #[method(name = "getCode")]
375    async fn get_code(&self, address: Address, block_id: Option<BlockId>) -> RpcResult<Bytes>;
376
377    /// Returns information about a block by hash.
378    #[method(name = "getBlockByHash")]
379    async fn block_by_hash(&self, hash: B256, full: bool) -> RpcResult<Option<B>>;
380
381    /// Returns information about a block by number.
382    #[method(name = "getBlockByNumber")]
383    async fn block_by_number(&self, number: BlockNumberOrTag, full: bool) -> RpcResult<Option<B>>;
384
385    /// Returns all transaction receipts for a given block.
386    #[method(name = "getBlockReceipts")]
387    async fn block_receipts(&self, block_id: BlockId) -> RpcResult<Option<Vec<R>>>;
388
389    /// Sends signed transaction, returning its hash.
390    #[method(name = "sendRawTransaction")]
391    async fn send_raw_transaction(&self, bytes: Bytes) -> RpcResult<B256>;
392
393    /// Returns the receipt of a transaction by transaction hash.
394    #[method(name = "getTransactionReceipt")]
395    async fn transaction_receipt(&self, hash: B256) -> RpcResult<Option<R>>;
396
397    /// Returns logs matching given filter object.
398    #[method(name = "getLogs")]
399    async fn logs(&self, filter: Filter) -> RpcResult<Vec<Log>>;
400
401    /// Returns the account and storage values of the specified account including the Merkle-proof.
402    /// This call can be used to verify that the data you are pulling from is not tampered with.
403    #[method(name = "getProof")]
404    async fn get_proof(
405        &self,
406        address: Address,
407        keys: Vec<JsonStorageKey>,
408        block_number: Option<BlockId>,
409    ) -> RpcResult<EIP1186AccountProofResponse>;
410
411    /// Returns the EIP-7928 block access list for a block by hash.
412    #[method(name = "getBlockAccessListByBlockHash")]
413    async fn block_access_list_by_block_hash(&self, hash: B256) -> RpcResult<Option<Value>>;
414
415    /// Returns the EIP-7928 block access list for a block by number.
416    #[method(name = "getBlockAccessListByBlockNumber")]
417    async fn block_access_list_by_block_number(
418        &self,
419        number: BlockNumberOrTag,
420    ) -> RpcResult<Option<Value>>;
421
422    /// Returns the EIP-7928 block access list for a block by block id.
423    #[method(name = "getBlockAccessList")]
424    async fn block_access_list(&self, block_id: BlockId) -> RpcResult<Option<Value>>;
425
426    /// Returns the EIP-7928 block access list bytes for a block by number.
427    #[method(name = "getBlockAccessListRaw")]
428    async fn block_access_list_raw(&self, block: BlockId) -> RpcResult<Option<Bytes>>;
429}