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