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 /// `custody_columns` maps to the third positional JSON-RPC parameter, `custodyColumns`,
137 /// the custody-column bitmask used for [EIP-8070] sparse blobpool signaling. It is
138 /// `DATA|null` and must be 16 bytes when set. When calling `engine_forkchoiceUpdatedV4`
139 /// with custody columns but without payload attributes, the second parameter must still
140 /// be supplied as `null`, for example:
141 /// `[forkchoiceState, null, custodyColumns]`.
142 ///
143 /// [EIP-8070]: https://eips.ethereum.org/EIPS/eip-8070
144 ///
145 /// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/amsterdam.md#engine_forkchoiceupdatedv4>
146 #[method(name = "forkchoiceUpdatedV4")]
147 async fn fork_choice_updated_v4(
148 &self,
149 fork_choice_state: ForkchoiceState,
150 payload_attributes: Option<Engine::PayloadAttributes>,
151 custody_columns: Option<B128>,
152 ) -> RpcResult<ForkchoiceUpdated>;
153
154 /// See also <https://github.com/ethereum/execution-apis/blob/6709c2a795b707202e93c4f2867fa0bf2640a84f/src/engine/paris.md#engine_getpayloadv1>
155 ///
156 /// Returns the most recent version of the payload that is available in the corresponding
157 /// payload build process at the time of receiving this call.
158 ///
159 /// Caution: This should not return the `withdrawals` field
160 ///
161 /// Note:
162 /// > Provider software MAY stop the corresponding build process after serving this call.
163 #[method(name = "getPayloadV1")]
164 async fn get_payload_v1(
165 &self,
166 payload_id: PayloadId,
167 ) -> RpcResult<Engine::ExecutionPayloadEnvelopeV1>;
168
169 /// See also <https://github.com/ethereum/execution-apis/blob/6709c2a795b707202e93c4f2867fa0bf2640a84f/src/engine/shanghai.md#engine_getpayloadv2>
170 ///
171 /// Returns the most recent version of the payload that is available in the corresponding
172 /// payload build process at the time of receiving this call. Note:
173 /// > Provider software MAY stop the corresponding build process after serving this call.
174 #[method(name = "getPayloadV2")]
175 async fn get_payload_v2(
176 &self,
177 payload_id: PayloadId,
178 ) -> RpcResult<Engine::ExecutionPayloadEnvelopeV2>;
179
180 /// Post Cancun payload handler which also returns a blobs bundle.
181 ///
182 /// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/cancun.md#engine_getpayloadv3>
183 ///
184 /// Returns the most recent version of the payload that is available in the corresponding
185 /// payload build process at the time of receiving this call. Note:
186 /// > Provider software MAY stop the corresponding build process after serving this call.
187 #[method(name = "getPayloadV3")]
188 async fn get_payload_v3(
189 &self,
190 payload_id: PayloadId,
191 ) -> RpcResult<Engine::ExecutionPayloadEnvelopeV3>;
192
193 /// Post Prague payload handler.
194 ///
195 /// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/prague.md#engine_getpayloadv4>
196 ///
197 /// Returns the most recent version of the payload that is available in the corresponding
198 /// payload build process at the time of receiving this call. Note:
199 /// > Provider software MAY stop the corresponding build process after serving this call.
200 #[method(name = "getPayloadV4")]
201 async fn get_payload_v4(
202 &self,
203 payload_id: PayloadId,
204 ) -> RpcResult<Engine::ExecutionPayloadEnvelopeV4>;
205
206 /// Post Osaka payload handler.
207 ///
208 /// See also <https://github.com/ethereum/execution-apis/blob/15399c2e2f16a5f800bf3f285640357e2c245ad9/src/engine/osaka.md#engine_getpayloadv5>.
209 ///
210 /// Returns the most recent version of the payload that is available in the corresponding
211 /// payload build process at the time of receiving this call. Note:
212 /// > Provider software MAY stop the corresponding build process after serving this call.
213 #[method(name = "getPayloadV5")]
214 async fn get_payload_v5(
215 &self,
216 payload_id: PayloadId,
217 ) -> RpcResult<Engine::ExecutionPayloadEnvelopeV5>;
218
219 /// Post Amsterdam payload handler.
220 ///
221 /// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/amsterdam.md#engine_getpayloadv6>
222 ///
223 /// Returns the most recent version of the payload that is available in the corresponding
224 /// payload build process at the time of receiving this call. Note:
225 /// > Provider software MAY stop the corresponding build process after serving this call.
226 #[method(name = "getPayloadV6")]
227 async fn get_payload_v6(
228 &self,
229 payload_id: PayloadId,
230 ) -> RpcResult<Engine::ExecutionPayloadEnvelopeV6>;
231
232 /// See also <https://github.com/ethereum/execution-apis/blob/6452a6b194d7db269bf1dbd087a267251d3cc7f8/src/engine/shanghai.md#engine_getpayloadbodiesbyhashv1>
233 #[method(name = "getPayloadBodiesByHashV1")]
234 async fn get_payload_bodies_by_hash_v1(
235 &self,
236 block_hashes: Vec<BlockHash>,
237 ) -> RpcResult<ExecutionPayloadBodiesV1>;
238
239 /// Returns `ExecutionPayloadBodyV2` objects for the given block hashes.
240 ///
241 /// V2 includes the `block_access_list` field for EIP-7928 BAL support.
242 ///
243 /// See also <https://eips.ethereum.org/EIPS/eip-7928>
244 #[method(name = "getPayloadBodiesByHashV2")]
245 async fn get_payload_bodies_by_hash_v2(
246 &self,
247 block_hashes: Vec<BlockHash>,
248 ) -> RpcResult<ExecutionPayloadBodiesV2>;
249
250 /// See also <https://github.com/ethereum/execution-apis/blob/6452a6b194d7db269bf1dbd087a267251d3cc7f8/src/engine/shanghai.md#engine_getpayloadbodiesbyrangev1>
251 ///
252 /// Returns the execution payload bodies by the range starting at `start`, containing `count`
253 /// blocks.
254 ///
255 /// WARNING: This method is associated with the `BeaconBlocksByRange` message in the consensus
256 /// layer p2p specification, meaning the input should be treated as untrusted or potentially
257 /// adversarial.
258 ///
259 /// Implementers should take care when acting on the input to this method, specifically
260 /// ensuring that the range is limited properly, and that the range boundaries are computed
261 /// correctly and without panics.
262 #[method(name = "getPayloadBodiesByRangeV1")]
263 async fn get_payload_bodies_by_range_v1(
264 &self,
265 start: U64,
266 count: U64,
267 ) -> RpcResult<ExecutionPayloadBodiesV1>;
268
269 /// Returns `ExecutionPayloadBodyV2` objects for the given block range.
270 ///
271 /// V2 includes the `block_access_list` field for EIP-7928 BAL support.
272 ///
273 /// WARNING: This method is associated with the `BeaconBlocksByRange` message in the consensus
274 /// layer p2p specification, meaning the input should be treated as untrusted or potentially
275 /// adversarial.
276 ///
277 /// Implementers should take care when acting on the input to this method, specifically
278 /// ensuring that the range is limited properly, and that the range boundaries are computed
279 /// correctly and without panics.
280 ///
281 /// See also <https://eips.ethereum.org/EIPS/eip-7928>
282 #[method(name = "getPayloadBodiesByRangeV2")]
283 async fn get_payload_bodies_by_range_v2(
284 &self,
285 start: U64,
286 count: U64,
287 ) -> RpcResult<ExecutionPayloadBodiesV2>;
288
289 /// This function will return the [`ClientVersionV1`] object.
290 /// See also:
291 /// <https://github.com/ethereum/execution-apis/blob/03911ffc053b8b806123f1fc237184b0092a485a/src/engine/identification.md#engine_getclientversionv1>
292 ///
293 ///
294 /// - When connected to a single execution client, the consensus client **MUST** receive an
295 /// array with a single `ClientVersionV1` object.
296 /// - When connected to multiple execution clients via a multiplexer, the multiplexer **MUST**
297 /// concatenate the responses from each execution client into a single,
298 /// flat array before returning the response to the consensus client.
299 #[method(name = "getClientVersionV1")]
300 async fn get_client_version_v1(
301 &self,
302 client_version: ClientVersionV1,
303 ) -> RpcResult<Vec<ClientVersionV1>>;
304
305 /// See also <https://github.com/ethereum/execution-apis/blob/6452a6b194d7db269bf1dbd087a267251d3cc7f8/src/engine/common.md#capabilities>
306 #[method(name = "exchangeCapabilities")]
307 async fn exchange_capabilities(&self, capabilities: Vec<String>) -> RpcResult<Vec<String>>;
308
309 /// Fetch blobs for the consensus layer from the blob store.
310 #[method(name = "getBlobsV1")]
311 async fn get_blobs_v1(
312 &self,
313 versioned_hashes: Vec<B256>,
314 ) -> RpcResult<Vec<Option<BlobAndProofV1>>>;
315
316 /// Fetch blobs for the consensus layer from the blob store.
317 ///
318 /// Returns a response only if blobs and proofs are present for _all_ of the versioned hashes:
319 /// 2. Client software MUST return null in case of any missing or older version blobs.
320 #[method(name = "getBlobsV2")]
321 async fn get_blobs_v2(
322 &self,
323 versioned_hashes: Vec<B256>,
324 ) -> RpcResult<Option<Vec<BlobAndProofV2>>>;
325
326 /// Fetch blobs for the consensus layer from the blob store.
327 ///
328 /// Returns a response of the same length as the request. Missing or older-version blobs are
329 /// returned as `null` elements.
330 ///
331 /// Returns `null` if syncing.
332 #[method(name = "getBlobsV3")]
333 async fn get_blobs_v3(
334 &self,
335 versioned_hashes: Vec<B256>,
336 ) -> RpcResult<Option<Vec<Option<BlobAndProofV2>>>>;
337
338 /// Fetch blob cells for the consensus layer from the blob store.
339 ///
340 /// Returns a response of the same length as the request. Missing blobs are returned as `null`
341 /// elements; missing requested cells within an available blob are returned as `null` cell and
342 /// proof entries.
343 ///
344 /// Returns `null` if syncing.
345 #[method(name = "getBlobsV4")]
346 async fn get_blobs_v4(
347 &self,
348 versioned_hashes: Vec<B256>,
349 indices_bitarray: B128,
350 ) -> RpcResult<Option<Vec<Option<BlobCellsAndProofsV1>>>>;
351}
352
353/// A subset of the ETH rpc interface: <https://ethereum.github.io/execution-apis/api-documentation>
354///
355/// This also includes additional eth functions required by optimism.
356///
357/// Specifically for the engine auth server: <https://github.com/ethereum/execution-apis/blob/main/src/engine/common.md#underlying-protocol>
358#[cfg_attr(not(feature = "client"), rpc(server, namespace = "eth"))]
359#[cfg_attr(feature = "client", rpc(server, client, namespace = "eth"))]
360pub trait EngineEthApi<TxReq: RpcObject, B: RpcObject, R: RpcObject> {
361 /// Returns an object with data about the sync status or false.
362 #[method(name = "syncing")]
363 fn syncing(&self) -> RpcResult<SyncStatus>;
364
365 /// Returns the chain ID of the current network.
366 #[method(name = "chainId")]
367 async fn chain_id(&self) -> RpcResult<Option<U64>>;
368
369 /// Returns the number of most recent block.
370 #[method(name = "blockNumber")]
371 fn block_number(&self) -> RpcResult<U256>;
372
373 /// Executes a new message call immediately without creating a transaction on the block chain.
374 #[method(name = "call")]
375 async fn call(
376 &self,
377 request: TxReq,
378 block_id: Option<BlockId>,
379 state_overrides: Option<StateOverride>,
380 block_overrides: Option<Box<BlockOverrides>>,
381 ) -> RpcResult<Bytes>;
382
383 /// Returns code at a given address at given block number.
384 #[method(name = "getCode")]
385 async fn get_code(&self, address: Address, block_id: Option<BlockId>) -> RpcResult<Bytes>;
386
387 /// Returns information about a block by hash.
388 #[method(name = "getBlockByHash")]
389 async fn block_by_hash(&self, hash: B256, full: bool) -> RpcResult<Option<B>>;
390
391 /// Returns information about a block by number.
392 #[method(name = "getBlockByNumber")]
393 async fn block_by_number(&self, number: BlockNumberOrTag, full: bool) -> RpcResult<Option<B>>;
394
395 /// Returns all transaction receipts for a given block.
396 #[method(name = "getBlockReceipts")]
397 async fn block_receipts(&self, block_id: BlockId) -> RpcResult<Option<Vec<R>>>;
398
399 /// Sends signed transaction, returning its hash.
400 #[method(name = "sendRawTransaction")]
401 async fn send_raw_transaction(&self, bytes: Bytes) -> RpcResult<B256>;
402
403 /// Returns the receipt of a transaction by transaction hash.
404 #[method(name = "getTransactionReceipt")]
405 async fn transaction_receipt(&self, hash: B256) -> RpcResult<Option<R>>;
406
407 /// Returns logs matching given filter object.
408 #[method(name = "getLogs")]
409 async fn logs(&self, filter: Filter) -> RpcResult<Vec<Log>>;
410
411 /// Returns the account and storage values of the specified account including the Merkle-proof.
412 /// This call can be used to verify that the data you are pulling from is not tampered with.
413 #[method(name = "getProof")]
414 async fn get_proof(
415 &self,
416 address: Address,
417 keys: Vec<JsonStorageKey>,
418 block_number: Option<BlockId>,
419 ) -> RpcResult<EIP1186AccountProofResponse>;
420
421 /// Returns the EIP-7928 block access list for a block by hash.
422 #[method(name = "getBlockAccessListByBlockHash")]
423 async fn block_access_list_by_block_hash(&self, hash: B256) -> RpcResult<Option<Value>>;
424
425 /// Returns the EIP-7928 block access list for a block by number.
426 #[method(name = "getBlockAccessListByBlockNumber")]
427 async fn block_access_list_by_block_number(
428 &self,
429 number: BlockNumberOrTag,
430 ) -> RpcResult<Option<Value>>;
431
432 /// Returns the EIP-7928 block access list for a block by block id.
433 #[method(name = "getBlockAccessList")]
434 async fn block_access_list(&self, block_id: BlockId) -> RpcResult<Option<Value>>;
435
436 /// Returns the EIP-7928 block access list bytes for a block by number.
437 #[method(name = "getBlockAccessListRaw")]
438 async fn block_access_list_raw(&self, block: BlockId) -> RpcResult<Option<Bytes>>;
439}