diff --git a/crates/eips/src/eip7685.rs b/crates/eips/src/eip7685.rs index 528c67cfbaa..a1e334d46f6 100644 --- a/crates/eips/src/eip7685.rs +++ b/crates/eips/src/eip7685.rs @@ -75,6 +75,55 @@ impl Requests { } } +/// A list of requests or a precomputed requests hash. +/// +/// For testing purposes, the `Hash` variant stores a precomputed requests hash. This can be useful +/// when the exact contents of the requests are unnecessary, and only a consistent hash value is +/// needed to simulate the presence of requests without holding actual data. +#[derive(Debug, Clone, PartialEq, Eq, Hash, derive_more::From)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum RequestsOrHash { + /// Stores a list of requests, allowing for dynamic requests hash calculation. + Requests(Requests), + /// Stores a precomputed requests hash, used primarily for testing or mocking because the + /// header only contains the hash. + Hash(B256), +} + +impl RequestsOrHash { + /// Returns the requests hash for the enum instance. + /// + /// - If the instance contains a list of requests, this function calculates the hash using + /// `requests_hash` of the [`Requests`] struct. + /// - If it contains a precomputed hash, it returns that hash directly. + #[cfg(feature = "sha2")] + pub fn requests_hash(&self) -> B256 { + match self { + Self::Requests(requests) => requests.requests_hash(), + Self::Hash(precomputed_hash) => *precomputed_hash, + } + } + + /// Returns an instance with the [`EMPTY_REQUESTS_HASH`]. + pub const fn empty() -> Self { + Self::Hash(EMPTY_REQUESTS_HASH) + } + + /// Returns the requests, if any. + pub const fn requests(&self) -> Option<&Requests> { + match self { + Self::Requests(requests) => Some(requests), + Self::Hash(_) => None, + } + } +} + +impl Default for RequestsOrHash { + fn default() -> Self { + Self::Requests(Requests::default()) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/rpc-types-engine/src/cancun.rs b/crates/rpc-types-engine/src/cancun.rs index eddef715d67..d0d2a48b29e 100644 --- a/crates/rpc-types-engine/src/cancun.rs +++ b/crates/rpc-types-engine/src/cancun.rs @@ -2,7 +2,6 @@ //! beacon consensus engine. use alloc::vec::Vec; - use alloy_primitives::B256; /// Fields introduced in `engine_newPayloadV3` that are not present in the `ExecutionPayload` RPC @@ -20,6 +19,13 @@ pub struct CancunPayloadFields { pub versioned_hashes: Vec, } +impl CancunPayloadFields { + /// Returns a new [`CancunPayloadFields`] instance. + pub const fn new(parent_beacon_block_root: B256, versioned_hashes: Vec) -> Self { + Self { parent_beacon_block_root, versioned_hashes } + } +} + /// A container type for [CancunPayloadFields] that may or may not be present. #[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] diff --git a/crates/rpc-types-engine/src/prague.rs b/crates/rpc-types-engine/src/prague.rs index fc1f119b425..36ae0a08135 100644 --- a/crates/rpc-types-engine/src/prague.rs +++ b/crates/rpc-types-engine/src/prague.rs @@ -1,7 +1,8 @@ //! Contains types related to the Prague hardfork that will be used by RPC to communicate with the //! beacon consensus engine. -use alloy_eips::eip7685::Requests; +use alloy_eips::eip7685::{Requests, RequestsOrHash}; +use alloy_primitives::B256; /// Fields introduced in `engine_newPayloadV4` that are not present in the `ExecutionPayload` RPC /// object. @@ -9,11 +10,18 @@ use alloy_eips::eip7685::Requests; #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct PraguePayloadFields { /// EIP-7685 requests. - pub requests: Requests, + pub requests: RequestsOrHash, /// EIP-7742 target number of blobs in the block. pub target_blobs_per_block: u64, } +impl PraguePayloadFields { + /// Returns a new [`PraguePayloadFields`] instance. + pub fn new(requests: impl Into, target_blobs_per_block: u64) -> Self { + Self { requests: requests.into(), target_blobs_per_block } + } +} + /// A container type for [PraguePayloadFields] that may or may not be present. #[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] @@ -34,7 +42,7 @@ impl MaybePraguePayloadFields { /// Returns the requests, if any. pub fn requests(&self) -> Option<&Requests> { - self.fields.as_ref().map(|fields| &fields.requests) + self.fields.as_ref().and_then(|fields| fields.requests.requests()) } /// Returns the target blobs per block, if any. @@ -42,6 +50,15 @@ impl MaybePraguePayloadFields { self.fields.as_ref().map(|fields| fields.target_blobs_per_block) } + /// Calculates or retrieves the requests hash. + /// + /// - If the `prague` field contains a list of requests, it calculates the requests hash + /// dynamically. + /// - If it contains a precomputed hash (used for testing), it returns that hash directly. + pub fn requests_hash(&self) -> Option { + self.fields.as_ref().map(|fields| fields.requests.requests_hash()) + } + /// Returns a reference to the inner fields. pub const fn as_ref(&self) -> Option<&PraguePayloadFields> { self.fields.as_ref() diff --git a/crates/rpc-types-engine/src/sidecar.rs b/crates/rpc-types-engine/src/sidecar.rs index 267f92bf546..f2e262fabd3 100644 --- a/crates/rpc-types-engine/src/sidecar.rs +++ b/crates/rpc-types-engine/src/sidecar.rs @@ -57,10 +57,22 @@ impl ExecutionPayloadSidecar { } /// Returns the EIP-7685 requests + /// + /// Note: if the [`PraguePayloadFields`] only contains the requests hash this will return + /// `None`. pub fn requests(&self) -> Option<&Requests> { self.prague.requests() } + /// Calculates or retrieves the requests hash. + /// + /// - If the `prague` field contains a list of requests, it calculates the requests hash + /// dynamically. + /// - If it contains a precomputed hash (used for testing), it returns that hash directly. + pub fn requests_hash(&self) -> Option { + self.prague.requests_hash() + } + /// Returns the target blobs per block pub fn target_blobs_per_block(&self) -> Option { self.prague.target_blobs_per_block()