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},
8    eip7685::RequestsOrHash,
9    BlockId, BlockNumberOrTag,
10};
11use alloy_json_rpc::RpcObject;
12use alloy_primitives::{Address, BlockHash, Bytes, 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;
24
25/// Helper trait for the engine api server.
26///
27/// This type-erases the concrete [`jsonrpsee`] server implementation and only returns the
28/// [`RpcModule`] that contains all the endpoints of the server.
29pub trait IntoEngineApiRpcModule {
30    /// Consumes the type and returns all the methods and subscriptions defined in the trait and
31    /// returns them as a single [`RpcModule`]
32    fn into_rpc_module(self) -> RpcModule<()>;
33}
34
35// NOTE: We can't use associated types in the `EngineApi` trait because of jsonrpsee, so we use a
36// generic here. It would be nice if the rpc macro would understand which types need to have serde.
37// By default, if the trait has a generic, the rpc macro will add e.g. `Engine: DeserializeOwned` to
38// the trait bounds, which is not what we want, because `Types` is not used directly in any of the
39// trait methods. Instead, we have to add the bounds manually. This would be disastrous if we had
40// more than one associated type used in the trait methods.
41
42#[cfg_attr(not(feature = "client"), rpc(server, namespace = "engine"), server_bounds(Engine::PayloadAttributes: jsonrpsee::core::DeserializeOwned))]
43#[cfg_attr(feature = "client", rpc(server, client, namespace = "engine", client_bounds(Engine::PayloadAttributes: jsonrpsee::core::Serialize + Clone), server_bounds(Engine::PayloadAttributes: jsonrpsee::core::DeserializeOwned)))]
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    /// See also <https://github.com/ethereum/execution-apis/blob/6709c2a795b707202e93c4f2867fa0bf2640a84f/src/engine/paris.md#engine_forkchoiceupdatedv1>
90    ///
91    /// Caution: This should not accept the `withdrawals` field in the payload attributes.
92    #[method(name = "forkchoiceUpdatedV1")]
93    async fn fork_choice_updated_v1(
94        &self,
95        fork_choice_state: ForkchoiceState,
96        payload_attributes: Option<Engine::PayloadAttributes>,
97    ) -> RpcResult<ForkchoiceUpdated>;
98
99    /// Post Shanghai forkchoice update handler
100    ///
101    /// This is the same as `forkchoiceUpdatedV1`, but expects an additional `withdrawals` field in
102    /// the `payloadAttributes`, if payload attributes are provided.
103    ///
104    /// See also <https://github.com/ethereum/execution-apis/blob/6709c2a795b707202e93c4f2867fa0bf2640a84f/src/engine/shanghai.md#engine_forkchoiceupdatedv2>
105    ///
106    /// Caution: This should not accept the `parentBeaconBlockRoot` field in the payload
107    /// attributes.
108    #[method(name = "forkchoiceUpdatedV2")]
109    async fn fork_choice_updated_v2(
110        &self,
111        fork_choice_state: ForkchoiceState,
112        payload_attributes: Option<Engine::PayloadAttributes>,
113    ) -> RpcResult<ForkchoiceUpdated>;
114
115    /// Post Cancun forkchoice update handler
116    ///
117    /// This is the same as `forkchoiceUpdatedV2`, but expects an additional
118    /// `parentBeaconBlockRoot` field in the `payloadAttributes`, if payload attributes
119    /// are provided.
120    ///
121    /// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/cancun.md#engine_forkchoiceupdatedv3>
122    #[method(name = "forkchoiceUpdatedV3")]
123    async fn fork_choice_updated_v3(
124        &self,
125        fork_choice_state: ForkchoiceState,
126        payload_attributes: Option<Engine::PayloadAttributes>,
127    ) -> RpcResult<ForkchoiceUpdated>;
128
129    /// Post Amsterdam forkchoice update handler
130    ///
131    /// This is the same as `forkchoiceUpdatedV3`, but expects an additional
132    /// `slotNumber` field in the `payloadAttributes`, if payload attributes
133    /// are provided.
134    ///
135    /// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/amsterdam.md#engine_forkchoiceupdatedv4>
136    #[method(name = "forkchoiceUpdatedV4")]
137    async fn fork_choice_updated_v4(
138        &self,
139        fork_choice_state: ForkchoiceState,
140        payload_attributes: Option<Engine::PayloadAttributes>,
141    ) -> RpcResult<ForkchoiceUpdated>;
142
143    /// See also <https://github.com/ethereum/execution-apis/blob/6709c2a795b707202e93c4f2867fa0bf2640a84f/src/engine/paris.md#engine_getpayloadv1>
144    ///
145    /// Returns the most recent version of the payload that is available in the corresponding
146    /// payload build process at the time of receiving this call.
147    ///
148    /// Caution: This should not return the `withdrawals` field
149    ///
150    /// Note:
151    /// > Provider software MAY stop the corresponding build process after serving this call.
152    #[method(name = "getPayloadV1")]
153    async fn get_payload_v1(
154        &self,
155        payload_id: PayloadId,
156    ) -> RpcResult<Engine::ExecutionPayloadEnvelopeV1>;
157
158    /// See also <https://github.com/ethereum/execution-apis/blob/6709c2a795b707202e93c4f2867fa0bf2640a84f/src/engine/shanghai.md#engine_getpayloadv2>
159    ///
160    /// Returns the most recent version of the payload that is available in the corresponding
161    /// payload build process at the time of receiving this call. Note:
162    /// > Provider software MAY stop the corresponding build process after serving this call.
163    #[method(name = "getPayloadV2")]
164    async fn get_payload_v2(
165        &self,
166        payload_id: PayloadId,
167    ) -> RpcResult<Engine::ExecutionPayloadEnvelopeV2>;
168
169    /// Post Cancun payload handler which also returns a blobs bundle.
170    ///
171    /// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/cancun.md#engine_getpayloadv3>
172    ///
173    /// Returns the most recent version of the payload that is available in the corresponding
174    /// payload build process at the time of receiving this call. Note:
175    /// > Provider software MAY stop the corresponding build process after serving this call.
176    #[method(name = "getPayloadV3")]
177    async fn get_payload_v3(
178        &self,
179        payload_id: PayloadId,
180    ) -> RpcResult<Engine::ExecutionPayloadEnvelopeV3>;
181
182    /// Post Prague payload handler.
183    ///
184    /// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/prague.md#engine_getpayloadv4>
185    ///
186    /// Returns the most recent version of the payload that is available in the corresponding
187    /// payload build process at the time of receiving this call. Note:
188    /// > Provider software MAY stop the corresponding build process after serving this call.
189    #[method(name = "getPayloadV4")]
190    async fn get_payload_v4(
191        &self,
192        payload_id: PayloadId,
193    ) -> RpcResult<Engine::ExecutionPayloadEnvelopeV4>;
194
195    /// Post Osaka payload handler.
196    ///
197    /// See also <https://github.com/ethereum/execution-apis/blob/15399c2e2f16a5f800bf3f285640357e2c245ad9/src/engine/osaka.md#engine_getpayloadv5>.
198    ///
199    /// Returns the most recent version of the payload that is available in the corresponding
200    /// payload build process at the time of receiving this call. Note:
201    /// > Provider software MAY stop the corresponding build process after serving this call.
202    #[method(name = "getPayloadV5")]
203    async fn get_payload_v5(
204        &self,
205        payload_id: PayloadId,
206    ) -> RpcResult<Engine::ExecutionPayloadEnvelopeV5>;
207
208    /// Post Amsterdam payload handler.
209    ///
210    /// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/amsterdam.md#engine_getpayloadv6>
211    ///
212    /// Returns the most recent version of the payload that is available in the corresponding
213    /// payload build process at the time of receiving this call. Note:
214    /// > Provider software MAY stop the corresponding build process after serving this call.
215    #[method(name = "getPayloadV6")]
216    async fn get_payload_v6(
217        &self,
218        payload_id: PayloadId,
219    ) -> RpcResult<Engine::ExecutionPayloadEnvelopeV6>;
220
221    /// See also <https://github.com/ethereum/execution-apis/blob/6452a6b194d7db269bf1dbd087a267251d3cc7f8/src/engine/shanghai.md#engine_getpayloadbodiesbyhashv1>
222    #[method(name = "getPayloadBodiesByHashV1")]
223    async fn get_payload_bodies_by_hash_v1(
224        &self,
225        block_hashes: Vec<BlockHash>,
226    ) -> RpcResult<ExecutionPayloadBodiesV1>;
227
228    /// Returns `ExecutionPayloadBodyV2` objects for the given block hashes.
229    ///
230    /// V2 includes the `block_access_list` field for EIP-7928 BAL support.
231    ///
232    /// See also <https://eips.ethereum.org/EIPS/eip-7928>
233    #[method(name = "getPayloadBodiesByHashV2")]
234    async fn get_payload_bodies_by_hash_v2(
235        &self,
236        block_hashes: Vec<BlockHash>,
237    ) -> RpcResult<ExecutionPayloadBodiesV2>;
238
239    /// See also <https://github.com/ethereum/execution-apis/blob/6452a6b194d7db269bf1dbd087a267251d3cc7f8/src/engine/shanghai.md#engine_getpayloadbodiesbyrangev1>
240    ///
241    /// Returns the execution payload bodies by the range starting at `start`, containing `count`
242    /// blocks.
243    ///
244    /// WARNING: This method is associated with the `BeaconBlocksByRange` message in the consensus
245    /// layer p2p specification, meaning the input should be treated as untrusted or potentially
246    /// adversarial.
247    ///
248    /// Implementers should take care when acting on the input to this method, specifically
249    /// ensuring that the range is limited properly, and that the range boundaries are computed
250    /// correctly and without panics.
251    #[method(name = "getPayloadBodiesByRangeV1")]
252    async fn get_payload_bodies_by_range_v1(
253        &self,
254        start: U64,
255        count: U64,
256    ) -> RpcResult<ExecutionPayloadBodiesV1>;
257
258    /// Returns `ExecutionPayloadBodyV2` objects for the given block range.
259    ///
260    /// V2 includes the `block_access_list` field for EIP-7928 BAL support.
261    ///
262    /// WARNING: This method is associated with the `BeaconBlocksByRange` message in the consensus
263    /// layer p2p specification, meaning the input should be treated as untrusted or potentially
264    /// adversarial.
265    ///
266    /// Implementers should take care when acting on the input to this method, specifically
267    /// ensuring that the range is limited properly, and that the range boundaries are computed
268    /// correctly and without panics.
269    ///
270    /// See also <https://eips.ethereum.org/EIPS/eip-7928>
271    #[method(name = "getPayloadBodiesByRangeV2")]
272    async fn get_payload_bodies_by_range_v2(
273        &self,
274        start: U64,
275        count: U64,
276    ) -> RpcResult<ExecutionPayloadBodiesV2>;
277
278    /// This function will return the [`ClientVersionV1`] object.
279    /// See also:
280    /// <https://github.com/ethereum/execution-apis/blob/03911ffc053b8b806123f1fc237184b0092a485a/src/engine/identification.md#engine_getclientversionv1>
281    ///
282    ///
283    /// - When connected to a single execution client, the consensus client **MUST** receive an
284    ///   array with a single `ClientVersionV1` object.
285    /// - When connected to multiple execution clients via a multiplexer, the multiplexer **MUST**
286    ///   concatenate the responses from each execution client into a single,
287    /// flat array before returning the response to the consensus client.
288    #[method(name = "getClientVersionV1")]
289    async fn get_client_version_v1(
290        &self,
291        client_version: ClientVersionV1,
292    ) -> RpcResult<Vec<ClientVersionV1>>;
293
294    /// See also <https://github.com/ethereum/execution-apis/blob/6452a6b194d7db269bf1dbd087a267251d3cc7f8/src/engine/common.md#capabilities>
295    #[method(name = "exchangeCapabilities")]
296    async fn exchange_capabilities(&self, capabilities: Vec<String>) -> RpcResult<Vec<String>>;
297
298    /// Fetch blobs for the consensus layer from the blob store.
299    #[method(name = "getBlobsV1")]
300    async fn get_blobs_v1(
301        &self,
302        versioned_hashes: Vec<B256>,
303    ) -> RpcResult<Vec<Option<BlobAndProofV1>>>;
304
305    /// Fetch blobs for the consensus layer from the blob store.
306    ///
307    /// Returns a response only if blobs and proofs are present for _all_ of the versioned hashes:
308    ///     2. Client software MUST return null in case of any missing or older version blobs.
309    #[method(name = "getBlobsV2")]
310    async fn get_blobs_v2(
311        &self,
312        versioned_hashes: Vec<B256>,
313    ) -> RpcResult<Option<Vec<BlobAndProofV2>>>;
314
315    /// Fetch blobs for the consensus layer from the blob store.
316    ///
317    /// Returns a response of the same length as the request. Missing or older-version blobs are
318    /// returned as `null` elements.
319    ///
320    /// Returns `null` if syncing.
321    #[method(name = "getBlobsV3")]
322    async fn get_blobs_v3(
323        &self,
324        versioned_hashes: Vec<B256>,
325    ) -> RpcResult<Option<Vec<Option<BlobAndProofV2>>>>;
326}
327
328/// A subset of the ETH rpc interface: <https://ethereum.github.io/execution-apis/api-documentation>
329///
330/// This also includes additional eth functions required by optimism.
331///
332/// Specifically for the engine auth server: <https://github.com/ethereum/execution-apis/blob/main/src/engine/common.md#underlying-protocol>
333#[cfg_attr(not(feature = "client"), rpc(server, namespace = "eth"))]
334#[cfg_attr(feature = "client", rpc(server, client, namespace = "eth"))]
335pub trait EngineEthApi<TxReq: RpcObject, B: RpcObject, R: RpcObject> {
336    /// Returns an object with data about the sync status or false.
337    #[method(name = "syncing")]
338    fn syncing(&self) -> RpcResult<SyncStatus>;
339
340    /// Returns the chain ID of the current network.
341    #[method(name = "chainId")]
342    async fn chain_id(&self) -> RpcResult<Option<U64>>;
343
344    /// Returns the number of most recent block.
345    #[method(name = "blockNumber")]
346    fn block_number(&self) -> RpcResult<U256>;
347
348    /// Executes a new message call immediately without creating a transaction on the block chain.
349    #[method(name = "call")]
350    async fn call(
351        &self,
352        request: TxReq,
353        block_id: Option<BlockId>,
354        state_overrides: Option<StateOverride>,
355        block_overrides: Option<Box<BlockOverrides>>,
356    ) -> RpcResult<Bytes>;
357
358    /// Returns code at a given address at given block number.
359    #[method(name = "getCode")]
360    async fn get_code(&self, address: Address, block_id: Option<BlockId>) -> RpcResult<Bytes>;
361
362    /// Returns information about a block by hash.
363    #[method(name = "getBlockByHash")]
364    async fn block_by_hash(&self, hash: B256, full: bool) -> RpcResult<Option<B>>;
365
366    /// Returns information about a block by number.
367    #[method(name = "getBlockByNumber")]
368    async fn block_by_number(&self, number: BlockNumberOrTag, full: bool) -> RpcResult<Option<B>>;
369
370    /// Returns all transaction receipts for a given block.
371    #[method(name = "getBlockReceipts")]
372    async fn block_receipts(&self, block_id: BlockId) -> RpcResult<Option<Vec<R>>>;
373
374    /// Sends signed transaction, returning its hash.
375    #[method(name = "sendRawTransaction")]
376    async fn send_raw_transaction(&self, bytes: Bytes) -> RpcResult<B256>;
377
378    /// Returns the receipt of a transaction by transaction hash.
379    #[method(name = "getTransactionReceipt")]
380    async fn transaction_receipt(&self, hash: B256) -> RpcResult<Option<R>>;
381
382    /// Returns logs matching given filter object.
383    #[method(name = "getLogs")]
384    async fn logs(&self, filter: Filter) -> RpcResult<Vec<Log>>;
385
386    /// Returns the account and storage values of the specified account including the Merkle-proof.
387    /// This call can be used to verify that the data you are pulling from is not tampered with.
388    #[method(name = "getProof")]
389    async fn get_proof(
390        &self,
391        address: Address,
392        keys: Vec<JsonStorageKey>,
393        block_number: Option<BlockId>,
394    ) -> RpcResult<EIP1186AccountProofResponse>;
395}