alloy_rpc_types_engine/
sidecar.rs

1//! Contains helpers for dealing with additional parameters of `newPayload` requests.
2
3use crate::{
4    CancunPayloadFields, MaybeCancunPayloadFields, MaybePraguePayloadFields, PraguePayloadFields,
5};
6use alloc::vec::Vec;
7use alloy_consensus::{Block, BlockHeader, Transaction};
8use alloy_eips::eip7685::Requests;
9use alloy_primitives::B256;
10
11/// Container type for all available additional `newPayload` request parameters that are not present
12/// in the `ExecutionPayload` object itself.
13#[derive(Debug, Clone, Default)]
14#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
15#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
16pub struct ExecutionPayloadSidecar {
17    /// Cancun request params introduced in `engine_newPayloadV3` that are not present in the
18    /// `ExecutionPayload`.
19    cancun: MaybeCancunPayloadFields,
20    /// The EIP-7685 requests provided as additional request params to `engine_newPayloadV4` that
21    /// are not present in the `ExecutionPayload`.
22    prague: MaybePraguePayloadFields,
23}
24
25impl ExecutionPayloadSidecar {
26    /// Extracts the [`ExecutionPayloadSidecar`] from the given [`alloy_consensus::Block`].
27    ///
28    /// Returns [`ExecutionPayloadSidecar::none`] if the block does not contain any sidecar fields
29    /// (pre-cancun): `requests_hash`, `parent_beacon_block_root`, `blob_versioned_hashes`.
30    ///
31    /// Note: This returns [`RequestOrHash::Hash`](alloy_eips::eip7685::RequestsOrHash::Hash) for
32    /// the EIP-7685 requests.
33    pub fn from_block<T, H>(block: &Block<T, H>) -> Self
34    where
35        T: Transaction,
36        H: BlockHeader,
37    {
38        let cancun =
39            block.parent_beacon_block_root().map(|parent_beacon_block_root| CancunPayloadFields {
40                parent_beacon_block_root,
41                versioned_hashes: block.body.blob_versioned_hashes_iter().copied().collect(),
42            });
43
44        let prague = block.requests_hash().map(PraguePayloadFields::new);
45
46        match (cancun, prague) {
47            (Some(cancun), Some(prague)) => Self::v4(cancun, prague),
48            (Some(cancun), None) => Self::v3(cancun),
49            _ => Self::none(),
50        }
51    }
52
53    /// Returns a new empty instance (pre-cancun, v1, v2)
54    pub const fn none() -> Self {
55        Self { cancun: MaybeCancunPayloadFields::none(), prague: MaybePraguePayloadFields::none() }
56    }
57
58    /// Creates a new instance for cancun with the cancun fields for `engine_newPayloadV3`
59    pub fn v3(cancun: CancunPayloadFields) -> Self {
60        Self { cancun: cancun.into(), prague: MaybePraguePayloadFields::none() }
61    }
62
63    /// Creates a new instance post prague for `engine_newPayloadV4`
64    pub fn v4(cancun: CancunPayloadFields, prague: PraguePayloadFields) -> Self {
65        Self { cancun: cancun.into(), prague: prague.into() }
66    }
67
68    /// Returns a reference to the [`CancunPayloadFields`].
69    pub const fn cancun(&self) -> Option<&CancunPayloadFields> {
70        self.cancun.as_ref()
71    }
72
73    /// Consumes the type and returns the [`CancunPayloadFields`]
74    pub fn into_cancun(self) -> Option<CancunPayloadFields> {
75        self.cancun.into_inner()
76    }
77
78    /// Returns a reference to the [`PraguePayloadFields`].
79    pub const fn prague(&self) -> Option<&PraguePayloadFields> {
80        self.prague.as_ref()
81    }
82
83    /// Consumes the type and returns the [`PraguePayloadFields`].
84    pub fn into_prague(self) -> Option<PraguePayloadFields> {
85        self.prague.into_inner()
86    }
87
88    /// Returns the parent beacon block root, if any.
89    pub fn parent_beacon_block_root(&self) -> Option<B256> {
90        self.cancun.parent_beacon_block_root()
91    }
92
93    /// Returns the blob versioned hashes, if any.
94    pub fn versioned_hashes(&self) -> Option<&Vec<B256>> {
95        self.cancun.versioned_hashes()
96    }
97
98    /// Returns the EIP-7685 requests
99    ///
100    /// Note: if the [`PraguePayloadFields`] only contains the requests hash this will return
101    /// `None`.
102    pub fn requests(&self) -> Option<&Requests> {
103        self.prague.requests()
104    }
105
106    /// Calculates or retrieves the requests hash.
107    ///
108    /// - If the `prague` field contains a list of requests, it calculates the requests hash
109    ///   dynamically.
110    /// - If it contains a precomputed hash (used for testing), it returns that hash directly.
111    pub fn requests_hash(&self) -> Option<B256> {
112        self.prague.requests_hash()
113    }
114}