mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 19:09:54 +00:00
refactor: replace extra fields with ExecutionPayloadSidecar in engine (#11901)
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -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",
|
||||||
|
|||||||
@ -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");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -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",
|
||||||
]
|
]
|
||||||
|
|||||||
@ -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)?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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>>,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -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();
|
||||||
|
|
||||||
|
|||||||
@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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,
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
|||||||
@ -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(),
|
||||||
|
|||||||
@ -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(),
|
||||||
},
|
},
|
||||||
)?,
|
)?,
|
||||||
)?;
|
)?;
|
||||||
|
|||||||
@ -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),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -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"] }
|
||||||
|
|||||||
@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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();
|
||||||
|
|||||||
Reference in New Issue
Block a user