Skip to content

Commit

Permalink
refactor: couple ExecutionPayload and ExecutionPayloadSidecar (#14172)
Browse files Browse the repository at this point in the history
  • Loading branch information
klkvr authored Feb 3, 2025
1 parent e310688 commit 04c1d71
Show file tree
Hide file tree
Showing 15 changed files with 155 additions and 113 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 2 additions & 7 deletions crates/engine/local/src/miner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,13 +208,8 @@ where
let block = payload.block();

let (tx, rx) = oneshot::channel();
let (payload, sidecar) = EngineT::block_to_payload(payload.block().clone());
self.to_engine.send(BeaconEngineMessage::NewPayload {
payload,
// todo: prague support
sidecar,
tx,
})?;
let payload = EngineT::block_to_payload(payload.block().clone());
self.to_engine.send(BeaconEngineMessage::NewPayload { payload, tx })?;

let res = rx.await??;

Expand Down
56 changes: 51 additions & 5 deletions crates/engine/primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

extern crate alloc;

use alloy_primitives::B256;
use reth_payload_primitives::{BuiltPayload, PayloadAttributes};
mod error;

Expand All @@ -32,15 +33,61 @@ pub use event::*;
mod invalid_block_hook;
pub use invalid_block_hook::InvalidBlockHook;

use alloy_eips::{eip7685::Requests, Decodable2718};
use reth_payload_primitives::{
validate_execution_requests, EngineApiMessageVersion, EngineObjectValidationError,
InvalidPayloadAttributesError, PayloadOrAttributes, PayloadTypes,
};
use reth_primitives::{NodePrimitives, SealedBlock};
use reth_primitives_traits::Block;
use serde::{de::DeserializeOwned, ser::Serialize};
use serde::{de::DeserializeOwned, Deserialize, Serialize};

/// Struct aggregating [`ExecutionPayload`] and [`ExecutionPayloadSidecar`] and encapsulating
/// complete payload supplied for execution.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ExecutionData {
/// Execution payload.
pub payload: ExecutionPayload,
/// Additional fork-specific fields.
pub sidecar: ExecutionPayloadSidecar,
}

impl ExecutionData {
/// Creates new instance of [`ExecutionData`].
pub const fn new(payload: ExecutionPayload, sidecar: ExecutionPayloadSidecar) -> Self {
Self { payload, sidecar }
}

/// Returns the parent hash of the block.
pub fn parent_hash(&self) -> B256 {
self.payload.parent_hash()
}

/// Returns the hash of the block.
pub fn block_hash(&self) -> B256 {
self.payload.block_hash()
}

use alloy_eips::eip7685::Requests;
/// Returns the number of the block.
pub fn block_number(&self) -> u64 {
self.payload.block_number()
}

/// Tries to create a new unsealed block from the given payload and payload sidecar.
///
/// Performs additional validation of `extra_data` and `base_fee_per_gas` fields.
///
/// # Note
///
/// The log bloom is assumed to be validated during serialization.
///
/// See <https://github.com/ethereum/go-ethereum/blob/79a478bb6176425c2400e949890e668a3d9a3d05/core/beacon/types.go#L145>
pub fn try_into_block<T: Decodable2718>(
self,
) -> Result<alloy_consensus::Block<T>, PayloadError> {
self.payload.try_into_block_with_sidecar(&self.sidecar)
}
}

/// This type defines the versioned types of the engine API.
///
Expand Down Expand Up @@ -94,7 +141,7 @@ pub trait EngineTypes:
block: SealedBlock<
<<Self::BuiltPayload as BuiltPayload>::Primitives as NodePrimitives>::Block,
>,
) -> (ExecutionPayload, ExecutionPayloadSidecar);
) -> ExecutionData;
}

/// Type that validates an [`ExecutionPayload`].
Expand All @@ -112,8 +159,7 @@ pub trait PayloadValidator: fmt::Debug + Send + Sync + Unpin + 'static {
/// engine-API specification.
fn ensure_well_formed_payload(
&self,
payload: ExecutionPayload,
sidecar: ExecutionPayloadSidecar,
payload: ExecutionData,
) -> Result<SealedBlock<Self::Block>, PayloadError>;
}

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

Expand Down
35 changes: 19 additions & 16 deletions crates/engine/tree/src/tree/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ use alloy_primitives::{
BlockNumber, B256, U256,
};
use alloy_rpc_types_engine::{
ExecutionPayload, ExecutionPayloadSidecar, ForkchoiceState, PayloadStatus, PayloadStatusEnum,
PayloadValidationError,
ForkchoiceState, PayloadStatus, PayloadStatusEnum, PayloadValidationError,
};
use block_buffer::BlockBuffer;
use error::{InsertBlockError, InsertBlockErrorKind, InsertBlockFatalError};
Expand All @@ -29,7 +28,7 @@ use reth_consensus::{Consensus, FullConsensus, PostExecutionInput};
pub use reth_engine_primitives::InvalidBlockHook;
use reth_engine_primitives::{
BeaconConsensusEngineEvent, BeaconEngineMessage, BeaconOnNewPayloadError, EngineTypes,
EngineValidator, ForkchoiceStateTracker, OnForkChoiceUpdated,
EngineValidator, ExecutionData, ForkchoiceStateTracker, OnForkChoiceUpdated,
};
use reth_errors::{ConsensusError, ProviderResult};
use reth_ethereum_primitives::EthPrimitives;
Expand Down Expand Up @@ -791,7 +790,7 @@ where

/// When the Consensus layer receives a new block via the consensus gossip protocol,
/// the transactions in the block are sent to the execution layer in the form of a
/// [`ExecutionPayload`]. The Execution layer executes the transactions and validates the
/// [`ExecutionData`]. The Execution layer executes the transactions and validates the
/// state in the block header, then passes validation data back to Consensus layer, that
/// adds the block to the head of its own blockchain and attests to it. The block is then
/// broadcast over the consensus p2p network in the form of a "Beacon block".
Expand All @@ -804,8 +803,7 @@ where
#[instrument(level = "trace", skip_all, fields(block_hash = %payload.block_hash(), block_num = %payload.block_number(),), target = "engine::tree")]
fn on_new_payload(
&mut self,
payload: ExecutionPayload,
sidecar: ExecutionPayloadSidecar,
payload: ExecutionData,
) -> Result<TreeOutcome<PayloadStatus>, InsertBlockFatalError> {
trace!(target: "engine::tree", "invoked new payload");
self.metrics.engine.new_payload_messages.increment(1);
Expand Down Expand Up @@ -836,7 +834,7 @@ where
//
// This validation **MUST** be instantly run in all cases even during active sync process.
let parent_hash = payload.parent_hash();
let block = match self.payload_validator.ensure_well_formed_payload(payload, sidecar) {
let block = match self.payload_validator.ensure_well_formed_payload(payload) {
Ok(block) => block,
Err(error) => {
error!(target: "engine::tree", %error, "Invalid payload");
Expand Down Expand Up @@ -1392,8 +1390,8 @@ where
error!(target: "engine::tree", "Failed to send event: {err:?}");
}
}
BeaconEngineMessage::NewPayload { payload, sidecar, tx } => {
let output = self.on_new_payload(payload, sidecar);
BeaconEngineMessage::NewPayload { payload, tx } => {
let output = self.on_new_payload(payload);
if let Err(err) =
tx.send(output.map(|o| o.outcome).map_err(|e| {
BeaconOnNewPayloadError::Internal(Box::new(e))
Expand Down Expand Up @@ -3207,13 +3205,13 @@ mod tests {
&block.clone_sealed_block().into_block(),
);
self.tree
.on_new_payload(
payload.into(),
ExecutionPayloadSidecar::v3(CancunPayloadFields {
.on_new_payload(ExecutionData {
payload: payload.into(),
sidecar: ExecutionPayloadSidecar::v3(CancunPayloadFields {
parent_beacon_block_root: block.parent_beacon_block_root.unwrap(),
versioned_hashes: vec![],
}),
)
})
.unwrap();
}

Expand Down Expand Up @@ -3478,7 +3476,10 @@ mod tests {

let outcome = test_harness
.tree
.on_new_payload(payload.into(), ExecutionPayloadSidecar::none())
.on_new_payload(ExecutionData {
payload: payload.into(),
sidecar: ExecutionPayloadSidecar::none(),
})
.unwrap();
assert!(outcome.outcome.is_syncing());

Expand Down Expand Up @@ -3523,8 +3524,10 @@ mod tests {
.tree
.on_engine_message(FromEngine::Request(
BeaconEngineMessage::NewPayload {
payload: payload.clone().into(),
sidecar: ExecutionPayloadSidecar::none(),
payload: ExecutionData {
payload: payload.clone().into(),
sidecar: ExecutionPayloadSidecar::none(),
},
tx,
}
.into(),
Expand Down
15 changes: 6 additions & 9 deletions crates/engine/util/src/engine_store.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
//! Stores engine API messages to disk for later inspection and replay.
use alloy_rpc_types_engine::{ExecutionPayload, ExecutionPayloadSidecar, ForkchoiceState};
use alloy_rpc_types_engine::ForkchoiceState;
use futures::{Stream, StreamExt};
use reth_engine_primitives::{BeaconEngineMessage, EngineTypes};
use reth_engine_primitives::{BeaconEngineMessage, EngineTypes, ExecutionData};
use reth_fs_util as fs;
use serde::{Deserialize, Serialize};
use std::{
Expand All @@ -27,11 +27,9 @@ pub enum StoredEngineApiMessage<Attributes> {
},
/// The on-disk representation of an `engine_newPayload` method call.
NewPayload {
/// The [`ExecutionPayload`] sent in the persisted call.
payload: ExecutionPayload,
/// The execution payload sidecar with additional version-specific fields received by
/// engine API.
sidecar: ExecutionPayloadSidecar,
/// The [`ExecutionData`] sent in the persisted call.
#[serde(flatten)]
payload: ExecutionData,
},
}

Expand Down Expand Up @@ -78,14 +76,13 @@ impl EngineMessageStore {
})?,
)?;
}
BeaconEngineMessage::NewPayload { payload, sidecar, tx: _tx } => {
BeaconEngineMessage::NewPayload { payload, tx: _tx } => {
let filename = format!("{}-new_payload-{}.json", timestamp, payload.block_hash());
fs::write(
self.path.join(filename),
serde_json::to_vec(
&StoredEngineApiMessage::<Engine::PayloadAttributes>::NewPayload {
payload: payload.clone(),
sidecar: sidecar.clone(),
},
)?,
)?;
Expand Down
Loading

0 comments on commit 04c1d71

Please sign in to comment.