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, ExecutionPayloadInputV2, ExecutionPayloadV1,
15    ExecutionPayloadV3, ForkchoiceState, ForkchoiceUpdated, PayloadId, PayloadStatus,
16};
17use alloy_rpc_types_eth::{
18    state::StateOverride, BlockOverrides, EIP1186AccountProofResponse, Filter, Log, SyncStatus,
19};
20use alloy_serde::JsonStorageKey;
21use jsonrpsee::{core::RpcResult, proc_macros::rpc, RpcModule};
22use reth_engine_primitives::EngineTypes;
23
24/// Helper trait for the engine api server.
25///
26/// This type-erases the concrete [`jsonrpsee`] server implementation and only returns the
27/// [`RpcModule`] that contains all the endpoints of the server.
28pub trait IntoEngineApiRpcModule {
29    /// Consumes the type and returns all the methods and subscriptions defined in the trait and
30    /// returns them as a single [`RpcModule`]
31    fn into_rpc_module(self) -> RpcModule<()>;
32}
33
34// NOTE: We can't use associated types in the `EngineApi` trait because of jsonrpsee, so we use a
35// generic here. It would be nice if the rpc macro would understand which types need to have serde.
36// By default, if the trait has a generic, the rpc macro will add e.g. `Engine: DeserializeOwned` to
37// the trait bounds, which is not what we want, because `Types` is not used directly in any of the
38// trait methods. Instead, we have to add the bounds manually. This would be disastrous if we had
39// more than one associated type used in the trait methods.
40
41#[cfg_attr(not(feature = "client"), rpc(server, namespace = "engine"), server_bounds(Engine::PayloadAttributes: jsonrpsee::core::DeserializeOwned))]
42#[cfg_attr(feature = "client", rpc(server, client, namespace = "engine", client_bounds(Engine::PayloadAttributes: jsonrpsee::core::Serialize + Clone), server_bounds(Engine::PayloadAttributes: jsonrpsee::core::DeserializeOwned)))]
43pub trait EngineApi<Engine: EngineTypes> {
44    /// See also <https://github.com/ethereum/execution-apis/blob/6709c2a795b707202e93c4f2867fa0bf2640a84f/src/engine/paris.md#engine_newpayloadv1>
45    /// Caution: This should not accept the `withdrawals` field
46    #[method(name = "newPayloadV1")]
47    async fn new_payload_v1(&self, payload: ExecutionPayloadV1) -> RpcResult<PayloadStatus>;
48
49    /// See also <https://github.com/ethereum/execution-apis/blob/584905270d8ad665718058060267061ecfd79ca5/src/engine/shanghai.md#engine_newpayloadv2>
50    #[method(name = "newPayloadV2")]
51    async fn new_payload_v2(&self, payload: ExecutionPayloadInputV2) -> RpcResult<PayloadStatus>;
52
53    /// Post Cancun payload handler
54    ///
55    /// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/cancun.md#engine_newpayloadv3>
56    #[method(name = "newPayloadV3")]
57    async fn new_payload_v3(
58        &self,
59        payload: ExecutionPayloadV3,
60        versioned_hashes: Vec<B256>,
61        parent_beacon_block_root: B256,
62    ) -> RpcResult<PayloadStatus>;
63
64    /// Post Prague payload handler
65    ///
66    /// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/prague.md#engine_newpayloadv4>
67    #[method(name = "newPayloadV4")]
68    async fn new_payload_v4(
69        &self,
70        payload: ExecutionPayloadV3,
71        versioned_hashes: Vec<B256>,
72        parent_beacon_block_root: B256,
73        execution_requests: RequestsOrHash,
74    ) -> RpcResult<PayloadStatus>;
75
76    /// See also <https://github.com/ethereum/execution-apis/blob/6709c2a795b707202e93c4f2867fa0bf2640a84f/src/engine/paris.md#engine_forkchoiceupdatedv1>
77    ///
78    /// Caution: This should not accept the `withdrawals` field in the payload attributes.
79    #[method(name = "forkchoiceUpdatedV1")]
80    async fn fork_choice_updated_v1(
81        &self,
82        fork_choice_state: ForkchoiceState,
83        payload_attributes: Option<Engine::PayloadAttributes>,
84    ) -> RpcResult<ForkchoiceUpdated>;
85
86    /// Post Shanghai forkchoice update handler
87    ///
88    /// This is the same as `forkchoiceUpdatedV1`, but expects an additional `withdrawals` field in
89    /// the `payloadAttributes`, if payload attributes are provided.
90    ///
91    /// See also <https://github.com/ethereum/execution-apis/blob/6709c2a795b707202e93c4f2867fa0bf2640a84f/src/engine/shanghai.md#engine_forkchoiceupdatedv2>
92    ///
93    /// Caution: This should not accept the `parentBeaconBlockRoot` field in the payload
94    /// attributes.
95    #[method(name = "forkchoiceUpdatedV2")]
96    async fn fork_choice_updated_v2(
97        &self,
98        fork_choice_state: ForkchoiceState,
99        payload_attributes: Option<Engine::PayloadAttributes>,
100    ) -> RpcResult<ForkchoiceUpdated>;
101
102    /// Post Cancun forkchoice update handler
103    ///
104    /// This is the same as `forkchoiceUpdatedV2`, but expects an additional
105    /// `parentBeaconBlockRoot` field in the `payloadAttributes`, if payload attributes
106    /// are provided.
107    ///
108    /// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/cancun.md#engine_forkchoiceupdatedv3>
109    #[method(name = "forkchoiceUpdatedV3")]
110    async fn fork_choice_updated_v3(
111        &self,
112        fork_choice_state: ForkchoiceState,
113        payload_attributes: Option<Engine::PayloadAttributes>,
114    ) -> RpcResult<ForkchoiceUpdated>;
115
116    /// See also <https://github.com/ethereum/execution-apis/blob/6709c2a795b707202e93c4f2867fa0bf2640a84f/src/engine/paris.md#engine_getpayloadv1>
117    ///
118    /// Returns the most recent version of the payload that is available in the corresponding
119    /// payload build process at the time of receiving this call.
120    ///
121    /// Caution: This should not return the `withdrawals` field
122    ///
123    /// Note:
124    /// > Provider software MAY stop the corresponding build process after serving this call.
125    #[method(name = "getPayloadV1")]
126    async fn get_payload_v1(
127        &self,
128        payload_id: PayloadId,
129    ) -> RpcResult<Engine::ExecutionPayloadEnvelopeV1>;
130
131    /// See also <https://github.com/ethereum/execution-apis/blob/6709c2a795b707202e93c4f2867fa0bf2640a84f/src/engine/shanghai.md#engine_getpayloadv2>
132    ///
133    /// Returns the most recent version of the payload that is available in the corresponding
134    /// payload build process at the time of receiving this call. Note:
135    /// > Provider software MAY stop the corresponding build process after serving this call.
136    #[method(name = "getPayloadV2")]
137    async fn get_payload_v2(
138        &self,
139        payload_id: PayloadId,
140    ) -> RpcResult<Engine::ExecutionPayloadEnvelopeV2>;
141
142    /// Post Cancun payload handler which also returns a blobs bundle.
143    ///
144    /// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/cancun.md#engine_getpayloadv3>
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. Note:
148    /// > Provider software MAY stop the corresponding build process after serving this call.
149    #[method(name = "getPayloadV3")]
150    async fn get_payload_v3(
151        &self,
152        payload_id: PayloadId,
153    ) -> RpcResult<Engine::ExecutionPayloadEnvelopeV3>;
154
155    /// Post Prague payload handler.
156    ///
157    /// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/prague.md#engine_getpayloadv4>
158    ///
159    /// Returns the most recent version of the payload that is available in the corresponding
160    /// payload build process at the time of receiving this call. Note:
161    /// > Provider software MAY stop the corresponding build process after serving this call.
162    #[method(name = "getPayloadV4")]
163    async fn get_payload_v4(
164        &self,
165        payload_id: PayloadId,
166    ) -> RpcResult<Engine::ExecutionPayloadEnvelopeV4>;
167
168    /// Post Osaka payload handler.
169    ///
170    /// See also <https://github.com/ethereum/execution-apis/blob/15399c2e2f16a5f800bf3f285640357e2c245ad9/src/engine/osaka.md#engine_getpayloadv5>.
171    ///
172    /// Returns the most recent version of the payload that is available in the corresponding
173    /// payload build process at the time of receiving this call. Note:
174    /// > Provider software MAY stop the corresponding build process after serving this call.
175    #[method(name = "getPayloadV5")]
176    async fn get_payload_v5(
177        &self,
178        payload_id: PayloadId,
179    ) -> RpcResult<Engine::ExecutionPayloadEnvelopeV5>;
180
181    /// See also <https://github.com/ethereum/execution-apis/blob/6452a6b194d7db269bf1dbd087a267251d3cc7f8/src/engine/shanghai.md#engine_getpayloadbodiesbyhashv1>
182    #[method(name = "getPayloadBodiesByHashV1")]
183    async fn get_payload_bodies_by_hash_v1(
184        &self,
185        block_hashes: Vec<BlockHash>,
186    ) -> RpcResult<ExecutionPayloadBodiesV1>;
187
188    /// See also <https://github.com/ethereum/execution-apis/blob/6452a6b194d7db269bf1dbd087a267251d3cc7f8/src/engine/shanghai.md#engine_getpayloadbodiesbyrangev1>
189    ///
190    /// Returns the execution payload bodies by the range starting at `start`, containing `count`
191    /// blocks.
192    ///
193    /// WARNING: This method is associated with the `BeaconBlocksByRange` message in the consensus
194    /// layer p2p specification, meaning the input should be treated as untrusted or potentially
195    /// adversarial.
196    ///
197    /// Implementers should take care when acting on the input to this method, specifically
198    /// ensuring that the range is limited properly, and that the range boundaries are computed
199    /// correctly and without panics.
200    #[method(name = "getPayloadBodiesByRangeV1")]
201    async fn get_payload_bodies_by_range_v1(
202        &self,
203        start: U64,
204        count: U64,
205    ) -> RpcResult<ExecutionPayloadBodiesV1>;
206
207    /// This function will return the [`ClientVersionV1`] object.
208    /// See also:
209    /// <https://github.com/ethereum/execution-apis/blob/03911ffc053b8b806123f1fc237184b0092a485a/src/engine/identification.md#engine_getclientversionv1>
210    ///
211    ///
212    /// - When connected to a single execution client, the consensus client **MUST** receive an
213    ///   array with a single `ClientVersionV1` object.
214    /// - When connected to multiple execution clients via a multiplexer, the multiplexer **MUST**
215    ///   concatenate the responses from each execution client into a single,
216    /// flat array before returning the response to the consensus client.
217    #[method(name = "getClientVersionV1")]
218    async fn get_client_version_v1(
219        &self,
220        client_version: ClientVersionV1,
221    ) -> RpcResult<Vec<ClientVersionV1>>;
222
223    /// See also <https://github.com/ethereum/execution-apis/blob/6452a6b194d7db269bf1dbd087a267251d3cc7f8/src/engine/common.md#capabilities>
224    #[method(name = "exchangeCapabilities")]
225    async fn exchange_capabilities(&self, capabilities: Vec<String>) -> RpcResult<Vec<String>>;
226
227    /// Fetch blobs for the consensus layer from the blob store.
228    #[method(name = "getBlobsV1")]
229    async fn get_blobs_v1(
230        &self,
231        versioned_hashes: Vec<B256>,
232    ) -> RpcResult<Vec<Option<BlobAndProofV1>>>;
233
234    /// Fetch blobs for the consensus layer from the blob store.
235    ///
236    /// Returns a response only if blobs and proofs are present for _all_ of the versioned hashes:
237    ///     2. Client software MUST return null in case of any missing or older version blobs.
238    #[method(name = "getBlobsV2")]
239    async fn get_blobs_v2(
240        &self,
241        versioned_hashes: Vec<B256>,
242    ) -> RpcResult<Option<Vec<BlobAndProofV2>>>;
243}
244
245/// A subset of the ETH rpc interface: <https://ethereum.github.io/execution-apis/api-documentation>
246///
247/// This also includes additional eth functions required by optimism.
248///
249/// Specifically for the engine auth server: <https://github.com/ethereum/execution-apis/blob/main/src/engine/common.md#underlying-protocol>
250#[cfg_attr(not(feature = "client"), rpc(server, namespace = "eth"))]
251#[cfg_attr(feature = "client", rpc(server, client, namespace = "eth"))]
252pub trait EngineEthApi<TxReq: RpcObject, B: RpcObject, R: RpcObject> {
253    /// Returns an object with data about the sync status or false.
254    #[method(name = "syncing")]
255    fn syncing(&self) -> RpcResult<SyncStatus>;
256
257    /// Returns the chain ID of the current network.
258    #[method(name = "chainId")]
259    async fn chain_id(&self) -> RpcResult<Option<U64>>;
260
261    /// Returns the number of most recent block.
262    #[method(name = "blockNumber")]
263    fn block_number(&self) -> RpcResult<U256>;
264
265    /// Executes a new message call immediately without creating a transaction on the block chain.
266    #[method(name = "call")]
267    async fn call(
268        &self,
269        request: TxReq,
270        block_id: Option<BlockId>,
271        state_overrides: Option<StateOverride>,
272        block_overrides: Option<Box<BlockOverrides>>,
273    ) -> RpcResult<Bytes>;
274
275    /// Returns code at a given address at given block number.
276    #[method(name = "getCode")]
277    async fn get_code(&self, address: Address, block_id: Option<BlockId>) -> RpcResult<Bytes>;
278
279    /// Returns information about a block by hash.
280    #[method(name = "getBlockByHash")]
281    async fn block_by_hash(&self, hash: B256, full: bool) -> RpcResult<Option<B>>;
282
283    /// Returns information about a block by number.
284    #[method(name = "getBlockByNumber")]
285    async fn block_by_number(&self, number: BlockNumberOrTag, full: bool) -> RpcResult<Option<B>>;
286
287    /// Returns all transaction receipts for a given block.
288    #[method(name = "getBlockReceipts")]
289    async fn block_receipts(&self, block_id: BlockId) -> RpcResult<Option<Vec<R>>>;
290
291    /// Sends signed transaction, returning its hash.
292    #[method(name = "sendRawTransaction")]
293    async fn send_raw_transaction(&self, bytes: Bytes) -> RpcResult<B256>;
294
295    /// Returns the receipt of a transaction by transaction hash.
296    #[method(name = "getTransactionReceipt")]
297    async fn transaction_receipt(&self, hash: B256) -> RpcResult<Option<R>>;
298
299    /// Returns logs matching given filter object.
300    #[method(name = "getLogs")]
301    async fn logs(&self, filter: Filter) -> RpcResult<Vec<Log>>;
302
303    /// Returns the account and storage values of the specified account including the Merkle-proof.
304    /// This call can be used to verify that the data you are pulling from is not tampered with.
305    #[method(name = "getProof")]
306    async fn get_proof(
307        &self,
308        address: Address,
309        keys: Vec<JsonStorageKey>,
310        block_number: Option<BlockId>,
311    ) -> RpcResult<EIP1186AccountProofResponse>;
312}