diff --git a/crates/engine/primitives/src/lib.rs b/crates/engine/primitives/src/lib.rs index e8d07df75..182921866 100644 --- a/crates/engine/primitives/src/lib.rs +++ b/crates/engine/primitives/src/lib.rs @@ -13,9 +13,7 @@ extern crate alloc; use alloy_consensus::BlockHeader; use alloy_eips::eip7685::Requests; -use alloy_primitives::B256; -use alloy_rpc_types_engine::ExecutionData; -use core::fmt::{self, Debug}; +use core::fmt; use reth_payload_primitives::{ validate_execution_requests, BuiltPayload, EngineApiMessageVersion, EngineObjectValidationError, InvalidPayloadAttributesError, NewPayloadError, PayloadAttributes, @@ -25,6 +23,9 @@ use reth_primitives::{NodePrimitives, RecoveredBlock, SealedBlock}; use reth_primitives_traits::Block; use serde::{de::DeserializeOwned, Serialize}; +// Re-export [`ExecutionPayload`] moved to `reth_payload_primitives` +pub use reth_payload_primitives::ExecutionPayload; + mod error; pub use error::*; @@ -40,34 +41,6 @@ pub use event::*; mod invalid_block_hook; pub use invalid_block_hook::InvalidBlockHook; -/// An execution payload. -pub trait ExecutionPayload: - Serialize + DeserializeOwned + Debug + Clone + Send + Sync + 'static -{ - /// Returns the parent hash of the block. - fn parent_hash(&self) -> B256; - - /// Returns the hash of the block. - fn block_hash(&self) -> B256; - - /// Returns the number of the block. - fn block_number(&self) -> u64; -} - -impl ExecutionPayload for ExecutionData { - fn parent_hash(&self) -> B256 { - self.payload.parent_hash() - } - - fn block_hash(&self) -> B256 { - self.payload.block_hash() - } - - fn block_number(&self) -> u64 { - self.payload.block_number() - } -} - /// This type defines the versioned types of the engine API. /// /// This includes the execution payload types and payload attributes that are used to trigger a @@ -117,7 +90,7 @@ pub trait EngineTypes: /// Execution data. type ExecutionData: ExecutionPayload; - /// Converts a [`BuiltPayload`] into an [`ExecutionData`]. + /// Converts a [`BuiltPayload`] into an [`Self::ExecutionData`]. fn block_to_payload( block: SealedBlock< <::Primitives as NodePrimitives>::Block, @@ -165,7 +138,11 @@ pub trait EngineValidator: fn validate_version_specific_fields( &self, version: EngineApiMessageVersion, - payload_or_attrs: PayloadOrAttributes<'_, ::PayloadAttributes>, + payload_or_attrs: PayloadOrAttributes< + '_, + Types::ExecutionData, + ::PayloadAttributes, + >, ) -> Result<(), EngineObjectValidationError>; /// Ensures that the payload attributes are valid for the given [`EngineApiMessageVersion`]. diff --git a/crates/ethereum/engine-primitives/src/lib.rs b/crates/ethereum/engine-primitives/src/lib.rs index 644da880a..ad26315e5 100644 --- a/crates/ethereum/engine-primitives/src/lib.rs +++ b/crates/ethereum/engine-primitives/src/lib.rs @@ -117,7 +117,7 @@ where fn validate_version_specific_fields( &self, version: EngineApiMessageVersion, - payload_or_attrs: PayloadOrAttributes<'_, EthPayloadAttributes>, + payload_or_attrs: PayloadOrAttributes<'_, Self::ExecutionData, EthPayloadAttributes>, ) -> Result<(), EngineObjectValidationError> { validate_version_specific_fields(self.chain_spec(), version, payload_or_attrs) } @@ -127,6 +127,12 @@ where version: EngineApiMessageVersion, attributes: &EthPayloadAttributes, ) -> Result<(), EngineObjectValidationError> { - validate_version_specific_fields(self.chain_spec(), version, attributes.into()) + validate_version_specific_fields( + self.chain_spec(), + version, + PayloadOrAttributes::::PayloadAttributes( + attributes, + ), + ) } } diff --git a/crates/optimism/node/src/engine.rs b/crates/optimism/node/src/engine.rs index 4b12008cd..02018b027 100644 --- a/crates/optimism/node/src/engine.rs +++ b/crates/optimism/node/src/engine.rs @@ -123,7 +123,7 @@ where fn validate_version_specific_fields( &self, version: EngineApiMessageVersion, - payload_or_attrs: PayloadOrAttributes<'_, OpPayloadAttributes>, + payload_or_attrs: PayloadOrAttributes<'_, Self::ExecutionData, OpPayloadAttributes>, ) -> Result<(), EngineObjectValidationError> { validate_withdrawals_presence( self.chain_spec(), @@ -146,7 +146,13 @@ where version: EngineApiMessageVersion, attributes: &OpPayloadAttributes, ) -> Result<(), EngineObjectValidationError> { - validate_version_specific_fields(self.chain_spec(), version, attributes.into())?; + validate_version_specific_fields( + self.chain_spec(), + version, + PayloadOrAttributes::::PayloadAttributes( + attributes, + ), + )?; if attributes.gas_limit.is_none() { return Err(EngineObjectValidationError::InvalidParams( diff --git a/crates/payload/primitives/src/lib.rs b/crates/payload/primitives/src/lib.rs index 69fda0bf8..8f0e800d6 100644 --- a/crates/payload/primitives/src/lib.rs +++ b/crates/payload/primitives/src/lib.rs @@ -29,7 +29,7 @@ pub use traits::{ }; mod payload; -pub use payload::PayloadOrAttributes; +pub use payload::{ExecutionPayload, PayloadOrAttributes}; /// The types that are used by the engine API. pub trait PayloadTypes: Send + Sync + Unpin + core::fmt::Debug + Clone + 'static { @@ -302,12 +302,13 @@ impl MessageValidationKind { /// either an execution payload, or payload attributes. /// /// The version is provided by the [`EngineApiMessageVersion`] argument. -pub fn validate_version_specific_fields( +pub fn validate_version_specific_fields( chain_spec: &T, version: EngineApiMessageVersion, - payload_or_attrs: PayloadOrAttributes<'_, Type>, + payload_or_attrs: PayloadOrAttributes<'_, Payload, Type>, ) -> Result<(), EngineObjectValidationError> where + Payload: ExecutionPayload, Type: PayloadAttributes, T: EthereumHardforks, { diff --git a/crates/payload/primitives/src/payload.rs b/crates/payload/primitives/src/payload.rs index 10a60cb10..106ebd608 100644 --- a/crates/payload/primitives/src/payload.rs +++ b/crates/payload/primitives/src/payload.rs @@ -2,32 +2,75 @@ use crate::{MessageValidationKind, PayloadAttributes}; use alloc::vec::Vec; use alloy_eips::eip4895::Withdrawal; use alloy_primitives::B256; -use alloy_rpc_types_engine::ExecutionPayload; +use alloy_rpc_types_engine::ExecutionData; +use core::fmt::Debug; +use serde::{de::DeserializeOwned, Serialize}; -/// Either an [`ExecutionPayload`] or a type that implements the [`PayloadAttributes`] trait. +/// An execution payload. +pub trait ExecutionPayload: + Serialize + DeserializeOwned + Debug + Clone + Send + Sync + 'static +{ + /// Returns the parent hash of the block. + fn parent_hash(&self) -> B256; + + /// Returns the hash of the block. + fn block_hash(&self) -> B256; + + /// Returns the number of the block. + fn block_number(&self) -> u64; + + /// Returns the withdrawals for the payload, if it exists. + fn withdrawals(&self) -> Option<&Vec>; + + /// Return the parent beacon block root for the payload, if it exists. + fn parent_beacon_block_root(&self) -> Option; + + /// Returns the timestamp to be used in the payload. + fn timestamp(&self) -> u64; +} + +impl ExecutionPayload for ExecutionData { + fn parent_hash(&self) -> B256 { + self.payload.parent_hash() + } + + fn block_hash(&self) -> B256 { + self.payload.block_hash() + } + + fn block_number(&self) -> u64 { + self.payload.block_number() + } + + fn withdrawals(&self) -> Option<&Vec> { + self.payload.withdrawals() + } + + fn parent_beacon_block_root(&self) -> Option { + self.sidecar.parent_beacon_block_root() + } + + fn timestamp(&self) -> u64 { + self.payload.timestamp() + } +} + +/// Either a type that implements the [`ExecutionPayload`] or a type that implements the +/// [`PayloadAttributes`] trait. /// /// This is a helper type to unify pre-validation of version specific fields of the engine API. #[derive(Debug)] -pub enum PayloadOrAttributes<'a, Attributes> { - /// An [`ExecutionPayload`] and optional parent beacon block root. - ExecutionPayload { - /// The inner execution payload - payload: &'a ExecutionPayload, - /// The parent beacon block root - parent_beacon_block_root: Option, - }, +pub enum PayloadOrAttributes<'a, Payload, Attributes> { + /// An [`ExecutionPayload`] + ExecutionPayload(&'a Payload), /// A payload attributes type. PayloadAttributes(&'a Attributes), } -impl<'a, Attributes> PayloadOrAttributes<'a, Attributes> { - /// Construct a [`PayloadOrAttributes`] from an [`ExecutionPayload`] and optional parent beacon - /// block root. - pub const fn from_execution_payload( - payload: &'a ExecutionPayload, - parent_beacon_block_root: Option, - ) -> Self { - Self::ExecutionPayload { payload, parent_beacon_block_root } +impl<'a, Payload, Attributes> PayloadOrAttributes<'a, Payload, Attributes> { + /// Construct a [`PayloadOrAttributes::ExecutionPayload`] variant + pub const fn from_execution_payload(payload: &'a Payload) -> Self { + Self::ExecutionPayload(payload) } /// Construct a [`PayloadOrAttributes::PayloadAttributes`] variant @@ -36,14 +79,15 @@ impl<'a, Attributes> PayloadOrAttributes<'a, Attributes> { } } -impl PayloadOrAttributes<'_, Attributes> +impl PayloadOrAttributes<'_, Payload, Attributes> where + Payload: ExecutionPayload, Attributes: PayloadAttributes, { /// Return the withdrawals for the payload or attributes. pub fn withdrawals(&self) -> Option<&Vec> { match self { - Self::ExecutionPayload { payload, .. } => payload.withdrawals(), + Self::ExecutionPayload(payload) => payload.withdrawals(), Self::PayloadAttributes(attributes) => attributes.withdrawals(), } } @@ -51,7 +95,7 @@ where /// Return the timestamp for the payload or attributes. pub fn timestamp(&self) -> u64 { match self { - Self::ExecutionPayload { payload, .. } => payload.timestamp(), + Self::ExecutionPayload(payload) => payload.timestamp(), Self::PayloadAttributes(attributes) => attributes.timestamp(), } } @@ -59,7 +103,7 @@ where /// Return the parent beacon block root for the payload or attributes. pub fn parent_beacon_block_root(&self) -> Option { match self { - Self::ExecutionPayload { parent_beacon_block_root, .. } => *parent_beacon_block_root, + Self::ExecutionPayload(payload) => payload.parent_beacon_block_root(), Self::PayloadAttributes(attributes) => attributes.parent_beacon_block_root(), } } @@ -73,7 +117,8 @@ where } } -impl<'a, AttributesType> From<&'a AttributesType> for PayloadOrAttributes<'a, AttributesType> +impl<'a, Payload, AttributesType> From<&'a AttributesType> + for PayloadOrAttributes<'a, Payload, AttributesType> where AttributesType: PayloadAttributes, { diff --git a/crates/rpc/rpc-engine-api/src/engine_api.rs b/crates/rpc/rpc-engine-api/src/engine_api.rs index 41d12ba73..e9d3e9e4f 100644 --- a/crates/rpc/rpc-engine-api/src/engine_api.rs +++ b/crates/rpc/rpc-engine-api/src/engine_api.rs @@ -9,10 +9,10 @@ use alloy_eips::{ }; use alloy_primitives::{BlockHash, BlockNumber, B256, U64}; use alloy_rpc_types_engine::{ - CancunPayloadFields, ClientVersionV1, ExecutionData, ExecutionPayload, - ExecutionPayloadBodiesV1, ExecutionPayloadBodyV1, ExecutionPayloadInputV2, - ExecutionPayloadSidecar, ExecutionPayloadV1, ExecutionPayloadV3, ForkchoiceState, - ForkchoiceUpdated, PayloadId, PayloadStatus, PraguePayloadFields, TransitionConfiguration, + CancunPayloadFields, ClientVersionV1, ExecutionData, ExecutionPayloadBodiesV1, + ExecutionPayloadBodyV1, ExecutionPayloadInputV2, ExecutionPayloadSidecar, ExecutionPayloadV1, + ExecutionPayloadV3, ForkchoiceState, ForkchoiceUpdated, PayloadId, PayloadStatus, + PraguePayloadFields, TransitionConfiguration, }; use async_trait::async_trait; use jsonrpsee_core::{server::RpcModule, RpcResult}; @@ -560,10 +560,11 @@ where &self, payload: ExecutionPayloadV1, ) -> EngineApiResult { - let payload = ExecutionPayload::from(payload); + let payload = + ExecutionData { payload: payload.into(), sidecar: ExecutionPayloadSidecar::none() }; let payload_or_attrs = - PayloadOrAttributes::<'_, EngineT::PayloadAttributes>::from_execution_payload( - &payload, None, + PayloadOrAttributes::<'_, ExecutionData, EngineT::PayloadAttributes>::from_execution_payload( + &payload, ); self.inner .validator @@ -572,7 +573,7 @@ where Ok(self .inner .beacon_consensus - .new_payload(ExecutionData { payload, sidecar: ExecutionPayloadSidecar::none() }) + .new_payload(payload) .await .inspect(|_| self.inner.on_new_payload_response())?) } @@ -596,10 +597,13 @@ where &self, payload: ExecutionPayloadInputV2, ) -> EngineApiResult { - let payload = payload.into_payload(); + let payload = ExecutionData { + payload: payload.into_payload(), + sidecar: ExecutionPayloadSidecar::none(), + }; let payload_or_attrs = - PayloadOrAttributes::<'_, EngineT::PayloadAttributes>::from_execution_payload( - &payload, None, + PayloadOrAttributes::<'_, ExecutionData, EngineT::PayloadAttributes>::from_execution_payload( + &payload, ); self.inner .validator @@ -607,7 +611,7 @@ where Ok(self .inner .beacon_consensus - .new_payload(ExecutionData { payload, sidecar: ExecutionPayloadSidecar::none() }) + .new_payload(payload) .await .inspect(|_| self.inner.on_new_payload_response())?) } @@ -633,11 +637,16 @@ where versioned_hashes: Vec, parent_beacon_block_root: B256, ) -> EngineApiResult { - let payload = ExecutionPayload::from(payload); + let payload = ExecutionData { + payload: payload.into(), + sidecar: ExecutionPayloadSidecar::v3(CancunPayloadFields { + versioned_hashes, + parent_beacon_block_root, + }), + }; let payload_or_attrs = - PayloadOrAttributes::<'_, EngineT::PayloadAttributes>::from_execution_payload( + PayloadOrAttributes::<'_, ExecutionData, EngineT::PayloadAttributes>::from_execution_payload( &payload, - Some(parent_beacon_block_root), ); self.inner .validator @@ -646,13 +655,7 @@ where Ok(self .inner .beacon_consensus - .new_payload(ExecutionData { - payload, - sidecar: ExecutionPayloadSidecar::v3(CancunPayloadFields { - versioned_hashes, - parent_beacon_block_root, - }), - }) + .new_payload(payload) .await .inspect(|_| self.inner.on_new_payload_response())?) } @@ -682,27 +685,29 @@ where parent_beacon_block_root: B256, execution_requests: Requests, ) -> EngineApiResult { - let payload = ExecutionPayload::from(payload); + let payload = ExecutionData { + payload: payload.into(), + sidecar: ExecutionPayloadSidecar::v4( + CancunPayloadFields { versioned_hashes, parent_beacon_block_root }, + PraguePayloadFields { requests: RequestsOrHash::Requests(execution_requests) }, + ), + }; let payload_or_attrs = - PayloadOrAttributes::<'_, EngineT::PayloadAttributes>::from_execution_payload( + PayloadOrAttributes::<'_, ExecutionData, EngineT::PayloadAttributes>::from_execution_payload( &payload, - Some(parent_beacon_block_root), ); self.inner .validator .validate_version_specific_fields(EngineApiMessageVersion::V4, payload_or_attrs)?; - self.inner.validator.validate_execution_requests(&execution_requests)?; + if let Some(requests) = payload.sidecar.requests() { + self.inner.validator.validate_execution_requests(requests)?; + } + Ok(self .inner .beacon_consensus - .new_payload(ExecutionData { - payload, - sidecar: ExecutionPayloadSidecar::v4( - CancunPayloadFields { versioned_hashes, parent_beacon_block_root }, - PraguePayloadFields { requests: RequestsOrHash::Requests(execution_requests) }, - ), - }) + .new_payload(payload) .await .inspect(|_| self.inner.on_new_payload_response())?) } diff --git a/examples/custom-engine-types/src/main.rs b/examples/custom-engine-types/src/main.rs index efaa8de20..a487034d1 100644 --- a/examples/custom-engine-types/src/main.rs +++ b/examples/custom-engine-types/src/main.rs @@ -218,7 +218,7 @@ where fn validate_version_specific_fields( &self, version: EngineApiMessageVersion, - payload_or_attrs: PayloadOrAttributes<'_, T::PayloadAttributes>, + payload_or_attrs: PayloadOrAttributes<'_, Self::ExecutionData, T::PayloadAttributes>, ) -> Result<(), EngineObjectValidationError> { validate_version_specific_fields(self.chain_spec(), version, payload_or_attrs) } @@ -228,7 +228,13 @@ where version: EngineApiMessageVersion, attributes: &T::PayloadAttributes, ) -> Result<(), EngineObjectValidationError> { - validate_version_specific_fields(self.chain_spec(), version, attributes.into())?; + validate_version_specific_fields( + self.chain_spec(), + version, + PayloadOrAttributes::::PayloadAttributes( + attributes, + ), + )?; // custom validation logic - ensure that the custom field is not zero if attributes.custom == 0 {