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::TransactionRequest;
14use alloy_rpc_types_engine::{
15 ClientVersionV1, ExecutionPayloadBodiesV1, ExecutionPayloadInputV2, ExecutionPayloadV1,
16 ExecutionPayloadV3, ForkchoiceState, ForkchoiceUpdated, 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 /// See also <https://github.com/ethereum/execution-apis/blob/6709c2a795b707202e93c4f2867fa0bf2640a84f/src/engine/paris.md#engine_forkchoiceupdatedv1>
78 ///
79 /// Caution: This should not accept the `withdrawals` field in the payload attributes.
80 #[method(name = "forkchoiceUpdatedV1")]
81 async fn fork_choice_updated_v1(
82 &self,
83 fork_choice_state: ForkchoiceState,
84 payload_attributes: Option<Engine::PayloadAttributes>,
85 ) -> RpcResult<ForkchoiceUpdated>;
86
87 /// Post Shanghai forkchoice update handler
88 ///
89 /// This is the same as `forkchoiceUpdatedV1`, but expects an additional `withdrawals` field in
90 /// the `payloadAttributes`, if payload attributes are provided.
91 ///
92 /// See also <https://github.com/ethereum/execution-apis/blob/6709c2a795b707202e93c4f2867fa0bf2640a84f/src/engine/shanghai.md#engine_forkchoiceupdatedv2>
93 ///
94 /// Caution: This should not accept the `parentBeaconBlockRoot` field in the payload
95 /// attributes.
96 #[method(name = "forkchoiceUpdatedV2")]
97 async fn fork_choice_updated_v2(
98 &self,
99 fork_choice_state: ForkchoiceState,
100 payload_attributes: Option<Engine::PayloadAttributes>,
101 ) -> RpcResult<ForkchoiceUpdated>;
102
103 /// Post Cancun forkchoice update handler
104 ///
105 /// This is the same as `forkchoiceUpdatedV2`, but expects an additional
106 /// `parentBeaconBlockRoot` field in the `payloadAttributes`, if payload attributes
107 /// are provided.
108 ///
109 /// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/cancun.md#engine_forkchoiceupdatedv3>
110 #[method(name = "forkchoiceUpdatedV3")]
111 async fn fork_choice_updated_v3(
112 &self,
113 fork_choice_state: ForkchoiceState,
114 payload_attributes: Option<Engine::PayloadAttributes>,
115 ) -> RpcResult<ForkchoiceUpdated>;
116
117 /// See also <https://github.com/ethereum/execution-apis/blob/6709c2a795b707202e93c4f2867fa0bf2640a84f/src/engine/paris.md#engine_getpayloadv1>
118 ///
119 /// Returns the most recent version of the payload that is available in the corresponding
120 /// payload build process at the time of receiving this call.
121 ///
122 /// Caution: This should not return the `withdrawals` field
123 ///
124 /// Note:
125 /// > Provider software MAY stop the corresponding build process after serving this call.
126 #[method(name = "getPayloadV1")]
127 async fn get_payload_v1(
128 &self,
129 payload_id: PayloadId,
130 ) -> RpcResult<Engine::ExecutionPayloadEnvelopeV1>;
131
132 /// See also <https://github.com/ethereum/execution-apis/blob/6709c2a795b707202e93c4f2867fa0bf2640a84f/src/engine/shanghai.md#engine_getpayloadv2>
133 ///
134 /// Returns the most recent version of the payload that is available in the corresponding
135 /// payload build process at the time of receiving this call. Note:
136 /// > Provider software MAY stop the corresponding build process after serving this call.
137 #[method(name = "getPayloadV2")]
138 async fn get_payload_v2(
139 &self,
140 payload_id: PayloadId,
141 ) -> RpcResult<Engine::ExecutionPayloadEnvelopeV2>;
142
143 /// Post Cancun payload handler which also returns a blobs bundle.
144 ///
145 /// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/cancun.md#engine_getpayloadv3>
146 ///
147 /// Returns the most recent version of the payload that is available in the corresponding
148 /// payload build process at the time of receiving this call. Note:
149 /// > Provider software MAY stop the corresponding build process after serving this call.
150 #[method(name = "getPayloadV3")]
151 async fn get_payload_v3(
152 &self,
153 payload_id: PayloadId,
154 ) -> RpcResult<Engine::ExecutionPayloadEnvelopeV3>;
155
156 /// Post Prague payload handler.
157 ///
158 /// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/prague.md#engine_getpayloadv4>
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 = "getPayloadV4")]
164 async fn get_payload_v4(
165 &self,
166 payload_id: PayloadId,
167 ) -> RpcResult<Engine::ExecutionPayloadEnvelopeV4>;
168
169 /// Post Osaka payload handler.
170 ///
171 /// See also <https://github.com/ethereum/execution-apis/blob/15399c2e2f16a5f800bf3f285640357e2c245ad9/src/engine/osaka.md#engine_getpayloadv5>.
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 = "getPayloadV5")]
177 async fn get_payload_v5(
178 &self,
179 payload_id: PayloadId,
180 ) -> RpcResult<Engine::ExecutionPayloadEnvelopeV5>;
181
182 /// See also <https://github.com/ethereum/execution-apis/blob/6452a6b194d7db269bf1dbd087a267251d3cc7f8/src/engine/shanghai.md#engine_getpayloadbodiesbyhashv1>
183 #[method(name = "getPayloadBodiesByHashV1")]
184 async fn get_payload_bodies_by_hash_v1(
185 &self,
186 block_hashes: Vec<BlockHash>,
187 ) -> RpcResult<ExecutionPayloadBodiesV1>;
188
189 /// See also <https://github.com/ethereum/execution-apis/blob/6452a6b194d7db269bf1dbd087a267251d3cc7f8/src/engine/shanghai.md#engine_getpayloadbodiesbyrangev1>
190 ///
191 /// Returns the execution payload bodies by the range starting at `start`, containing `count`
192 /// blocks.
193 ///
194 /// WARNING: This method is associated with the BeaconBlocksByRange message in the consensus
195 /// layer p2p specification, meaning the input should be treated as untrusted or potentially
196 /// adversarial.
197 ///
198 /// Implementers should take care when acting on the input to this method, specifically
199 /// ensuring that the range is limited properly, and that the range boundaries are computed
200 /// correctly and without panics.
201 #[method(name = "getPayloadBodiesByRangeV1")]
202 async fn get_payload_bodies_by_range_v1(
203 &self,
204 start: U64,
205 count: U64,
206 ) -> RpcResult<ExecutionPayloadBodiesV1>;
207
208 /// This function will return the ClientVersionV1 object.
209 /// See also:
210 /// <https://github.com/ethereum/execution-apis/blob/03911ffc053b8b806123f1fc237184b0092a485a/src/engine/identification.md#engine_getclientversionv1>make fmt
211 ///
212 ///
213 /// - When connected to a single execution client, the consensus client **MUST** receive an
214 /// array with a single `ClientVersionV1` object.
215 /// - When connected to multiple execution clients via a multiplexer, the multiplexer **MUST**
216 /// concatenate the responses from each execution client into a single,
217 /// flat array before returning the response to the consensus client.
218 #[method(name = "getClientVersionV1")]
219 async fn get_client_version_v1(
220 &self,
221 client_version: ClientVersionV1,
222 ) -> RpcResult<Vec<ClientVersionV1>>;
223
224 /// See also <https://github.com/ethereum/execution-apis/blob/6452a6b194d7db269bf1dbd087a267251d3cc7f8/src/engine/common.md#capabilities>
225 #[method(name = "exchangeCapabilities")]
226 async fn exchange_capabilities(&self, capabilities: Vec<String>) -> RpcResult<Vec<String>>;
227
228 /// Fetch blobs for the consensus layer from the blob store.
229 #[method(name = "getBlobsV1")]
230 async fn get_blobs_v1(
231 &self,
232 versioned_hashes: Vec<B256>,
233 ) -> RpcResult<Vec<Option<BlobAndProofV1>>>;
234
235 /// Fetch blobs for the consensus layer from the blob store.
236 ///
237 /// Returns a response only if blobs and proofs are present for _all_ of the versioned hashes:
238 /// 2. Client software MUST return null in case of any missing or older version blobs.
239 #[method(name = "getBlobsV2")]
240 async fn get_blobs_v2(
241 &self,
242 versioned_hashes: Vec<B256>,
243 ) -> RpcResult<Option<Vec<BlobAndProofV2>>>;
244}
245
246/// A subset of the ETH rpc interface: <https://ethereum.github.io/execution-apis/docs/reference/json-rpc-api>
247///
248/// This also includes additional eth functions required by optimism.
249///
250/// Specifically for the engine auth server: <https://github.com/ethereum/execution-apis/blob/main/src/engine/common.md#underlying-protocol>
251#[cfg_attr(not(feature = "client"), rpc(server, namespace = "eth"))]
252#[cfg_attr(feature = "client", rpc(server, client, namespace = "eth"))]
253pub trait EngineEthApi<B: RpcObject, R: RpcObject> {
254 /// Returns an object with data about the sync status or false.
255 #[method(name = "syncing")]
256 fn syncing(&self) -> RpcResult<SyncStatus>;
257
258 /// Returns the chain ID of the current network.
259 #[method(name = "chainId")]
260 async fn chain_id(&self) -> RpcResult<Option<U64>>;
261
262 /// Returns the number of most recent block.
263 #[method(name = "blockNumber")]
264 fn block_number(&self) -> RpcResult<U256>;
265
266 /// Executes a new message call immediately without creating a transaction on the block chain.
267 #[method(name = "call")]
268 async fn call(
269 &self,
270 request: TransactionRequest,
271 block_number: Option<BlockId>,
272 state_overrides: Option<StateOverride>,
273 block_overrides: Option<Box<BlockOverrides>>,
274 ) -> RpcResult<Bytes>;
275
276 /// Returns code at a given address at given block number.
277 #[method(name = "getCode")]
278 async fn get_code(&self, address: Address, block_id: Option<BlockId>) -> RpcResult<Bytes>;
279
280 /// Returns information about a block by hash.
281 #[method(name = "getBlockByHash")]
282 async fn block_by_hash(&self, hash: B256, full: bool) -> RpcResult<Option<B>>;
283
284 /// Returns information about a block by number.
285 #[method(name = "getBlockByNumber")]
286 async fn block_by_number(&self, number: BlockNumberOrTag, full: bool) -> RpcResult<Option<B>>;
287
288 /// Returns all transaction receipts for a given block.
289 #[method(name = "getBlockReceipts")]
290 async fn block_receipts(&self, block_id: BlockId) -> RpcResult<Option<Vec<R>>>;
291
292 /// Sends signed transaction, returning its hash.
293 #[method(name = "sendRawTransaction")]
294 async fn send_raw_transaction(&self, bytes: Bytes) -> RpcResult<B256>;
295
296 /// Returns the receipt of a transaction by transaction hash.
297 #[method(name = "getTransactionReceipt")]
298 async fn transaction_receipt(&self, hash: B256) -> RpcResult<Option<R>>;
299
300 /// Returns logs matching given filter object.
301 #[method(name = "getLogs")]
302 async fn logs(&self, filter: Filter) -> RpcResult<Vec<Log>>;
303
304 /// Returns the account and storage values of the specified account including the Merkle-proof.
305 /// This call can be used to verify that the data you are pulling from is not tampered with.
306 #[method(name = "getProof")]
307 async fn get_proof(
308 &self,
309 address: Address,
310 keys: Vec<JsonStorageKey>,
311 block_number: Option<BlockId>,
312 ) -> RpcResult<EIP1186AccountProofResponse>;
313}