Make PayloadOrAttributes generic over ExecutionData (#14666)

Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
This commit is contained in:
Yohann Kazoula
2025-02-24 10:50:39 +02:00
committed by GitHub
parent c72731e913
commit 33443de09a
7 changed files with 144 additions and 98 deletions

View File

@ -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<
<<Self::BuiltPayload as BuiltPayload>::Primitives as NodePrimitives>::Block,
@ -165,7 +138,11 @@ pub trait EngineValidator<Types: EngineTypes>:
fn validate_version_specific_fields(
&self,
version: EngineApiMessageVersion,
payload_or_attrs: PayloadOrAttributes<'_, <Types as PayloadTypes>::PayloadAttributes>,
payload_or_attrs: PayloadOrAttributes<
'_,
Types::ExecutionData,
<Types as PayloadTypes>::PayloadAttributes,
>,
) -> Result<(), EngineObjectValidationError>;
/// Ensures that the payload attributes are valid for the given [`EngineApiMessageVersion`].

View File

@ -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::<Self::ExecutionData, EthPayloadAttributes>::PayloadAttributes(
attributes,
),
)
}
}

View File

@ -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::<Self::ExecutionData, OpPayloadAttributes>::PayloadAttributes(
attributes,
),
)?;
if attributes.gas_limit.is_none() {
return Err(EngineObjectValidationError::InvalidParams(

View File

@ -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<Type, T>(
pub fn validate_version_specific_fields<Payload, Type, T>(
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,
{

View File

@ -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<Withdrawal>>;
/// Return the parent beacon block root for the payload, if it exists.
fn parent_beacon_block_root(&self) -> Option<B256>;
/// 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<Withdrawal>> {
self.payload.withdrawals()
}
fn parent_beacon_block_root(&self) -> Option<B256> {
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<B256>,
},
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<B256>,
) -> 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<Attributes> PayloadOrAttributes<'_, Attributes>
impl<Payload, Attributes> PayloadOrAttributes<'_, Payload, Attributes>
where
Payload: ExecutionPayload,
Attributes: PayloadAttributes,
{
/// Return the withdrawals for the payload or attributes.
pub fn withdrawals(&self) -> Option<&Vec<Withdrawal>> {
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<B256> {
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,
{

View File

@ -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<PayloadStatus> {
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<PayloadStatus> {
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<B256>,
parent_beacon_block_root: B256,
) -> EngineApiResult<PayloadStatus> {
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<PayloadStatus> {
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())?)
}