refactor: couple ExecutionPayload and ExecutionPayloadSidecar (#14172)

This commit is contained in:
Arsenii Kulikov
2025-02-04 01:04:42 +04:00
committed by GitHub
parent e3106889a8
commit 04c1d7120e
15 changed files with 155 additions and 113 deletions

1
Cargo.lock generated
View File

@ -8556,6 +8556,7 @@ version = "1.1.5"
dependencies = [ dependencies = [
"alloy-rpc-types", "alloy-rpc-types",
"reth-chainspec", "reth-chainspec",
"reth-engine-primitives",
"reth-primitives", "reth-primitives",
"reth-primitives-traits", "reth-primitives-traits",
] ]

View File

@ -208,13 +208,8 @@ where
let block = payload.block(); let block = payload.block();
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
let (payload, sidecar) = EngineT::block_to_payload(payload.block().clone()); let payload = EngineT::block_to_payload(payload.block().clone());
self.to_engine.send(BeaconEngineMessage::NewPayload { self.to_engine.send(BeaconEngineMessage::NewPayload { payload, tx })?;
payload,
// todo: prague support
sidecar,
tx,
})?;
let res = rx.await??; let res = rx.await??;

View File

@ -11,6 +11,7 @@
extern crate alloc; extern crate alloc;
use alloy_primitives::B256;
use reth_payload_primitives::{BuiltPayload, PayloadAttributes}; use reth_payload_primitives::{BuiltPayload, PayloadAttributes};
mod error; mod error;
@ -32,15 +33,61 @@ pub use event::*;
mod invalid_block_hook; mod invalid_block_hook;
pub use invalid_block_hook::InvalidBlockHook; pub use invalid_block_hook::InvalidBlockHook;
use alloy_eips::{eip7685::Requests, Decodable2718};
use reth_payload_primitives::{ use reth_payload_primitives::{
validate_execution_requests, EngineApiMessageVersion, EngineObjectValidationError, validate_execution_requests, EngineApiMessageVersion, EngineObjectValidationError,
InvalidPayloadAttributesError, PayloadOrAttributes, PayloadTypes, InvalidPayloadAttributesError, PayloadOrAttributes, PayloadTypes,
}; };
use reth_primitives::{NodePrimitives, SealedBlock}; use reth_primitives::{NodePrimitives, SealedBlock};
use reth_primitives_traits::Block; use reth_primitives_traits::Block;
use serde::{de::DeserializeOwned, ser::Serialize}; use serde::{de::DeserializeOwned, Deserialize, Serialize};
use alloy_eips::eip7685::Requests; /// Struct aggregating [`ExecutionPayload`] and [`ExecutionPayloadSidecar`] and encapsulating
/// complete payload supplied for execution.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ExecutionData {
/// Execution payload.
pub payload: ExecutionPayload,
/// Additional fork-specific fields.
pub sidecar: ExecutionPayloadSidecar,
}
impl ExecutionData {
/// Creates new instance of [`ExecutionData`].
pub const fn new(payload: ExecutionPayload, sidecar: ExecutionPayloadSidecar) -> Self {
Self { payload, sidecar }
}
/// Returns the parent hash of the block.
pub fn parent_hash(&self) -> B256 {
self.payload.parent_hash()
}
/// Returns the hash of the block.
pub fn block_hash(&self) -> B256 {
self.payload.block_hash()
}
/// Returns the number of the block.
pub fn block_number(&self) -> u64 {
self.payload.block_number()
}
/// Tries to create a new unsealed block from the given payload and payload sidecar.
///
/// Performs additional validation of `extra_data` and `base_fee_per_gas` fields.
///
/// # Note
///
/// The log bloom is assumed to be validated during serialization.
///
/// See <https://github.com/ethereum/go-ethereum/blob/79a478bb6176425c2400e949890e668a3d9a3d05/core/beacon/types.go#L145>
pub fn try_into_block<T: Decodable2718>(
self,
) -> Result<alloy_consensus::Block<T>, PayloadError> {
self.payload.try_into_block_with_sidecar(&self.sidecar)
}
}
/// This type defines the versioned types of the engine API. /// This type defines the versioned types of the engine API.
/// ///
@ -94,7 +141,7 @@ pub trait EngineTypes:
block: SealedBlock< block: SealedBlock<
<<Self::BuiltPayload as BuiltPayload>::Primitives as NodePrimitives>::Block, <<Self::BuiltPayload as BuiltPayload>::Primitives as NodePrimitives>::Block,
>, >,
) -> (ExecutionPayload, ExecutionPayloadSidecar); ) -> ExecutionData;
} }
/// Type that validates an [`ExecutionPayload`]. /// Type that validates an [`ExecutionPayload`].
@ -112,8 +159,7 @@ pub trait PayloadValidator: fmt::Debug + Send + Sync + Unpin + 'static {
/// engine-API specification. /// engine-API specification.
fn ensure_well_formed_payload( fn ensure_well_formed_payload(
&self, &self,
payload: ExecutionPayload, payload: ExecutionData,
sidecar: ExecutionPayloadSidecar,
) -> Result<SealedBlock<Self::Block>, PayloadError>; ) -> Result<SealedBlock<Self::Block>, PayloadError>;
} }

View File

@ -1,10 +1,10 @@
use crate::{ use crate::{
error::BeaconForkChoiceUpdateError, BeaconOnNewPayloadError, EngineApiMessageVersion, error::BeaconForkChoiceUpdateError, BeaconOnNewPayloadError, EngineApiMessageVersion,
EngineTypes, ForkchoiceStatus, EngineTypes, ExecutionData, ForkchoiceStatus,
}; };
use alloy_rpc_types_engine::{ use alloy_rpc_types_engine::{
ExecutionPayload, ExecutionPayloadSidecar, ForkChoiceUpdateResult, ForkchoiceState, ForkChoiceUpdateResult, ForkchoiceState, ForkchoiceUpdateError, ForkchoiceUpdated, PayloadId,
ForkchoiceUpdateError, ForkchoiceUpdated, PayloadId, PayloadStatus, PayloadStatusEnum, PayloadStatus, PayloadStatusEnum,
}; };
use core::{ use core::{
fmt::{self, Display}, fmt::{self, Display},
@ -145,10 +145,7 @@ pub enum BeaconEngineMessage<Engine: EngineTypes> {
/// Message with new payload. /// Message with new payload.
NewPayload { NewPayload {
/// The execution payload received by Engine API. /// The execution payload received by Engine API.
payload: ExecutionPayload, payload: ExecutionData,
/// The execution payload sidecar with additional version-specific fields received by
/// engine API.
sidecar: ExecutionPayloadSidecar,
/// The sender for returning payload status result. /// The sender for returning payload status result.
tx: oneshot::Sender<Result<PayloadStatus, BeaconOnNewPayloadError>>, tx: oneshot::Sender<Result<PayloadStatus, BeaconOnNewPayloadError>>,
}, },
@ -220,11 +217,10 @@ where
/// See also <https://github.com/ethereum/execution-apis/blob/3d627c95a4d3510a8187dd02e0250ecb4331d27e/src/engine/shanghai.md#engine_newpayloadv2> /// See also <https://github.com/ethereum/execution-apis/blob/3d627c95a4d3510a8187dd02e0250ecb4331d27e/src/engine/shanghai.md#engine_newpayloadv2>
pub async fn new_payload( pub async fn new_payload(
&self, &self,
payload: ExecutionPayload, payload: ExecutionData,
sidecar: ExecutionPayloadSidecar,
) -> Result<PayloadStatus, BeaconOnNewPayloadError> { ) -> Result<PayloadStatus, BeaconOnNewPayloadError> {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
let _ = self.to_engine.send(BeaconEngineMessage::NewPayload { payload, sidecar, tx }); let _ = self.to_engine.send(BeaconEngineMessage::NewPayload { payload, tx });
rx.await.map_err(|_| BeaconOnNewPayloadError::EngineUnavailable)? rx.await.map_err(|_| BeaconOnNewPayloadError::EngineUnavailable)?
} }

View File

@ -15,8 +15,7 @@ use alloy_primitives::{
BlockNumber, B256, U256, BlockNumber, B256, U256,
}; };
use alloy_rpc_types_engine::{ use alloy_rpc_types_engine::{
ExecutionPayload, ExecutionPayloadSidecar, ForkchoiceState, PayloadStatus, PayloadStatusEnum, ForkchoiceState, PayloadStatus, PayloadStatusEnum, PayloadValidationError,
PayloadValidationError,
}; };
use block_buffer::BlockBuffer; use block_buffer::BlockBuffer;
use error::{InsertBlockError, InsertBlockErrorKind, InsertBlockFatalError}; use error::{InsertBlockError, InsertBlockErrorKind, InsertBlockFatalError};
@ -29,7 +28,7 @@ use reth_consensus::{Consensus, FullConsensus, PostExecutionInput};
pub use reth_engine_primitives::InvalidBlockHook; pub use reth_engine_primitives::InvalidBlockHook;
use reth_engine_primitives::{ use reth_engine_primitives::{
BeaconConsensusEngineEvent, BeaconEngineMessage, BeaconOnNewPayloadError, EngineTypes, BeaconConsensusEngineEvent, BeaconEngineMessage, BeaconOnNewPayloadError, EngineTypes,
EngineValidator, ForkchoiceStateTracker, OnForkChoiceUpdated, EngineValidator, ExecutionData, ForkchoiceStateTracker, OnForkChoiceUpdated,
}; };
use reth_errors::{ConsensusError, ProviderResult}; use reth_errors::{ConsensusError, ProviderResult};
use reth_ethereum_primitives::EthPrimitives; use reth_ethereum_primitives::EthPrimitives;
@ -791,7 +790,7 @@ where
/// When the Consensus layer receives a new block via the consensus gossip protocol, /// When the Consensus layer receives a new block via the consensus gossip protocol,
/// the transactions in the block are sent to the execution layer in the form of a /// the transactions in the block are sent to the execution layer in the form of a
/// [`ExecutionPayload`]. The Execution layer executes the transactions and validates the /// [`ExecutionData`]. The Execution layer executes the transactions and validates the
/// state in the block header, then passes validation data back to Consensus layer, that /// state in the block header, then passes validation data back to Consensus layer, that
/// adds the block to the head of its own blockchain and attests to it. The block is then /// adds the block to the head of its own blockchain and attests to it. The block is then
/// broadcast over the consensus p2p network in the form of a "Beacon block". /// broadcast over the consensus p2p network in the form of a "Beacon block".
@ -804,8 +803,7 @@ where
#[instrument(level = "trace", skip_all, fields(block_hash = %payload.block_hash(), block_num = %payload.block_number(),), target = "engine::tree")] #[instrument(level = "trace", skip_all, fields(block_hash = %payload.block_hash(), block_num = %payload.block_number(),), target = "engine::tree")]
fn on_new_payload( fn on_new_payload(
&mut self, &mut self,
payload: ExecutionPayload, payload: ExecutionData,
sidecar: ExecutionPayloadSidecar,
) -> Result<TreeOutcome<PayloadStatus>, InsertBlockFatalError> { ) -> Result<TreeOutcome<PayloadStatus>, InsertBlockFatalError> {
trace!(target: "engine::tree", "invoked new payload"); trace!(target: "engine::tree", "invoked new payload");
self.metrics.engine.new_payload_messages.increment(1); self.metrics.engine.new_payload_messages.increment(1);
@ -836,7 +834,7 @@ where
// //
// This validation **MUST** be instantly run in all cases even during active sync process. // This validation **MUST** be instantly run in all cases even during active sync process.
let parent_hash = payload.parent_hash(); let parent_hash = payload.parent_hash();
let block = match self.payload_validator.ensure_well_formed_payload(payload, sidecar) { let block = match self.payload_validator.ensure_well_formed_payload(payload) {
Ok(block) => block, Ok(block) => block,
Err(error) => { Err(error) => {
error!(target: "engine::tree", %error, "Invalid payload"); error!(target: "engine::tree", %error, "Invalid payload");
@ -1392,8 +1390,8 @@ where
error!(target: "engine::tree", "Failed to send event: {err:?}"); error!(target: "engine::tree", "Failed to send event: {err:?}");
} }
} }
BeaconEngineMessage::NewPayload { payload, sidecar, tx } => { BeaconEngineMessage::NewPayload { payload, tx } => {
let output = self.on_new_payload(payload, sidecar); let output = self.on_new_payload(payload);
if let Err(err) = if let Err(err) =
tx.send(output.map(|o| o.outcome).map_err(|e| { tx.send(output.map(|o| o.outcome).map_err(|e| {
BeaconOnNewPayloadError::Internal(Box::new(e)) BeaconOnNewPayloadError::Internal(Box::new(e))
@ -3207,13 +3205,13 @@ mod tests {
&block.clone_sealed_block().into_block(), &block.clone_sealed_block().into_block(),
); );
self.tree self.tree
.on_new_payload( .on_new_payload(ExecutionData {
payload.into(), payload: payload.into(),
ExecutionPayloadSidecar::v3(CancunPayloadFields { sidecar: ExecutionPayloadSidecar::v3(CancunPayloadFields {
parent_beacon_block_root: block.parent_beacon_block_root.unwrap(), parent_beacon_block_root: block.parent_beacon_block_root.unwrap(),
versioned_hashes: vec![], versioned_hashes: vec![],
}), }),
) })
.unwrap(); .unwrap();
} }
@ -3478,7 +3476,10 @@ mod tests {
let outcome = test_harness let outcome = test_harness
.tree .tree
.on_new_payload(payload.into(), ExecutionPayloadSidecar::none()) .on_new_payload(ExecutionData {
payload: payload.into(),
sidecar: ExecutionPayloadSidecar::none(),
})
.unwrap(); .unwrap();
assert!(outcome.outcome.is_syncing()); assert!(outcome.outcome.is_syncing());
@ -3523,8 +3524,10 @@ mod tests {
.tree .tree
.on_engine_message(FromEngine::Request( .on_engine_message(FromEngine::Request(
BeaconEngineMessage::NewPayload { BeaconEngineMessage::NewPayload {
payload: payload.clone().into(), payload: ExecutionData {
sidecar: ExecutionPayloadSidecar::none(), payload: payload.clone().into(),
sidecar: ExecutionPayloadSidecar::none(),
},
tx, tx,
} }
.into(), .into(),

View File

@ -1,8 +1,8 @@
//! Stores engine API messages to disk for later inspection and replay. //! Stores engine API messages to disk for later inspection and replay.
use alloy_rpc_types_engine::{ExecutionPayload, ExecutionPayloadSidecar, ForkchoiceState}; use alloy_rpc_types_engine::ForkchoiceState;
use futures::{Stream, StreamExt}; use futures::{Stream, StreamExt};
use reth_engine_primitives::{BeaconEngineMessage, EngineTypes}; use reth_engine_primitives::{BeaconEngineMessage, EngineTypes, ExecutionData};
use reth_fs_util as fs; use reth_fs_util as fs;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{ use std::{
@ -27,11 +27,9 @@ pub enum StoredEngineApiMessage<Attributes> {
}, },
/// The on-disk representation of an `engine_newPayload` method call. /// The on-disk representation of an `engine_newPayload` method call.
NewPayload { NewPayload {
/// The [`ExecutionPayload`] sent in the persisted call. /// The [`ExecutionData`] sent in the persisted call.
payload: ExecutionPayload, #[serde(flatten)]
/// The execution payload sidecar with additional version-specific fields received by payload: ExecutionData,
/// engine API.
sidecar: ExecutionPayloadSidecar,
}, },
} }
@ -78,14 +76,13 @@ impl EngineMessageStore {
})?, })?,
)?; )?;
} }
BeaconEngineMessage::NewPayload { payload, sidecar, tx: _tx } => { BeaconEngineMessage::NewPayload { payload, tx: _tx } => {
let filename = format!("{}-new_payload-{}.json", timestamp, payload.block_hash()); let filename = format!("{}-new_payload-{}.json", timestamp, payload.block_hash());
fs::write( fs::write(
self.path.join(filename), self.path.join(filename),
serde_json::to_vec( serde_json::to_vec(
&StoredEngineApiMessage::<Engine::PayloadAttributes>::NewPayload { &StoredEngineApiMessage::<Engine::PayloadAttributes>::NewPayload {
payload: payload.clone(), payload: payload.clone(),
sidecar: sidecar.clone(),
}, },
)?, )?,
)?; )?;

View File

@ -8,7 +8,7 @@ use futures::{stream::FuturesUnordered, Stream, StreamExt, TryFutureExt};
use itertools::Either; use itertools::Either;
use reth_chainspec::EthChainSpec; use reth_chainspec::EthChainSpec;
use reth_engine_primitives::{ use reth_engine_primitives::{
BeaconEngineMessage, BeaconOnNewPayloadError, EngineTypes, OnForkChoiceUpdated, BeaconEngineMessage, BeaconOnNewPayloadError, EngineTypes, ExecutionData, OnForkChoiceUpdated,
}; };
use reth_errors::{BlockExecutionError, BlockValidationError, RethError, RethResult}; use reth_errors::{BlockExecutionError, BlockValidationError, RethError, RethResult};
use reth_ethereum_forks::EthereumHardforks; use reth_ethereum_forks::EthereumHardforks;
@ -147,7 +147,7 @@ where
let next = ready!(this.stream.poll_next_unpin(cx)); let next = ready!(this.stream.poll_next_unpin(cx));
let item = match (next, &this.last_forkchoice_state) { let item = match (next, &this.last_forkchoice_state) {
( (
Some(BeaconEngineMessage::NewPayload { payload, sidecar, tx }), Some(BeaconEngineMessage::NewPayload { payload, tx }),
Some(last_forkchoice_state), Some(last_forkchoice_state),
) if this.forkchoice_states_forwarded > this.frequency && ) if this.forkchoice_states_forwarded > this.frequency &&
// Only enter reorg state if new payload attaches to current head. // Only enter reorg state if new payload attaches to current head.
@ -162,13 +162,12 @@ where
// forkchoice state. We will rely on CL to reorg us back to canonical chain. // forkchoice state. We will rely on CL to reorg us back to canonical chain.
// TODO: This is an expensive blocking operation, ideally it's spawned as a task // TODO: This is an expensive blocking operation, ideally it's spawned as a task
// so that the stream could yield the control back. // so that the stream could yield the control back.
let (reorg_payload, reorg_sidecar) = match create_reorg_head( let reorg_payload = match create_reorg_head(
this.provider, this.provider,
this.evm_config, this.evm_config,
this.payload_validator, this.payload_validator,
*this.depth, *this.depth,
payload.clone(), payload.clone(),
sidecar.clone(),
) { ) {
Ok(result) => result, Ok(result) => result,
Err(error) => { Err(error) => {
@ -177,7 +176,6 @@ where
// the next one // the next one
return Poll::Ready(Some(BeaconEngineMessage::NewPayload { return Poll::Ready(Some(BeaconEngineMessage::NewPayload {
payload, payload,
sidecar,
tx, tx,
})) }))
} }
@ -197,11 +195,10 @@ where
let queue = VecDeque::from([ let queue = VecDeque::from([
// Current payload // Current payload
BeaconEngineMessage::NewPayload { payload, sidecar, tx }, BeaconEngineMessage::NewPayload { payload, tx },
// Reorg payload // Reorg payload
BeaconEngineMessage::NewPayload { BeaconEngineMessage::NewPayload {
payload: reorg_payload, payload: reorg_payload,
sidecar: reorg_sidecar,
tx: reorg_payload_tx, tx: reorg_payload_tx,
}, },
// Reorg forkchoice state // Reorg forkchoice state
@ -248,9 +245,8 @@ fn create_reorg_head<Provider, Evm, Spec>(
evm_config: &Evm, evm_config: &Evm,
payload_validator: &ExecutionPayloadValidator<Spec>, payload_validator: &ExecutionPayloadValidator<Spec>,
mut depth: usize, mut depth: usize,
next_payload: ExecutionPayload, next_payload: ExecutionData,
next_sidecar: ExecutionPayloadSidecar, ) -> RethResult<ExecutionData>
) -> RethResult<(ExecutionPayload, ExecutionPayloadSidecar)>
where where
Provider: BlockReader<Block = reth_primitives::Block> + StateProviderFactory, Provider: BlockReader<Block = reth_primitives::Block> + StateProviderFactory,
Evm: ConfigureEvm<Header = Header, Transaction = reth_primitives::TransactionSigned>, Evm: ConfigureEvm<Header = Header, Transaction = reth_primitives::TransactionSigned>,
@ -259,9 +255,8 @@ where
let chain_spec = payload_validator.chain_spec(); let chain_spec = payload_validator.chain_spec();
// Ensure next payload is valid. // Ensure next payload is valid.
let next_block = payload_validator let next_block =
.ensure_well_formed_payload(next_payload, next_sidecar) payload_validator.ensure_well_formed_payload(next_payload).map_err(RethError::msg)?;
.map_err(RethError::msg)?;
// Fetch reorg target block depending on its depth and its parent. // Fetch reorg target block depending on its depth and its parent.
let mut previous_hash = next_block.parent_hash; let mut previous_hash = next_block.parent_hash;
@ -419,10 +414,14 @@ where
} }
.seal_slow(); .seal_slow();
Ok(( Ok(ExecutionData {
ExecutionPayload::from_block_unchecked(reorg_block.hash(), &reorg_block.into_block()).0, payload: ExecutionPayload::from_block_unchecked(
reorg_block.hash(),
&reorg_block.into_block(),
)
.0,
// todo(onbjerg): how do we support execution requests? // todo(onbjerg): how do we support execution requests?
reorg_target sidecar: reorg_target
.header .header
.parent_beacon_block_root .parent_beacon_block_root
.map(|root| { .map(|root| {
@ -432,5 +431,5 @@ where
}) })
}) })
.unwrap_or_else(ExecutionPayloadSidecar::none), .unwrap_or_else(ExecutionPayloadSidecar::none),
)) })
} }

View File

@ -40,14 +40,14 @@ where
loop { loop {
let next = ready!(this.stream.poll_next_unpin(cx)); let next = ready!(this.stream.poll_next_unpin(cx));
let item = match next { let item = match next {
Some(BeaconEngineMessage::NewPayload { payload, sidecar, tx }) => { Some(BeaconEngineMessage::NewPayload { payload, tx }) => {
if this.skipped < this.threshold { if this.skipped < this.threshold {
*this.skipped += 1; *this.skipped += 1;
tracing::warn!( tracing::warn!(
target: "engine::stream::skip_new_payload", target: "engine::stream::skip_new_payload",
block_number = payload.block_number(), block_number = payload.block_number(),
block_hash = %payload.block_hash(), block_hash = %payload.block_hash(),
?sidecar, ?payload,
threshold=this.threshold, threshold=this.threshold,
skipped=this.skipped, "Skipping new payload" skipped=this.skipped, "Skipping new payload"
); );
@ -55,7 +55,7 @@ where
continue continue
} }
*this.skipped = 0; *this.skipped = 0;
Some(BeaconEngineMessage::NewPayload { payload, sidecar, tx }) Some(BeaconEngineMessage::NewPayload { payload, tx })
} }
next => next, next => next,
}; };

View File

@ -13,14 +13,14 @@ extern crate alloc;
mod payload; mod payload;
use alloc::sync::Arc; use alloc::sync::Arc;
use alloy_rpc_types_engine::{ExecutionPayload, ExecutionPayloadSidecar, PayloadError}; use alloy_rpc_types_engine::{ExecutionPayload, PayloadError};
pub use alloy_rpc_types_engine::{ pub use alloy_rpc_types_engine::{
ExecutionPayloadEnvelopeV2, ExecutionPayloadEnvelopeV3, ExecutionPayloadEnvelopeV4, ExecutionPayloadEnvelopeV2, ExecutionPayloadEnvelopeV3, ExecutionPayloadEnvelopeV4,
ExecutionPayloadV1, PayloadAttributes as EthPayloadAttributes, ExecutionPayloadV1, PayloadAttributes as EthPayloadAttributes,
}; };
pub use payload::{EthBuiltPayload, EthPayloadBuilderAttributes}; pub use payload::{EthBuiltPayload, EthPayloadBuilderAttributes};
use reth_chainspec::ChainSpec; use reth_chainspec::ChainSpec;
use reth_engine_primitives::{EngineTypes, EngineValidator, PayloadValidator}; use reth_engine_primitives::{EngineTypes, EngineValidator, ExecutionData, PayloadValidator};
use reth_payload_primitives::{ use reth_payload_primitives::{
validate_version_specific_fields, BuiltPayload, EngineApiMessageVersion, validate_version_specific_fields, BuiltPayload, EngineApiMessageVersion,
EngineObjectValidationError, PayloadOrAttributes, PayloadTypes, EngineObjectValidationError, PayloadOrAttributes, PayloadTypes,
@ -59,8 +59,10 @@ where
block: SealedBlock< block: SealedBlock<
<<Self::BuiltPayload as BuiltPayload>::Primitives as NodePrimitives>::Block, <<Self::BuiltPayload as BuiltPayload>::Primitives as NodePrimitives>::Block,
>, >,
) -> (ExecutionPayload, ExecutionPayloadSidecar) { ) -> ExecutionData {
ExecutionPayload::from_block_unchecked(block.hash(), &block.into_block()) let (payload, sidecar) =
ExecutionPayload::from_block_unchecked(block.hash(), &block.into_block());
ExecutionData { payload, sidecar }
} }
} }
@ -99,10 +101,9 @@ impl PayloadValidator for EthereumEngineValidator {
fn ensure_well_formed_payload( fn ensure_well_formed_payload(
&self, &self,
payload: ExecutionPayload, payload: ExecutionData,
sidecar: ExecutionPayloadSidecar,
) -> Result<SealedBlock, PayloadError> { ) -> Result<SealedBlock, PayloadError> {
self.inner.ensure_well_formed_payload(payload, sidecar) self.inner.ensure_well_formed_payload(payload)
} }
} }

View File

@ -1,6 +1,5 @@
use alloy_rpc_types_engine::{ use alloy_rpc_types_engine::{
ExecutionPayload, ExecutionPayloadEnvelopeV2, ExecutionPayloadSidecar, ExecutionPayloadV1, ExecutionPayload, ExecutionPayloadEnvelopeV2, ExecutionPayloadV1, PayloadError,
PayloadError,
}; };
use op_alloy_rpc_types_engine::{ use op_alloy_rpc_types_engine::{
OpExecutionPayloadEnvelopeV3, OpExecutionPayloadEnvelopeV4, OpPayloadAttributes, OpExecutionPayloadEnvelopeV3, OpExecutionPayloadEnvelopeV4, OpPayloadAttributes,
@ -12,8 +11,8 @@ use reth_node_api::{
EngineObjectValidationError, MessageValidationKind, PayloadOrAttributes, PayloadTypes, EngineObjectValidationError, MessageValidationKind, PayloadOrAttributes, PayloadTypes,
VersionSpecificValidationError, VersionSpecificValidationError,
}, },
validate_version_specific_fields, BuiltPayload, EngineTypes, EngineValidator, NodePrimitives, validate_version_specific_fields, BuiltPayload, EngineTypes, EngineValidator, ExecutionData,
PayloadValidator, NodePrimitives, PayloadValidator,
}; };
use reth_optimism_chainspec::OpChainSpec; use reth_optimism_chainspec::OpChainSpec;
use reth_optimism_forks::{OpHardfork, OpHardforks}; use reth_optimism_forks::{OpHardfork, OpHardforks};
@ -53,8 +52,10 @@ where
block: SealedBlock< block: SealedBlock<
<<Self::BuiltPayload as BuiltPayload>::Primitives as NodePrimitives>::Block, <<Self::BuiltPayload as BuiltPayload>::Primitives as NodePrimitives>::Block,
>, >,
) -> (ExecutionPayload, ExecutionPayloadSidecar) { ) -> ExecutionData {
ExecutionPayload::from_block_unchecked(block.hash(), &block.into_block()) let (payload, sidecar) =
ExecutionPayload::from_block_unchecked(block.hash(), &block.into_block());
ExecutionData { payload, sidecar }
} }
} }
@ -93,10 +94,9 @@ impl PayloadValidator for OpEngineValidator {
fn ensure_well_formed_payload( fn ensure_well_formed_payload(
&self, &self,
payload: ExecutionPayload, payload: ExecutionData,
sidecar: ExecutionPayloadSidecar,
) -> Result<SealedBlock<Self::Block>, PayloadError> { ) -> Result<SealedBlock<Self::Block>, PayloadError> {
self.inner.ensure_well_formed_payload(payload, sidecar) self.inner.ensure_well_formed_payload(payload)
} }
} }

View File

@ -16,6 +16,7 @@ workspace = true
reth-chainspec.workspace = true reth-chainspec.workspace = true
reth-primitives.workspace = true reth-primitives.workspace = true
reth-primitives-traits.workspace = true reth-primitives-traits.workspace = true
reth-engine-primitives.workspace = true
# alloy # alloy
alloy-rpc-types = { workspace = true, features = ["engine"] } alloy-rpc-types = { workspace = true, features = ["engine"] }

View File

@ -8,10 +8,9 @@
#![cfg_attr(not(test), warn(unused_crate_dependencies))] #![cfg_attr(not(test), warn(unused_crate_dependencies))]
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
use alloy_rpc_types::engine::{ use alloy_rpc_types::engine::{MaybeCancunPayloadFields, PayloadError};
ExecutionPayload, ExecutionPayloadSidecar, MaybeCancunPayloadFields, PayloadError,
};
use reth_chainspec::EthereumHardforks; use reth_chainspec::EthereumHardforks;
use reth_engine_primitives::ExecutionData;
use reth_primitives::SealedBlock; use reth_primitives::SealedBlock;
use reth_primitives_traits::{Block, SignedTransaction}; use reth_primitives_traits::{Block, SignedTransaction};
use std::sync::Arc; use std::sync::Arc;
@ -114,11 +113,12 @@ impl<ChainSpec: EthereumHardforks> ExecutionPayloadValidator<ChainSpec> {
/// <https://github.com/ethereum/execution-apis/blob/fe8e13c288c592ec154ce25c534e26cb7ce0530d/src/engine/cancun.md#specification> /// <https://github.com/ethereum/execution-apis/blob/fe8e13c288c592ec154ce25c534e26cb7ce0530d/src/engine/cancun.md#specification>
pub fn ensure_well_formed_payload<T: SignedTransaction>( pub fn ensure_well_formed_payload<T: SignedTransaction>(
&self, &self,
payload: ExecutionPayload, payload: ExecutionData,
sidecar: ExecutionPayloadSidecar,
) -> Result<SealedBlock<reth_primitives::Block<T>>, PayloadError> { ) -> Result<SealedBlock<reth_primitives::Block<T>>, PayloadError> {
let expected_hash = payload.block_hash(); let expected_hash = payload.block_hash();
let ExecutionData { payload, sidecar } = payload;
// First parse the block // First parse the block
let sealed_block = payload.try_into_block_with_sidecar(&sidecar)?.seal_slow(); let sealed_block = payload.try_into_block_with_sidecar(&sidecar)?.seal_slow();

View File

@ -17,7 +17,9 @@ use async_trait::async_trait;
use jsonrpsee_core::RpcResult; use jsonrpsee_core::RpcResult;
use parking_lot::Mutex; use parking_lot::Mutex;
use reth_chainspec::{EthereumHardfork, EthereumHardforks}; use reth_chainspec::{EthereumHardfork, EthereumHardforks};
use reth_engine_primitives::{BeaconConsensusEngineHandle, EngineTypes, EngineValidator}; use reth_engine_primitives::{
BeaconConsensusEngineHandle, EngineTypes, EngineValidator, ExecutionData,
};
use reth_payload_builder::PayloadStore; use reth_payload_builder::PayloadStore;
use reth_payload_primitives::{ use reth_payload_primitives::{
validate_payload_timestamp, EngineApiMessageVersion, PayloadBuilderAttributes, validate_payload_timestamp, EngineApiMessageVersion, PayloadBuilderAttributes,
@ -148,7 +150,7 @@ where
Ok(self Ok(self
.inner .inner
.beacon_consensus .beacon_consensus
.new_payload(payload, ExecutionPayloadSidecar::none()) .new_payload(ExecutionData { payload, sidecar: ExecutionPayloadSidecar::none() })
.await .await
.inspect(|_| self.inner.on_new_payload_response())?) .inspect(|_| self.inner.on_new_payload_response())?)
} }
@ -183,7 +185,7 @@ where
Ok(self Ok(self
.inner .inner
.beacon_consensus .beacon_consensus
.new_payload(payload, ExecutionPayloadSidecar::none()) .new_payload(ExecutionData { payload, sidecar: ExecutionPayloadSidecar::none() })
.await .await
.inspect(|_| self.inner.on_new_payload_response())?) .inspect(|_| self.inner.on_new_payload_response())?)
} }
@ -222,13 +224,13 @@ where
Ok(self Ok(self
.inner .inner
.beacon_consensus .beacon_consensus
.new_payload( .new_payload(ExecutionData {
payload, payload,
ExecutionPayloadSidecar::v3(CancunPayloadFields { sidecar: ExecutionPayloadSidecar::v3(CancunPayloadFields {
versioned_hashes, versioned_hashes,
parent_beacon_block_root, parent_beacon_block_root,
}), }),
) })
.await .await
.inspect(|_| self.inner.on_new_payload_response())?) .inspect(|_| self.inner.on_new_payload_response())?)
} }
@ -272,13 +274,13 @@ where
Ok(self Ok(self
.inner .inner
.beacon_consensus .beacon_consensus
.new_payload( .new_payload(ExecutionData {
payload, payload,
ExecutionPayloadSidecar::v4( sidecar: ExecutionPayloadSidecar::v4(
CancunPayloadFields { versioned_hashes, parent_beacon_block_root }, CancunPayloadFields { versioned_hashes, parent_beacon_block_root },
PraguePayloadFields { requests: RequestsOrHash::Requests(execution_requests) }, PraguePayloadFields { requests: RequestsOrHash::Requests(execution_requests) },
), ),
) })
.await .await
.inspect(|_| self.inner.on_new_payload_response())?) .inspect(|_| self.inner.on_new_payload_response())?)
} }

View File

@ -14,7 +14,7 @@ use async_trait::async_trait;
use jsonrpsee::core::RpcResult; use jsonrpsee::core::RpcResult;
use reth_chainspec::{ChainSpecProvider, EthereumHardforks}; use reth_chainspec::{ChainSpecProvider, EthereumHardforks};
use reth_consensus::{Consensus, FullConsensus, PostExecutionInput}; use reth_consensus::{Consensus, FullConsensus, PostExecutionInput};
use reth_engine_primitives::PayloadValidator; use reth_engine_primitives::{ExecutionData, PayloadValidator};
use reth_errors::{BlockExecutionError, ConsensusError, ProviderError}; use reth_errors::{BlockExecutionError, ConsensusError, ProviderError};
use reth_evm::execute::{BlockExecutorProvider, Executor}; use reth_evm::execute::{BlockExecutorProvider, Executor};
use reth_metrics::{metrics, metrics::Gauge, Metrics}; use reth_metrics::{metrics, metrics::Gauge, Metrics};
@ -348,13 +348,13 @@ where
) -> Result<(), ValidationApiError> { ) -> Result<(), ValidationApiError> {
let block = self let block = self
.payload_validator .payload_validator
.ensure_well_formed_payload( .ensure_well_formed_payload(ExecutionData {
ExecutionPayload::V3(request.request.execution_payload), payload: ExecutionPayload::V3(request.request.execution_payload),
ExecutionPayloadSidecar::v3(CancunPayloadFields { sidecar: ExecutionPayloadSidecar::v3(CancunPayloadFields {
parent_beacon_block_root: request.parent_beacon_block_root, parent_beacon_block_root: request.parent_beacon_block_root,
versioned_hashes: self.validate_blobs_bundle(request.request.blobs_bundle)?, versioned_hashes: self.validate_blobs_bundle(request.request.blobs_bundle)?,
}), }),
)? })?
.try_recover() .try_recover()
.map_err(|_| ValidationApiError::InvalidTransactionSignature)?; .map_err(|_| ValidationApiError::InvalidTransactionSignature)?;
@ -373,9 +373,9 @@ where
) -> Result<(), ValidationApiError> { ) -> Result<(), ValidationApiError> {
let block = self let block = self
.payload_validator .payload_validator
.ensure_well_formed_payload( .ensure_well_formed_payload(ExecutionData {
ExecutionPayload::V3(request.request.execution_payload), payload: ExecutionPayload::V3(request.request.execution_payload),
ExecutionPayloadSidecar::v4( sidecar: ExecutionPayloadSidecar::v4(
CancunPayloadFields { CancunPayloadFields {
parent_beacon_block_root: request.parent_beacon_block_root, parent_beacon_block_root: request.parent_beacon_block_root,
versioned_hashes: self versioned_hashes: self
@ -387,7 +387,7 @@ where
), ),
}, },
), ),
)? })?
.try_recover() .try_recover()
.map_err(|_| ValidationApiError::InvalidTransactionSignature)?; .map_err(|_| ValidationApiError::InvalidTransactionSignature)?;

View File

@ -42,7 +42,7 @@ use reth::{
providers::{CanonStateSubscriptions, EthStorage, StateProviderFactory}, providers::{CanonStateSubscriptions, EthStorage, StateProviderFactory},
rpc::{ rpc::{
eth::EthApi, eth::EthApi,
types::engine::{ExecutionPayload, ExecutionPayloadSidecar, PayloadError}, types::engine::{ExecutionPayload, PayloadError},
}, },
tasks::TaskManager, tasks::TaskManager,
transaction_pool::{PoolTransaction, TransactionPool}, transaction_pool::{PoolTransaction, TransactionPool},
@ -57,7 +57,7 @@ use reth_engine_local::payload::UnsupportedLocalAttributes;
use reth_ethereum_payload_builder::EthereumBuilderConfig; use reth_ethereum_payload_builder::EthereumBuilderConfig;
use reth_node_api::{ use reth_node_api::{
payload::{EngineApiMessageVersion, EngineObjectValidationError, PayloadOrAttributes}, payload::{EngineApiMessageVersion, EngineObjectValidationError, PayloadOrAttributes},
validate_version_specific_fields, AddOnsContext, EngineTypes, EngineValidator, validate_version_specific_fields, AddOnsContext, EngineTypes, EngineValidator, ExecutionData,
FullNodeComponents, PayloadAttributes, PayloadBuilderAttributes, PayloadValidator, FullNodeComponents, PayloadAttributes, PayloadBuilderAttributes, PayloadValidator,
}; };
use reth_node_core::{args::RpcServerArgs, node_config::NodeConfig}; use reth_node_core::{args::RpcServerArgs, node_config::NodeConfig};
@ -179,8 +179,10 @@ impl EngineTypes for CustomEngineTypes {
block: SealedBlock< block: SealedBlock<
<<Self::BuiltPayload as reth_node_api::BuiltPayload>::Primitives as reth_node_api::NodePrimitives>::Block, <<Self::BuiltPayload as reth_node_api::BuiltPayload>::Primitives as reth_node_api::NodePrimitives>::Block,
>, >,
) -> (ExecutionPayload, ExecutionPayloadSidecar) { ) -> ExecutionData {
ExecutionPayload::from_block_unchecked(block.hash(), &block.into_block()) let (payload, sidecar) =
ExecutionPayload::from_block_unchecked(block.hash(), &block.into_block());
ExecutionData { payload, sidecar }
} }
} }
@ -208,10 +210,9 @@ impl PayloadValidator for CustomEngineValidator {
fn ensure_well_formed_payload( fn ensure_well_formed_payload(
&self, &self,
payload: ExecutionPayload, payload: ExecutionData,
sidecar: ExecutionPayloadSidecar,
) -> Result<SealedBlock<Self::Block>, PayloadError> { ) -> Result<SealedBlock<Self::Block>, PayloadError> {
self.inner.ensure_well_formed_payload(payload, sidecar) self.inner.ensure_well_formed_payload(payload)
} }
} }