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