alloy_provider/ext/
engine.rs

1use crate::Provider;
2use alloy_network::Network;
3use alloy_primitives::{BlockHash, Bytes, B256};
4use alloy_rpc_types_engine::{
5    ClientVersionV1, ExecutionPayloadBodiesV1, ExecutionPayloadEnvelopeV2,
6    ExecutionPayloadEnvelopeV3, ExecutionPayloadEnvelopeV4, ExecutionPayloadEnvelopeV5,
7    ExecutionPayloadInputV2, ExecutionPayloadV1, ExecutionPayloadV3, ForkchoiceState,
8    ForkchoiceUpdated, PayloadAttributes, PayloadId, PayloadStatus,
9};
10use alloy_transport::TransportResult;
11
12/// Extension trait that gives access to engine API RPC methods.
13#[cfg_attr(target_family = "wasm", async_trait::async_trait(?Send))]
14#[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)]
15pub trait EngineApi<N>: Send + Sync {
16    /// Sends the given payload to the execution layer client, as specified for the Paris fork.
17    ///
18    /// Caution: This should not accept the `withdrawals` field
19    ///
20    /// See also <https://github.com/ethereum/execution-apis/blob/6709c2a795b707202e93c4f2867fa0bf2640a84f/src/engine/paris.md#engine_newpayloadv1>
21    async fn new_payload_v1(&self, payload: ExecutionPayloadV1) -> TransportResult<PayloadStatus>;
22
23    /// Sends the given payload to the execution layer client, as specified for the Shanghai fork.
24    ///
25    /// See also <https://github.com/ethereum/execution-apis/blob/584905270d8ad665718058060267061ecfd79ca5/src/engine/shanghai.md#engine_newpayloadv2>
26    async fn new_payload_v2(
27        &self,
28        payload: ExecutionPayloadInputV2,
29    ) -> TransportResult<PayloadStatus>;
30
31    /// Sends the given payload to the execution layer client, as specified for the Cancun fork.
32    ///
33    /// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/cancun.md#engine_newpayloadv3>
34    async fn new_payload_v3(
35        &self,
36        payload: ExecutionPayloadV3,
37        versioned_hashes: Vec<B256>,
38        parent_beacon_block_root: B256,
39    ) -> TransportResult<PayloadStatus>;
40
41    /// Sends the given payload to the execution layer client, as specified for the Prague fork.
42    ///
43    /// See also <https://github.com/ethereum/execution-apis/blob/03911ffc053b8b806123f1fc237184b0092a485a/src/engine/prague.md#engine_newpayloadv4>
44    async fn new_payload_v4(
45        &self,
46        payload: ExecutionPayloadV3,
47        versioned_hashes: Vec<B256>,
48        parent_beacon_block_root: B256,
49        execution_requests: Vec<Bytes>,
50    ) -> TransportResult<PayloadStatus>;
51
52    /// Updates the execution layer client with the given fork choice, as specified for the Paris
53    /// fork.
54    ///
55    /// Caution: This should not accept the `withdrawals` field in the payload attributes.
56    ///
57    /// See also <https://github.com/ethereum/execution-apis/blob/6709c2a795b707202e93c4f2867fa0bf2640a84f/src/engine/paris.md#engine_forkchoiceupdatedv1>
58    async fn fork_choice_updated_v1(
59        &self,
60        fork_choice_state: ForkchoiceState,
61        payload_attributes: Option<PayloadAttributes>,
62    ) -> TransportResult<ForkchoiceUpdated>;
63
64    /// Updates the execution layer client with the given fork choice, as specified for the Shanghai
65    /// fork.
66    ///
67    /// Caution: This should not accept the `parentBeaconBlockRoot` field in the payload attributes.
68    ///
69    /// See also <https://github.com/ethereum/execution-apis/blob/6709c2a795b707202e93c4f2867fa0bf2640a84f/src/engine/shanghai.md#engine_forkchoiceupdatedv2>
70    async fn fork_choice_updated_v2(
71        &self,
72        fork_choice_state: ForkchoiceState,
73        payload_attributes: Option<PayloadAttributes>,
74    ) -> TransportResult<ForkchoiceUpdated>;
75
76    /// Updates the execution layer client with the given fork choice, as specified for the Cancun
77    /// fork.
78    ///
79    /// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/cancun.md#engine_forkchoiceupdatedv3>
80    async fn fork_choice_updated_v3(
81        &self,
82        fork_choice_state: ForkchoiceState,
83        payload_attributes: Option<PayloadAttributes>,
84    ) -> TransportResult<ForkchoiceUpdated>;
85
86    /// Retrieves an execution payload from a previously started build process, as specified for the
87    /// Paris fork.
88    ///
89    /// Caution: This should not return the `withdrawals` field
90    ///
91    /// See also <https://github.com/ethereum/execution-apis/blob/6709c2a795b707202e93c4f2867fa0bf2640a84f/src/engine/paris.md#engine_getpayloadv1>
92    ///
93    /// Note:
94    /// > Provider software MAY stop the corresponding build process after serving this call.
95    async fn get_payload_v1(&self, payload_id: PayloadId) -> TransportResult<ExecutionPayloadV1>;
96
97    /// Retrieves an execution payload from a previously started build process, as specified for the
98    /// Shanghai fork.
99    ///
100    /// See also <https://github.com/ethereum/execution-apis/blob/6709c2a795b707202e93c4f2867fa0bf2640a84f/src/engine/shanghai.md#engine_getpayloadv2>
101    ///
102    /// Note:
103    /// > Provider software MAY stop the corresponding build process after serving this call.
104    async fn get_payload_v2(
105        &self,
106        payload_id: PayloadId,
107    ) -> TransportResult<ExecutionPayloadEnvelopeV2>;
108
109    /// Retrieves an execution payload from a previously started build process, as specified for the
110    /// Cancun fork.
111    ///
112    /// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/cancun.md#engine_getpayloadv3>
113    ///
114    /// Note:
115    /// > Provider software MAY stop the corresponding build process after serving this call.
116    async fn get_payload_v3(
117        &self,
118        payload_id: PayloadId,
119    ) -> TransportResult<ExecutionPayloadEnvelopeV3>;
120
121    /// Returns the most recent version of the payload that is available in the corresponding
122    /// payload build process at the time of receiving this call.
123    ///
124    /// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/prague.md#engine_getpayloadv4>
125    ///
126    /// Note:
127    /// > Provider software MAY stop the corresponding build process after serving this call.
128    async fn get_payload_v4(
129        &self,
130        payload_id: PayloadId,
131    ) -> TransportResult<ExecutionPayloadEnvelopeV4>;
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.
135    ///
136    /// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/osaka.md#engine_getpayloadv5>
137    ///
138    /// Note:
139    /// > Provider software MAY stop the corresponding build process after serving this call.
140    async fn get_payload_v5(
141        &self,
142        payload_id: PayloadId,
143    ) -> TransportResult<ExecutionPayloadEnvelopeV5>;
144
145    /// Returns the execution payload bodies by the given hash.
146    ///
147    /// See also <https://github.com/ethereum/execution-apis/blob/6452a6b194d7db269bf1dbd087a267251d3cc7f8/src/engine/shanghai.md#engine_getpayloadbodiesbyhashv1>
148    async fn get_payload_bodies_by_hash_v1(
149        &self,
150        block_hashes: Vec<BlockHash>,
151    ) -> TransportResult<ExecutionPayloadBodiesV1>;
152
153    /// Returns the execution payload bodies by the range starting at `start`, containing `count`
154    /// blocks.
155    ///
156    /// WARNING: This method is associated with the BeaconBlocksByRange message in the consensus
157    /// layer p2p specification, meaning the input should be treated as untrusted or potentially
158    /// adversarial.
159    ///
160    /// Implementers should take care when acting on the input to this method, specifically
161    /// ensuring that the range is limited properly, and that the range boundaries are computed
162    /// correctly and without panics.
163    ///
164    /// See also <https://github.com/ethereum/execution-apis/blob/6452a6b194d7db269bf1dbd087a267251d3cc7f8/src/engine/shanghai.md#engine_getpayloadbodiesbyrangev1>
165    async fn get_payload_bodies_by_range_v1(
166        &self,
167        start: u64,
168        count: u64,
169    ) -> TransportResult<ExecutionPayloadBodiesV1>;
170
171    /// Returns the execution client version information.
172    ///
173    /// Note:
174    /// > The `client_version` parameter identifies the consensus client.
175    ///
176    /// See also <https://github.com/ethereum/execution-apis/blob/main/src/engine/identification.md#engine_getclientversionv1>
177    async fn get_client_version_v1(
178        &self,
179        client_version: ClientVersionV1,
180    ) -> TransportResult<Vec<ClientVersionV1>>;
181
182    /// Returns the list of Engine API methods supported by the execution layer client software.
183    ///
184    /// See also <https://github.com/ethereum/execution-apis/blob/6452a6b194d7db269bf1dbd087a267251d3cc7f8/src/engine/common.md#capabilities>
185    async fn exchange_capabilities(
186        &self,
187        capabilities: Vec<String>,
188    ) -> TransportResult<Vec<String>>;
189}
190
191#[cfg_attr(target_family = "wasm", async_trait::async_trait(?Send))]
192#[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)]
193impl<N, P> EngineApi<N> for P
194where
195    N: Network,
196    P: Provider<N>,
197{
198    async fn new_payload_v1(&self, payload: ExecutionPayloadV1) -> TransportResult<PayloadStatus> {
199        self.client().request("engine_newPayloadV1", (payload,)).await
200    }
201
202    async fn new_payload_v2(
203        &self,
204        payload: ExecutionPayloadInputV2,
205    ) -> TransportResult<PayloadStatus> {
206        self.client().request("engine_newPayloadV2", (payload,)).await
207    }
208
209    async fn new_payload_v3(
210        &self,
211        payload: ExecutionPayloadV3,
212        versioned_hashes: Vec<B256>,
213        parent_beacon_block_root: B256,
214    ) -> TransportResult<PayloadStatus> {
215        self.client()
216            .request("engine_newPayloadV3", (payload, versioned_hashes, parent_beacon_block_root))
217            .await
218    }
219
220    async fn new_payload_v4(
221        &self,
222        payload: ExecutionPayloadV3,
223        versioned_hashes: Vec<B256>,
224        parent_beacon_block_root: B256,
225        execution_requests: Vec<Bytes>,
226    ) -> TransportResult<PayloadStatus> {
227        self.client()
228            .request(
229                "engine_newPayloadV4",
230                (payload, versioned_hashes, parent_beacon_block_root, execution_requests),
231            )
232            .await
233    }
234
235    async fn fork_choice_updated_v1(
236        &self,
237        fork_choice_state: ForkchoiceState,
238        payload_attributes: Option<PayloadAttributes>,
239    ) -> TransportResult<ForkchoiceUpdated> {
240        self.client()
241            .request("engine_forkchoiceUpdatedV1", (fork_choice_state, payload_attributes))
242            .await
243    }
244
245    async fn fork_choice_updated_v2(
246        &self,
247        fork_choice_state: ForkchoiceState,
248        payload_attributes: Option<PayloadAttributes>,
249    ) -> TransportResult<ForkchoiceUpdated> {
250        self.client()
251            .request("engine_forkchoiceUpdatedV2", (fork_choice_state, payload_attributes))
252            .await
253    }
254
255    async fn fork_choice_updated_v3(
256        &self,
257        fork_choice_state: ForkchoiceState,
258        payload_attributes: Option<PayloadAttributes>,
259    ) -> TransportResult<ForkchoiceUpdated> {
260        self.client()
261            .request("engine_forkchoiceUpdatedV3", (fork_choice_state, payload_attributes))
262            .await
263    }
264
265    async fn get_payload_v1(&self, payload_id: PayloadId) -> TransportResult<ExecutionPayloadV1> {
266        self.client().request("engine_getPayloadV1", (payload_id,)).await
267    }
268
269    async fn get_payload_v2(
270        &self,
271        payload_id: PayloadId,
272    ) -> TransportResult<ExecutionPayloadEnvelopeV2> {
273        self.client().request("engine_getPayloadV2", (payload_id,)).await
274    }
275
276    async fn get_payload_v3(
277        &self,
278        payload_id: PayloadId,
279    ) -> TransportResult<ExecutionPayloadEnvelopeV3> {
280        self.client().request("engine_getPayloadV3", (payload_id,)).await
281    }
282
283    async fn get_payload_v4(
284        &self,
285        payload_id: PayloadId,
286    ) -> TransportResult<ExecutionPayloadEnvelopeV4> {
287        self.client().request("engine_getPayloadV4", (payload_id,)).await
288    }
289
290    async fn get_payload_v5(
291        &self,
292        payload_id: PayloadId,
293    ) -> TransportResult<ExecutionPayloadEnvelopeV5> {
294        self.client().request("engine_getPayloadV5", (payload_id,)).await
295    }
296
297    async fn get_payload_bodies_by_hash_v1(
298        &self,
299        block_hashes: Vec<BlockHash>,
300    ) -> TransportResult<ExecutionPayloadBodiesV1> {
301        self.client().request("engine_getPayloadBodiesByHashV1", (block_hashes,)).await
302    }
303
304    async fn get_payload_bodies_by_range_v1(
305        &self,
306        start: u64,
307        count: u64,
308    ) -> TransportResult<ExecutionPayloadBodiesV1> {
309        self.client().request("engine_getPayloadBodiesByRangeV1", (start, count)).await
310    }
311
312    async fn get_client_version_v1(
313        &self,
314        client_version: ClientVersionV1,
315    ) -> TransportResult<Vec<ClientVersionV1>> {
316        self.client().request("engine_getClientVersionV1", (client_version,)).await
317    }
318
319    async fn exchange_capabilities(
320        &self,
321        capabilities: Vec<String>,
322    ) -> TransportResult<Vec<String>> {
323        self.client().request("engine_exchangeCapabilities", (capabilities,)).await
324    }
325}