refactor: replace extra fields with ExecutionPayloadSidecar in engine (#11901)

This commit is contained in:
Oliver
2024-10-23 16:44:37 +02:00
committed by GitHub
parent 889a7e0b98
commit 89eb73f3d2
17 changed files with 179 additions and 215 deletions

2
Cargo.lock generated
View File

@ -6394,7 +6394,6 @@ dependencies = [
name = "reth-beacon-consensus" name = "reth-beacon-consensus"
version = "1.1.0" version = "1.1.0"
dependencies = [ dependencies = [
"alloy-eips",
"alloy-genesis", "alloy-genesis",
"alloy-primitives", "alloy-primitives",
"alloy-rpc-types-engine", "alloy-rpc-types-engine",
@ -8356,7 +8355,6 @@ dependencies = [
name = "reth-payload-validator" name = "reth-payload-validator"
version = "1.1.0" version = "1.1.0"
dependencies = [ dependencies = [
"alloy-eips",
"alloy-rpc-types", "alloy-rpc-types",
"reth-chainspec", "reth-chainspec",
"reth-primitives", "reth-primitives",

View File

@ -170,10 +170,8 @@ impl<C: ChainSpecParser<ChainSpec = ChainSpec>> Command<C> {
beacon_engine_handle.fork_choice_updated(state, payload_attrs).await?; beacon_engine_handle.fork_choice_updated(state, payload_attrs).await?;
debug!(target: "reth::cli", ?response, "Received for forkchoice updated"); debug!(target: "reth::cli", ?response, "Received for forkchoice updated");
} }
StoredEngineApiMessage::NewPayload { payload, cancun_fields } => { StoredEngineApiMessage::NewPayload { payload, sidecar } => {
// todo: prague (last arg) let response = beacon_engine_handle.new_payload(payload, sidecar).await?;
let response =
beacon_engine_handle.new_payload(payload, cancun_fields, None).await?;
debug!(target: "reth::cli", ?response, "Received for new payload"); debug!(target: "reth::cli", ?response, "Received for new payload");
} }
}; };

View File

@ -31,7 +31,6 @@ reth-node-types.workspace = true
reth-chainspec = { workspace = true, optional = true } reth-chainspec = { workspace = true, optional = true }
# ethereum # ethereum
alloy-eips.workspace = true
alloy-primitives.workspace = true alloy-primitives.workspace = true
alloy-rpc-types-engine.workspace = true alloy-rpc-types-engine.workspace = true
@ -78,10 +77,10 @@ assert_matches.workspace = true
[features] [features]
optimism = [ optimism = [
"reth-chainspec", "reth-chainspec",
"reth-primitives/optimism", "reth-primitives/optimism",
"reth-provider/optimism", "reth-provider/optimism",
"reth-blockchain-tree/optimism", "reth-blockchain-tree/optimism",
"reth-db/optimism", "reth-db/optimism",
"reth-db-api/optimism" "reth-db-api/optimism",
] ]

View File

@ -4,9 +4,8 @@ use crate::{
engine::message::OnForkChoiceUpdated, BeaconConsensusEngineEvent, BeaconEngineMessage, engine::message::OnForkChoiceUpdated, BeaconConsensusEngineEvent, BeaconEngineMessage,
BeaconForkChoiceUpdateError, BeaconOnNewPayloadError, BeaconForkChoiceUpdateError, BeaconOnNewPayloadError,
}; };
use alloy_eips::eip7685::Requests;
use alloy_rpc_types_engine::{ use alloy_rpc_types_engine::{
CancunPayloadFields, ExecutionPayload, ForkchoiceState, ForkchoiceUpdated, PayloadStatus, ExecutionPayload, ExecutionPayloadSidecar, ForkchoiceState, ForkchoiceUpdated, PayloadStatus,
}; };
use futures::TryFutureExt; use futures::TryFutureExt;
use reth_engine_primitives::EngineTypes; use reth_engine_primitives::EngineTypes;
@ -47,18 +46,10 @@ where
pub async fn new_payload( pub async fn new_payload(
&self, &self,
payload: ExecutionPayload, payload: ExecutionPayload,
cancun_fields: Option<CancunPayloadFields>, sidecar: ExecutionPayloadSidecar,
execution_requests: Option<Requests>,
) -> Result<PayloadStatus, BeaconOnNewPayloadError> { ) -> Result<PayloadStatus, BeaconOnNewPayloadError> {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
// HACK(onbjerg): We should have a pectra payload fields struct, this is just a temporary let _ = self.to_engine.send(BeaconEngineMessage::NewPayload { payload, sidecar, tx });
// workaround.
let _ = self.to_engine.send(BeaconEngineMessage::NewPayload {
payload,
cancun_fields,
execution_requests,
tx,
});
rx.await.map_err(|_| BeaconOnNewPayloadError::EngineUnavailable)? rx.await.map_err(|_| BeaconOnNewPayloadError::EngineUnavailable)?
} }

View File

@ -1,7 +1,6 @@
use crate::engine::{error::BeaconOnNewPayloadError, forkchoice::ForkchoiceStatus}; use crate::engine::{error::BeaconOnNewPayloadError, forkchoice::ForkchoiceStatus};
use alloy_eips::eip7685::Requests;
use alloy_rpc_types_engine::{ use alloy_rpc_types_engine::{
CancunPayloadFields, ExecutionPayload, ForkChoiceUpdateResult, ForkchoiceState, ExecutionPayload, ExecutionPayloadSidecar, ForkChoiceUpdateResult, ForkchoiceState,
ForkchoiceUpdateError, ForkchoiceUpdated, PayloadId, PayloadStatus, PayloadStatusEnum, ForkchoiceUpdateError, ForkchoiceUpdated, PayloadId, PayloadStatus, PayloadStatusEnum,
}; };
use futures::{future::Either, FutureExt}; use futures::{future::Either, FutureExt};
@ -145,12 +144,9 @@ pub enum BeaconEngineMessage<Engine: EngineTypes> {
NewPayload { NewPayload {
/// The execution payload received by Engine API. /// The execution payload received by Engine API.
payload: ExecutionPayload, payload: ExecutionPayload,
/// The cancun-related newPayload fields, if any. /// The execution payload sidecar with additional version-specific fields received by
cancun_fields: Option<CancunPayloadFields>, /// engine API.
// HACK(onbjerg): We should have a pectra payload fields struct, this is just a temporary sidecar: ExecutionPayloadSidecar,
// workaround.
/// The pectra EIP-7685 execution requests.
execution_requests: Option<Requests>,
/// 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>>,
}, },

View File

@ -1,7 +1,6 @@
use alloy_eips::eip7685::Requests;
use alloy_primitives::{BlockNumber, B256}; use alloy_primitives::{BlockNumber, B256};
use alloy_rpc_types_engine::{ use alloy_rpc_types_engine::{
CancunPayloadFields, ExecutionPayload, ForkchoiceState, PayloadStatus, PayloadStatusEnum, ExecutionPayload, ExecutionPayloadSidecar, ForkchoiceState, PayloadStatus, PayloadStatusEnum,
PayloadValidationError, PayloadValidationError,
}; };
use futures::{stream::BoxStream, Future, StreamExt}; use futures::{stream::BoxStream, Future, StreamExt};
@ -1081,14 +1080,11 @@ where
/// ///
/// This returns a [`PayloadStatus`] that represents the outcome of a processed new payload and /// This returns a [`PayloadStatus`] that represents the outcome of a processed new payload and
/// returns an error if an internal error occurred. /// returns an error if an internal error occurred.
#[instrument(level = "trace", skip(self, payload, cancun_fields), fields(block_hash = ?payload.block_hash(), block_number = %payload.block_number(), is_pipeline_idle = %self.sync.is_pipeline_idle()), target = "consensus::engine")] #[instrument(level = "trace", skip(self, payload, sidecar), fields(block_hash = ?payload.block_hash(), block_number = %payload.block_number(), is_pipeline_idle = %self.sync.is_pipeline_idle()), target = "consensus::engine")]
fn on_new_payload( fn on_new_payload(
&mut self, &mut self,
payload: ExecutionPayload, payload: ExecutionPayload,
cancun_fields: Option<CancunPayloadFields>, sidecar: ExecutionPayloadSidecar,
// HACK(onbjerg): We should have a pectra payload fields struct, this is just a temporary
// workaround.
execution_requests: Option<Requests>,
) -> Result<Either<PayloadStatus, SealedBlock>, BeaconOnNewPayloadError> { ) -> Result<Either<PayloadStatus, SealedBlock>, BeaconOnNewPayloadError> {
self.metrics.new_payload_messages.increment(1); self.metrics.new_payload_messages.increment(1);
@ -1118,11 +1114,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( let block = match self.payload_validator.ensure_well_formed_payload(payload, sidecar) {
payload,
cancun_fields.into(),
execution_requests,
) {
Ok(block) => block, Ok(block) => block,
Err(error) => { Err(error) => {
error!(target: "consensus::engine", %error, "Invalid payload"); error!(target: "consensus::engine", %error, "Invalid payload");
@ -1867,13 +1859,8 @@ where
BeaconEngineMessage::ForkchoiceUpdated { state, payload_attrs, tx } => { BeaconEngineMessage::ForkchoiceUpdated { state, payload_attrs, tx } => {
this.on_forkchoice_updated(state, payload_attrs, tx); this.on_forkchoice_updated(state, payload_attrs, tx);
} }
BeaconEngineMessage::NewPayload { BeaconEngineMessage::NewPayload { payload, sidecar, tx } => {
payload, match this.on_new_payload(payload, sidecar) {
cancun_fields,
execution_requests,
tx,
} => {
match this.on_new_payload(payload, cancun_fields, execution_requests) {
Ok(Either::Right(block)) => { Ok(Either::Right(block)) => {
this.set_blockchain_tree_action( this.set_blockchain_tree_action(
BlockchainTreeAction::InsertNewPayload { block, tx }, BlockchainTreeAction::InsertNewPayload { block, tx },
@ -2061,7 +2048,12 @@ mod tests {
assert_matches!(rx.try_recv(), Err(TryRecvError::Empty)); assert_matches!(rx.try_recv(), Err(TryRecvError::Empty));
// consensus engine is still idle because no FCUs were received // consensus engine is still idle because no FCUs were received
let _ = env.send_new_payload(block_to_payload_v1(SealedBlock::default()), None).await; let _ = env
.send_new_payload(
block_to_payload_v1(SealedBlock::default()),
ExecutionPayloadSidecar::none(),
)
.await;
assert_matches!(rx.try_recv(), Err(TryRecvError::Empty)); assert_matches!(rx.try_recv(), Err(TryRecvError::Empty));
@ -2626,7 +2618,7 @@ mod tests {
0, 0,
BlockParams { ommers_count: Some(0), ..Default::default() }, BlockParams { ommers_count: Some(0), ..Default::default() },
)), )),
None, ExecutionPayloadSidecar::none(),
) )
.await; .await;
@ -2641,7 +2633,7 @@ mod tests {
1, 1,
BlockParams { ommers_count: Some(0), ..Default::default() }, BlockParams { ommers_count: Some(0), ..Default::default() },
)), )),
None, ExecutionPayloadSidecar::none(),
) )
.await; .await;
@ -2719,7 +2711,10 @@ mod tests {
// Send new payload // Send new payload
let result = env let result = env
.send_new_payload_retry_on_syncing(block_to_payload_v1(block2.clone()), None) .send_new_payload_retry_on_syncing(
block_to_payload_v1(block2.clone()),
ExecutionPayloadSidecar::none(),
)
.await .await
.unwrap(); .unwrap();
@ -2854,7 +2849,9 @@ mod tests {
2, 2,
BlockParams { parent: Some(parent), ommers_count: Some(0), ..Default::default() }, BlockParams { parent: Some(parent), ommers_count: Some(0), ..Default::default() },
); );
let res = env.send_new_payload(block_to_payload_v1(block), None).await; let res = env
.send_new_payload(block_to_payload_v1(block), ExecutionPayloadSidecar::none())
.await;
let expected_result = PayloadStatus::from_status(PayloadStatusEnum::Syncing); let expected_result = PayloadStatus::from_status(PayloadStatusEnum::Syncing);
assert_matches!(res, Ok(result) => assert_eq!(result, expected_result)); assert_matches!(res, Ok(result) => assert_eq!(result, expected_result));
@ -2924,7 +2921,10 @@ mod tests {
// Send new payload // Send new payload
let result = env let result = env
.send_new_payload_retry_on_syncing(block_to_payload_v1(block2.clone()), None) .send_new_payload_retry_on_syncing(
block_to_payload_v1(block2.clone()),
ExecutionPayloadSidecar::none(),
)
.await .await
.unwrap(); .unwrap();

View File

@ -6,7 +6,7 @@ use crate::{
}; };
use alloy_primitives::{BlockNumber, Sealable, B256}; use alloy_primitives::{BlockNumber, Sealable, B256};
use alloy_rpc_types_engine::{ use alloy_rpc_types_engine::{
CancunPayloadFields, ExecutionPayload, ForkchoiceState, ForkchoiceUpdated, PayloadStatus, ExecutionPayload, ExecutionPayloadSidecar, ForkchoiceState, ForkchoiceUpdated, PayloadStatus,
}; };
use reth_blockchain_tree::{ use reth_blockchain_tree::{
config::BlockchainTreeConfig, externals::TreeExternals, BlockchainTree, ShareableBlockchainTree, config::BlockchainTreeConfig, externals::TreeExternals, BlockchainTree, ShareableBlockchainTree,
@ -68,9 +68,9 @@ impl<DB> TestEnv<DB> {
pub async fn send_new_payload<T: Into<ExecutionPayload>>( pub async fn send_new_payload<T: Into<ExecutionPayload>>(
&self, &self,
payload: T, payload: T,
cancun_fields: Option<CancunPayloadFields>, sidecar: ExecutionPayloadSidecar,
) -> Result<PayloadStatus, BeaconOnNewPayloadError> { ) -> Result<PayloadStatus, BeaconOnNewPayloadError> {
self.engine_handle.new_payload(payload.into(), cancun_fields, None).await self.engine_handle.new_payload(payload.into(), sidecar).await
} }
/// Sends the `ExecutionPayload` message to the consensus engine and retries if the engine /// Sends the `ExecutionPayload` message to the consensus engine and retries if the engine
@ -78,11 +78,11 @@ impl<DB> TestEnv<DB> {
pub async fn send_new_payload_retry_on_syncing<T: Into<ExecutionPayload>>( pub async fn send_new_payload_retry_on_syncing<T: Into<ExecutionPayload>>(
&self, &self,
payload: T, payload: T,
cancun_fields: Option<CancunPayloadFields>, sidecar: ExecutionPayloadSidecar,
) -> Result<PayloadStatus, BeaconOnNewPayloadError> { ) -> Result<PayloadStatus, BeaconOnNewPayloadError> {
let payload: ExecutionPayload = payload.into(); let payload: ExecutionPayload = payload.into();
loop { loop {
let result = self.send_new_payload(payload.clone(), cancun_fields.clone()).await?; let result = self.send_new_payload(payload.clone(), sidecar.clone()).await?;
if !result.is_syncing() { if !result.is_syncing() {
return Ok(result) return Ok(result)
} }

View File

@ -1,7 +1,7 @@
//! Contains the implementation of the mining mode for the local engine. //! Contains the implementation of the mining mode for the local engine.
use alloy_primitives::{TxHash, B256}; use alloy_primitives::{TxHash, B256};
use alloy_rpc_types_engine::{CancunPayloadFields, ForkchoiceState}; use alloy_rpc_types_engine::{CancunPayloadFields, ExecutionPayloadSidecar, ForkchoiceState};
use eyre::OptionExt; use eyre::OptionExt;
use futures_util::{stream::Fuse, StreamExt}; use futures_util::{stream::Fuse, StreamExt};
use reth_beacon_consensus::BeaconEngineMessage; use reth_beacon_consensus::BeaconEngineMessage;
@ -221,9 +221,10 @@ where
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
self.to_engine.send(BeaconEngineMessage::NewPayload { self.to_engine.send(BeaconEngineMessage::NewPayload {
payload: block_to_payload(payload.block().clone()), payload: block_to_payload(payload.block().clone()),
cancun_fields, // todo: prague support
// todo: prague sidecar: cancun_fields
execution_requests: None, .map(ExecutionPayloadSidecar::v3)
.unwrap_or_else(ExecutionPayloadSidecar::none),
tx, tx,
})?; })?;

View File

@ -10,7 +10,7 @@ use alloy_primitives::{
BlockNumber, B256, U256, BlockNumber, B256, U256,
}; };
use alloy_rpc_types_engine::{ use alloy_rpc_types_engine::{
CancunPayloadFields, ExecutionPayload, ForkchoiceState, PayloadStatus, PayloadStatusEnum, ExecutionPayload, ExecutionPayloadSidecar, ForkchoiceState, PayloadStatus, PayloadStatusEnum,
PayloadValidationError, PayloadValidationError,
}; };
use reth_beacon_consensus::{ use reth_beacon_consensus::{
@ -70,7 +70,6 @@ use crate::{
engine::{EngineApiKind, EngineApiRequest}, engine::{EngineApiKind, EngineApiRequest},
tree::metrics::EngineApiMetrics, tree::metrics::EngineApiMetrics,
}; };
use alloy_eips::eip7685::Requests;
pub use config::TreeConfig; pub use config::TreeConfig;
pub use invalid_block_hook::{InvalidBlockHooks, NoopInvalidBlockHook}; pub use invalid_block_hook::{InvalidBlockHooks, NoopInvalidBlockHook};
pub use persistence_state::PersistenceState; pub use persistence_state::PersistenceState;
@ -722,8 +721,7 @@ where
fn on_new_payload( fn on_new_payload(
&mut self, &mut self,
payload: ExecutionPayload, payload: ExecutionPayload,
cancun_fields: Option<CancunPayloadFields>, sidecar: ExecutionPayloadSidecar,
execution_requests: Option<Requests>,
) -> 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);
@ -754,11 +752,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( let block = match self.payload_validator.ensure_well_formed_payload(payload, sidecar) {
payload,
cancun_fields.into(),
execution_requests,
) {
Ok(block) => block, Ok(block) => block,
Err(error) => { Err(error) => {
error!(target: "engine::tree", %error, "Invalid payload"); error!(target: "engine::tree", %error, "Invalid payload");
@ -1241,14 +1235,8 @@ where
error!(target: "engine::tree", "Failed to send event: {err:?}"); error!(target: "engine::tree", "Failed to send event: {err:?}");
} }
} }
BeaconEngineMessage::NewPayload { BeaconEngineMessage::NewPayload { payload, sidecar, tx } => {
payload, let output = self.on_new_payload(payload, sidecar);
cancun_fields,
execution_requests,
tx,
} => {
let output =
self.on_new_payload(payload, cancun_fields, execution_requests);
if let Err(err) = tx.send(output.map(|o| o.outcome).map_err(|e| { if let Err(err) = tx.send(output.map(|o| o.outcome).map_err(|e| {
reth_beacon_consensus::BeaconOnNewPayloadError::Internal( reth_beacon_consensus::BeaconOnNewPayloadError::Internal(
Box::new(e), Box::new(e),
@ -2585,6 +2573,7 @@ mod tests {
use crate::persistence::PersistenceAction; use crate::persistence::PersistenceAction;
use alloy_primitives::{Bytes, Sealable}; use alloy_primitives::{Bytes, Sealable};
use alloy_rlp::Decodable; use alloy_rlp::Decodable;
use alloy_rpc_types_engine::{CancunPayloadFields, ExecutionPayloadSidecar};
use assert_matches::assert_matches; use assert_matches::assert_matches;
use reth_beacon_consensus::{EthBeaconConsensus, ForkchoiceStatus}; use reth_beacon_consensus::{EthBeaconConsensus, ForkchoiceStatus};
use reth_chain_state::{test_utils::TestBlockBuilder, BlockState}; use reth_chain_state::{test_utils::TestBlockBuilder, BlockState};
@ -2862,11 +2851,10 @@ mod tests {
self.tree self.tree
.on_new_payload( .on_new_payload(
payload.into(), payload.into(),
Some(CancunPayloadFields { 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![],
}), }),
None,
) )
.unwrap(); .unwrap();
} }
@ -3129,7 +3117,10 @@ mod tests {
let mut test_harness = TestHarness::new(HOLESKY.clone()); let mut test_harness = TestHarness::new(HOLESKY.clone());
let outcome = test_harness.tree.on_new_payload(payload.into(), None, None).unwrap(); let outcome = test_harness
.tree
.on_new_payload(payload.into(), ExecutionPayloadSidecar::none())
.unwrap();
assert!(outcome.outcome.is_syncing()); assert!(outcome.outcome.is_syncing());
// ensure block is buffered // ensure block is buffered
@ -3173,8 +3164,7 @@ mod tests {
.on_engine_message(FromEngine::Request( .on_engine_message(FromEngine::Request(
BeaconEngineMessage::NewPayload { BeaconEngineMessage::NewPayload {
payload: payload.clone().into(), payload: payload.clone().into(),
cancun_fields: None, sidecar: ExecutionPayloadSidecar::none(),
execution_requests: None,
tx, tx,
} }
.into(), .into(),

View File

@ -1,6 +1,6 @@
//! 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::{CancunPayloadFields, ExecutionPayload, ForkchoiceState}; use alloy_rpc_types_engine::{ExecutionPayload, ExecutionPayloadSidecar, ForkchoiceState};
use futures::{Stream, StreamExt}; use futures::{Stream, StreamExt};
use reth_beacon_consensus::BeaconEngineMessage; use reth_beacon_consensus::BeaconEngineMessage;
use reth_engine_primitives::EngineTypes; use reth_engine_primitives::EngineTypes;
@ -30,8 +30,9 @@ pub enum StoredEngineApiMessage<Attributes> {
NewPayload { NewPayload {
/// The [`ExecutionPayload`] sent in the persisted call. /// The [`ExecutionPayload`] sent in the persisted call.
payload: ExecutionPayload, payload: ExecutionPayload,
/// The Cancun-specific fields sent in the persisted call, if any. /// The execution payload sidecar with additional version-specific fields received by
cancun_fields: Option<CancunPayloadFields>, /// engine API.
sidecar: ExecutionPayloadSidecar,
}, },
} }
@ -73,20 +74,14 @@ impl EngineMessageStore {
})?, })?,
)?; )?;
} }
// todo(onbjerg): execution requests BeaconEngineMessage::NewPayload { payload, sidecar, tx: _tx } => {
BeaconEngineMessage::NewPayload {
payload,
cancun_fields,
execution_requests: _,
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(),
cancun_fields: cancun_fields.clone(), sidecar: sidecar.clone(),
}, },
)?, )?,
)?; )?;

View File

@ -1,10 +1,9 @@
//! Stream wrapper that simulates reorgs. //! Stream wrapper that simulates reorgs.
use alloy_consensus::Transaction; use alloy_consensus::Transaction;
use alloy_eips::eip7685::Requests;
use alloy_primitives::U256; use alloy_primitives::U256;
use alloy_rpc_types_engine::{ use alloy_rpc_types_engine::{
CancunPayloadFields, ExecutionPayload, ForkchoiceState, PayloadStatus, CancunPayloadFields, ExecutionPayload, ExecutionPayloadSidecar, ForkchoiceState, PayloadStatus,
}; };
use futures::{stream::FuturesUnordered, Stream, StreamExt, TryFutureExt}; use futures::{stream::FuturesUnordered, Stream, StreamExt, TryFutureExt};
use itertools::Either; use itertools::Either;
@ -150,12 +149,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 { Some(BeaconEngineMessage::NewPayload { payload, sidecar, tx }),
payload,
cancun_fields,
execution_requests,
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.
@ -170,29 +164,26 @@ 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_cancun_fields, reorg_execution_requests) = let (reorg_payload, reorg_sidecar) = match create_reorg_head(
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(),
cancun_fields.clone(), ) {
execution_requests.clone(), Ok(result) => result,
) { Err(error) => {
Ok(result) => result, error!(target: "engine::stream::reorg", %error, "Error attempting to create reorg head");
Err(error) => { // Forward the payload and attempt to create reorg on top of
error!(target: "engine::stream::reorg", %error, "Error attempting to create reorg head"); // the next one
// Forward the payload and attempt to create reorg on top of return Poll::Ready(Some(BeaconEngineMessage::NewPayload {
// the next one payload,
return Poll::Ready(Some(BeaconEngineMessage::NewPayload { sidecar,
payload, tx,
cancun_fields, }))
execution_requests, }
tx, };
}))
}
};
let reorg_forkchoice_state = ForkchoiceState { let reorg_forkchoice_state = ForkchoiceState {
finalized_block_hash: last_forkchoice_state.finalized_block_hash, finalized_block_hash: last_forkchoice_state.finalized_block_hash,
safe_block_hash: last_forkchoice_state.safe_block_hash, safe_block_hash: last_forkchoice_state.safe_block_hash,
@ -208,17 +199,11 @@ where
let queue = VecDeque::from([ let queue = VecDeque::from([
// Current payload // Current payload
BeaconEngineMessage::NewPayload { BeaconEngineMessage::NewPayload { payload, sidecar, tx },
payload,
cancun_fields,
execution_requests,
tx,
},
// Reorg payload // Reorg payload
BeaconEngineMessage::NewPayload { BeaconEngineMessage::NewPayload {
payload: reorg_payload, payload: reorg_payload,
cancun_fields: reorg_cancun_fields, sidecar: reorg_sidecar,
execution_requests: reorg_execution_requests,
tx: reorg_payload_tx, tx: reorg_payload_tx,
}, },
// Reorg forkchoice state // Reorg forkchoice state
@ -252,9 +237,8 @@ fn create_reorg_head<Provider, Evm, Spec>(
payload_validator: &ExecutionPayloadValidator<Spec>, payload_validator: &ExecutionPayloadValidator<Spec>,
mut depth: usize, mut depth: usize,
next_payload: ExecutionPayload, next_payload: ExecutionPayload,
next_cancun_fields: Option<CancunPayloadFields>, next_sidecar: ExecutionPayloadSidecar,
next_execution_requests: Option<Requests>, ) -> RethResult<(ExecutionPayload, ExecutionPayloadSidecar)>
) -> RethResult<(ExecutionPayload, Option<CancunPayloadFields>, Option<Requests>)>
where where
Provider: BlockReader + StateProviderFactory, Provider: BlockReader + StateProviderFactory,
Evm: ConfigureEvm<Header = Header>, Evm: ConfigureEvm<Header = Header>,
@ -264,11 +248,7 @@ where
// Ensure next payload is valid. // Ensure next payload is valid.
let next_block = payload_validator let next_block = payload_validator
.ensure_well_formed_payload( .ensure_well_formed_payload(next_payload, next_sidecar)
next_payload,
next_cancun_fields.into(),
next_execution_requests,
)
.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.
@ -439,11 +419,16 @@ where
Ok(( Ok((
block_to_payload(reorg_block), block_to_payload(reorg_block),
// todo(onbjerg): how do we support execution requests?
reorg_target reorg_target
.header .header
.parent_beacon_block_root .parent_beacon_block_root
.map(|root| CancunPayloadFields { parent_beacon_block_root: root, versioned_hashes }), .map(|root| {
// todo(prague) ExecutionPayloadSidecar::v3(CancunPayloadFields {
None, parent_beacon_block_root: root,
versioned_hashes,
})
})
.unwrap_or_else(ExecutionPayloadSidecar::none),
)) ))
} }

View File

@ -41,19 +41,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 { Some(BeaconEngineMessage::NewPayload { payload, sidecar, tx }) => {
payload,
cancun_fields,
execution_requests,
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(),
?cancun_fields, ?sidecar,
threshold=this.threshold, threshold=this.threshold,
skipped=this.skipped, "Skipping new payload" skipped=this.skipped, "Skipping new payload"
); );
@ -61,12 +56,7 @@ where
continue continue
} }
*this.skipped = 0; *this.skipped = 0;
Some(BeaconEngineMessage::NewPayload { Some(BeaconEngineMessage::NewPayload { payload, sidecar, tx })
payload,
cancun_fields,
execution_requests,
tx,
})
} }
next => next, next => next,
}; };

View File

@ -18,5 +18,4 @@ reth-primitives.workspace = true
reth-rpc-types-compat.workspace = true reth-rpc-types-compat.workspace = true
# alloy # alloy
alloy-eips.workspace = true
alloy-rpc-types = { workspace = true, features = ["engine"] } alloy-rpc-types = { workspace = true, features = ["engine"] }

View File

@ -8,8 +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_eips::eip7685::Requests; use alloy_rpc_types::engine::{
use alloy_rpc_types::engine::{ExecutionPayload, MaybeCancunPayloadFields, PayloadError}; ExecutionPayload, ExecutionPayloadSidecar, MaybeCancunPayloadFields, PayloadError,
};
use reth_chainspec::EthereumHardforks; use reth_chainspec::EthereumHardforks;
use reth_primitives::SealedBlock; use reth_primitives::SealedBlock;
use reth_rpc_types_compat::engine::payload::try_into_block; use reth_rpc_types_compat::engine::payload::try_into_block;
@ -112,15 +113,12 @@ impl<ChainSpec: EthereumHardforks> ExecutionPayloadValidator<ChainSpec> {
pub fn ensure_well_formed_payload( pub fn ensure_well_formed_payload(
&self, &self,
payload: ExecutionPayload, payload: ExecutionPayload,
cancun_fields: MaybeCancunPayloadFields, sidecar: ExecutionPayloadSidecar,
execution_requests: Option<Requests>,
) -> Result<SealedBlock, PayloadError> { ) -> Result<SealedBlock, PayloadError> {
let expected_hash = payload.block_hash(); let expected_hash = payload.block_hash();
// First parse the block // First parse the block
let sealed_block = let sealed_block = try_into_block(payload, &sidecar)?.seal_slow();
try_into_block(payload, cancun_fields.parent_beacon_block_root(), execution_requests)?
.seal_slow();
// Ensure the hash included in the payload matches the block hash // Ensure the hash included in the payload matches the block hash
if expected_hash != sealed_block.hash() { if expected_hash != sealed_block.hash() {
@ -139,7 +137,7 @@ impl<ChainSpec: EthereumHardforks> ExecutionPayloadValidator<ChainSpec> {
// cancun active but excess blob gas not present // cancun active but excess blob gas not present
return Err(PayloadError::PostCancunBlockWithoutExcessBlobGas) return Err(PayloadError::PostCancunBlockWithoutExcessBlobGas)
} }
if cancun_fields.as_ref().is_none() { if sidecar.cancun().is_none() {
// cancun active but cancun fields not present // cancun active but cancun fields not present
return Err(PayloadError::PostCancunWithoutCancunFields) return Err(PayloadError::PostCancunWithoutCancunFields)
} }
@ -156,7 +154,7 @@ impl<ChainSpec: EthereumHardforks> ExecutionPayloadValidator<ChainSpec> {
// cancun not active but excess blob gas present // cancun not active but excess blob gas present
return Err(PayloadError::PreCancunBlockWithExcessBlobGas) return Err(PayloadError::PreCancunBlockWithExcessBlobGas)
} }
if cancun_fields.as_ref().is_some() { if sidecar.cancun().is_some() {
// cancun not active but cancun fields present // cancun not active but cancun fields present
return Err(PayloadError::PreCancunWithCancunFields) return Err(PayloadError::PreCancunWithCancunFields)
} }
@ -175,7 +173,10 @@ impl<ChainSpec: EthereumHardforks> ExecutionPayloadValidator<ChainSpec> {
} }
// EIP-4844 checks // EIP-4844 checks
self.ensure_matching_blob_versioned_hashes(&sealed_block, &cancun_fields)?; self.ensure_matching_blob_versioned_hashes(
&sealed_block,
&sidecar.cancun().cloned().into(),
)?;
Ok(sealed_block) Ok(sealed_block)
} }

View File

@ -5,8 +5,8 @@ use alloy_eips::{eip4844::BlobAndProofV1, eip7685::Requests};
use alloy_primitives::{BlockHash, BlockNumber, B256, U64}; use alloy_primitives::{BlockHash, BlockNumber, B256, U64};
use alloy_rpc_types_engine::{ use alloy_rpc_types_engine::{
CancunPayloadFields, ClientVersionV1, ExecutionPayload, ExecutionPayloadBodiesV1, CancunPayloadFields, ClientVersionV1, ExecutionPayload, ExecutionPayloadBodiesV1,
ExecutionPayloadInputV2, ExecutionPayloadV1, ExecutionPayloadV3, ForkchoiceState, ExecutionPayloadInputV2, ExecutionPayloadSidecar, ExecutionPayloadV1, ExecutionPayloadV3,
ForkchoiceUpdated, PayloadId, PayloadStatus, TransitionConfiguration, ForkchoiceState, ForkchoiceUpdated, PayloadId, PayloadStatus, TransitionConfiguration,
}; };
use async_trait::async_trait; use async_trait::async_trait;
use jsonrpsee_core::RpcResult; use jsonrpsee_core::RpcResult;
@ -140,7 +140,11 @@ where
self.inner self.inner
.validator .validator
.validate_version_specific_fields(EngineApiMessageVersion::V1, payload_or_attrs)?; .validate_version_specific_fields(EngineApiMessageVersion::V1, payload_or_attrs)?;
Ok(self.inner.beacon_consensus.new_payload(payload, None, None).await?) Ok(self
.inner
.beacon_consensus
.new_payload(payload, ExecutionPayloadSidecar::none())
.await?)
} }
/// See also <https://github.com/ethereum/execution-apis/blob/584905270d8ad665718058060267061ecfd79ca5/src/engine/shanghai.md#engine_newpayloadv2> /// See also <https://github.com/ethereum/execution-apis/blob/584905270d8ad665718058060267061ecfd79ca5/src/engine/shanghai.md#engine_newpayloadv2>
@ -156,7 +160,11 @@ where
self.inner self.inner
.validator .validator
.validate_version_specific_fields(EngineApiMessageVersion::V2, payload_or_attrs)?; .validate_version_specific_fields(EngineApiMessageVersion::V2, payload_or_attrs)?;
Ok(self.inner.beacon_consensus.new_payload(payload, None, None).await?) Ok(self
.inner
.beacon_consensus
.new_payload(payload, ExecutionPayloadSidecar::none())
.await?)
} }
/// See also <https://github.com/ethereum/execution-apis/blob/fe8e13c288c592ec154ce25c534e26cb7ce0530d/src/engine/cancun.md#engine_newpayloadv3> /// See also <https://github.com/ethereum/execution-apis/blob/fe8e13c288c592ec154ce25c534e26cb7ce0530d/src/engine/cancun.md#engine_newpayloadv3>
@ -176,9 +184,17 @@ where
.validator .validator
.validate_version_specific_fields(EngineApiMessageVersion::V3, payload_or_attrs)?; .validate_version_specific_fields(EngineApiMessageVersion::V3, payload_or_attrs)?;
let cancun_fields = CancunPayloadFields { versioned_hashes, parent_beacon_block_root }; Ok(self
.inner
Ok(self.inner.beacon_consensus.new_payload(payload, Some(cancun_fields), None).await?) .beacon_consensus
.new_payload(
payload,
ExecutionPayloadSidecar::v3(CancunPayloadFields {
versioned_hashes,
parent_beacon_block_root,
}),
)
.await?)
} }
/// See also <https://github.com/ethereum/execution-apis/blob/7907424db935b93c2fe6a3c0faab943adebe8557/src/engine/prague.md#engine_newpayloadv4> /// See also <https://github.com/ethereum/execution-apis/blob/7907424db935b93c2fe6a3c0faab943adebe8557/src/engine/prague.md#engine_newpayloadv4>
@ -187,8 +203,6 @@ where
payload: ExecutionPayloadV3, payload: ExecutionPayloadV3,
versioned_hashes: Vec<B256>, versioned_hashes: Vec<B256>,
parent_beacon_block_root: B256, parent_beacon_block_root: B256,
// TODO(onbjerg): Figure out why we even get these here, since we'll check the requests
// from execution against the requests root in the header.
execution_requests: Requests, execution_requests: Requests,
) -> EngineApiResult<PayloadStatus> { ) -> EngineApiResult<PayloadStatus> {
let payload = ExecutionPayload::from(payload); let payload = ExecutionPayload::from(payload);
@ -201,14 +215,16 @@ where
.validator .validator
.validate_version_specific_fields(EngineApiMessageVersion::V4, payload_or_attrs)?; .validate_version_specific_fields(EngineApiMessageVersion::V4, payload_or_attrs)?;
let cancun_fields = CancunPayloadFields { versioned_hashes, parent_beacon_block_root };
// HACK(onbjerg): We should have a pectra payload fields struct, this is just a temporary
// workaround.
Ok(self Ok(self
.inner .inner
.beacon_consensus .beacon_consensus
.new_payload(payload, Some(cancun_fields), Some(execution_requests)) .new_payload(
payload,
ExecutionPayloadSidecar::v4(
CancunPayloadFields { versioned_hashes, parent_beacon_block_root },
execution_requests,
),
)
.await?) .await?)
} }

View File

@ -3,7 +3,8 @@
use alloy_primitives::{Bytes, Sealable, U256}; use alloy_primitives::{Bytes, Sealable, U256};
use alloy_rlp::{Decodable, Error as RlpError}; use alloy_rlp::{Decodable, Error as RlpError};
use alloy_rpc_types_engine::{ use alloy_rpc_types_engine::{
ExecutionPayload, ExecutionPayloadBodyV1, ExecutionPayloadV1, PayloadError, ExecutionPayload, ExecutionPayloadBodyV1, ExecutionPayloadSidecar, ExecutionPayloadV1,
PayloadError,
}; };
use assert_matches::assert_matches; use assert_matches::assert_matches;
use reth_primitives::{proofs, Block, SealedBlock, SealedHeader, TransactionSigned, Withdrawals}; use reth_primitives::{proofs, Block, SealedBlock, SealedHeader, TransactionSigned, Withdrawals};
@ -75,7 +76,10 @@ fn payload_validation() {
b b
}); });
assert_matches!(try_into_sealed_block(block_with_valid_extra_data, None, None), Ok(_)); assert_matches!(
try_into_sealed_block(block_with_valid_extra_data, &ExecutionPayloadSidecar::none()),
Ok(_)
);
// Invalid extra data // Invalid extra data
let block_with_invalid_extra_data = Bytes::from_static(&[0; 33]); let block_with_invalid_extra_data = Bytes::from_static(&[0; 33]);
@ -84,7 +88,7 @@ fn payload_validation() {
b b
}); });
assert_matches!( assert_matches!(
try_into_sealed_block(invalid_extra_data_block, None, None), try_into_sealed_block(invalid_extra_data_block, &ExecutionPayloadSidecar::none()),
Err(PayloadError::ExtraData(data)) if data == block_with_invalid_extra_data Err(PayloadError::ExtraData(data)) if data == block_with_invalid_extra_data
); );
@ -94,7 +98,7 @@ fn payload_validation() {
b b
}); });
assert_matches!( assert_matches!(
try_into_sealed_block(block_with_zero_base_fee, None, None), try_into_sealed_block(block_with_zero_base_fee, &ExecutionPayloadSidecar::none()),
Err(PayloadError::BaseFee(val)) if val.is_zero() Err(PayloadError::BaseFee(val)) if val.is_zero()
); );
@ -113,7 +117,7 @@ fn payload_validation() {
b b
}); });
assert_matches!( assert_matches!(
try_into_sealed_block(block_with_ommers.clone(), None, None), try_into_sealed_block(block_with_ommers.clone(), &ExecutionPayloadSidecar::none()),
Err(PayloadError::BlockHash { consensus, .. }) Err(PayloadError::BlockHash { consensus, .. })
if consensus == block_with_ommers.block_hash() if consensus == block_with_ommers.block_hash()
); );
@ -124,7 +128,7 @@ fn payload_validation() {
b b
}); });
assert_matches!( assert_matches!(
try_into_sealed_block(block_with_difficulty.clone(), None, None), try_into_sealed_block(block_with_difficulty.clone(), &ExecutionPayloadSidecar::none()),
Err(PayloadError::BlockHash { consensus, .. }) if consensus == block_with_difficulty.block_hash() Err(PayloadError::BlockHash { consensus, .. }) if consensus == block_with_difficulty.block_hash()
); );
@ -134,9 +138,8 @@ fn payload_validation() {
b b
}); });
assert_matches!( assert_matches!(
try_into_sealed_block(block_with_nonce.clone(), None, None), try_into_sealed_block(block_with_nonce.clone(), &ExecutionPayloadSidecar::none()),
Err(PayloadError::BlockHash { consensus, .. }) if consensus == block_with_nonce.block_hash() Err(PayloadError::BlockHash { consensus, .. }) if consensus == block_with_nonce.block_hash()
); );
// Valid block // Valid block

View File

@ -9,7 +9,8 @@ use alloy_eips::{
use alloy_primitives::{B256, U256}; use alloy_primitives::{B256, U256};
use alloy_rpc_types_engine::{ use alloy_rpc_types_engine::{
payload::{ExecutionPayloadBodyV1, ExecutionPayloadFieldV2, ExecutionPayloadInputV2}, payload::{ExecutionPayloadBodyV1, ExecutionPayloadFieldV2, ExecutionPayloadInputV2},
ExecutionPayload, ExecutionPayloadV1, ExecutionPayloadV2, ExecutionPayloadV3, PayloadError, ExecutionPayload, ExecutionPayloadSidecar, ExecutionPayloadV1, ExecutionPayloadV2,
ExecutionPayloadV3, PayloadError,
}; };
use reth_primitives::{ use reth_primitives::{
proofs::{self}, proofs::{self},
@ -248,17 +249,18 @@ pub fn convert_block_to_payload_input_v2(value: SealedBlock) -> ExecutionPayload
} }
} }
/// Tries to create a new block (without a block hash) from the given payload and optional parent /// Tries to create a new unsealed block from the given payload and payload sidecar.
/// beacon block root. ///
/// Performs additional validation of `extra_data` and `base_fee_per_gas` fields. /// Performs additional validation of `extra_data` and `base_fee_per_gas` fields.
/// ///
/// NOTE: The log bloom is assumed to be validated during serialization. /// # 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> /// See <https://github.com/ethereum/go-ethereum/blob/79a478bb6176425c2400e949890e668a3d9a3d05/core/beacon/types.go#L145>
pub fn try_into_block( pub fn try_into_block(
value: ExecutionPayload, value: ExecutionPayload,
parent_beacon_block_root: Option<B256>, sidecar: &ExecutionPayloadSidecar,
execution_requests: Option<Requests>,
) -> Result<Block, PayloadError> { ) -> Result<Block, PayloadError> {
let mut base_payload = match value { let mut base_payload = match value {
ExecutionPayload::V1(payload) => try_payload_v1_to_block(payload)?, ExecutionPayload::V1(payload) => try_payload_v1_to_block(payload)?,
@ -266,29 +268,30 @@ pub fn try_into_block(
ExecutionPayload::V3(payload) => try_payload_v3_to_block(payload)?, ExecutionPayload::V3(payload) => try_payload_v3_to_block(payload)?,
}; };
base_payload.header.parent_beacon_block_root = parent_beacon_block_root; base_payload.header.parent_beacon_block_root = sidecar.parent_beacon_block_root();
base_payload.header.requests_hash = execution_requests.map(|reqs| reqs.requests_hash()); base_payload.header.requests_hash = sidecar.requests().map(Requests::requests_hash);
Ok(base_payload) Ok(base_payload)
} }
/// Tries to create a new block from the given payload and optional parent beacon block root. /// Tries to create a sealed new block from the given payload and payload sidecar.
///
/// NOTE: Empty ommers, nonce and difficulty values are validated upon computing block hash and
/// comparing the value with `payload.block_hash`.
/// ///
/// Uses [`try_into_block`] to convert from the [`ExecutionPayload`] to [`Block`] and seals the /// Uses [`try_into_block`] to convert from the [`ExecutionPayload`] to [`Block`] and seals the
/// block with its hash. /// block with its hash.
/// ///
/// Uses [`validate_block_hash`] to validate the payload block hash and ultimately return the /// Uses [`validate_block_hash`] to validate the payload block hash and ultimately return the
/// [`SealedBlock`]. /// [`SealedBlock`].
///
/// # Note
///
/// Empty ommers, nonce, difficulty, and execution request values are validated upon computing block
/// hash and comparing the value with `payload.block_hash`.
pub fn try_into_sealed_block( pub fn try_into_sealed_block(
payload: ExecutionPayload, payload: ExecutionPayload,
parent_beacon_block_root: Option<B256>, sidecar: &ExecutionPayloadSidecar,
execution_requests: Option<Requests>,
) -> Result<SealedBlock, PayloadError> { ) -> Result<SealedBlock, PayloadError> {
let block_hash = payload.block_hash(); let block_hash = payload.block_hash();
let base_payload = try_into_block(payload, parent_beacon_block_root, execution_requests)?; let base_payload = try_into_block(payload, sidecar)?;
// validate block hash and return // validate block hash and return
validate_block_hash(block_hash, base_payload) validate_block_hash(block_hash, base_payload)
@ -356,8 +359,8 @@ mod tests {
}; };
use alloy_primitives::{b256, hex, Bytes, U256}; use alloy_primitives::{b256, hex, Bytes, U256};
use alloy_rpc_types_engine::{ use alloy_rpc_types_engine::{
CancunPayloadFields, ExecutionPayload, ExecutionPayloadV1, ExecutionPayloadV2, CancunPayloadFields, ExecutionPayload, ExecutionPayloadSidecar, ExecutionPayloadV1,
ExecutionPayloadV3, ExecutionPayloadV2, ExecutionPayloadV3,
}; };
#[test] #[test]
@ -575,8 +578,7 @@ mod tests {
let cancun_fields = CancunPayloadFields { parent_beacon_block_root, versioned_hashes }; let cancun_fields = CancunPayloadFields { parent_beacon_block_root, versioned_hashes };
// convert into block // convert into block
let block = let block = try_into_block(payload, &ExecutionPayloadSidecar::v3(cancun_fields)).unwrap();
try_into_block(payload, Some(cancun_fields.parent_beacon_block_root), None).unwrap();
// Ensure the actual hash is calculated if we set the fields to what they should be // Ensure the actual hash is calculated if we set the fields to what they should be
validate_block_hash(block_hash_with_blob_fee_fields, block).unwrap(); validate_block_hash(block_hash_with_blob_fee_fields, block).unwrap();