This commit is contained in:
Eitan Seri- Levi
2026-03-02 13:05:13 -08:00
10 changed files with 210 additions and 107 deletions

View File

@@ -22,7 +22,7 @@ pub const VALIDATOR_MONITOR_ATTESTATION_SIMULATOR_SOURCE_ATTESTER_MISS_TOTAL: &s
"validator_monitor_attestation_simulator_source_attester_miss_total";
/*
* Execution Payload Envelope Procsesing
* Execution Payload Envelope Processing
*/
pub static ENVELOPE_PROCESSING_REQUESTS: LazyLock<Result<IntCounter>> = LazyLock::new(|| {

View File

@@ -5,7 +5,7 @@ use state_processing::{
VerifySignatures,
envelope_processing::{VerifyStateRoot, process_execution_payload_envelope},
};
use types::{EthSpec, SignedExecutionPayloadEnvelope};
use types::EthSpec;
use crate::{
BeaconChain, BeaconChainError, BeaconChainTypes, NotifyExecutionLayer,
@@ -18,24 +18,14 @@ use crate::{
},
};
pub trait IntoExecutionPendingEnvelope<T: BeaconChainTypes>: Sized {
fn into_execution_pending_envelope(
self,
chain: &Arc<BeaconChain<T>>,
notify_execution_layer: NotifyExecutionLayer,
) -> Result<ExecutionPendingEnvelope<T::EthSpec>, EnvelopeError>;
fn envelope(&self) -> &Arc<SignedExecutionPayloadEnvelope<T::EthSpec>>;
}
pub struct ExecutionPendingEnvelope<E: EthSpec> {
pub signed_envelope: MaybeAvailableEnvelope<E>,
pub import_data: EnvelopeImportData<E>,
pub payload_verification_handle: PayloadVerificationHandle,
}
impl<T: BeaconChainTypes> IntoExecutionPendingEnvelope<T> for GossipVerifiedEnvelope<T> {
fn into_execution_pending_envelope(
impl<T: BeaconChainTypes> GossipVerifiedEnvelope<T> {
pub fn into_execution_pending_envelope(
self,
chain: &Arc<BeaconChain<T>>,
notify_execution_layer: NotifyExecutionLayer,
@@ -116,25 +106,4 @@ impl<T: BeaconChainTypes> IntoExecutionPendingEnvelope<T> for GossipVerifiedEnve
payload_verification_handle,
})
}
fn envelope(&self) -> &Arc<SignedExecutionPayloadEnvelope<T::EthSpec>> {
&self.signed_envelope
}
}
impl<T: BeaconChainTypes> IntoExecutionPendingEnvelope<T>
for Arc<SignedExecutionPayloadEnvelope<T::EthSpec>>
{
fn into_execution_pending_envelope(
self,
chain: &Arc<BeaconChain<T>>,
notify_execution_layer: NotifyExecutionLayer,
) -> Result<ExecutionPendingEnvelope<T::EthSpec>, EnvelopeError> {
GossipVerifiedEnvelope::new(self, &chain.gossip_verification_context())?
.into_execution_pending_envelope(chain, notify_execution_layer)
}
fn envelope(&self) -> &Arc<SignedExecutionPayloadEnvelope<T::EthSpec>> {
self
}
}

View File

@@ -248,7 +248,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
///
/// ## Errors
///
/// Returns an `Err` if the given envelope was invalid, or an error was encountered during
/// Returns an `Err` if the given envelope was invalid, or an error was encountered during verification.
pub async fn verify_envelope_for_gossip(
self: &Arc<Self>,
envelope: Arc<SignedExecutionPayloadEnvelope<T::EthSpec>>,

View File

@@ -10,14 +10,14 @@ use types::{BeaconState, BlockImportSource, Hash256, SignedBeaconBlock, Slot};
use super::{
AvailableEnvelope, AvailableExecutedEnvelope, EnvelopeError, EnvelopeImportData,
ExecutedEnvelope, IntoExecutionPendingEnvelope, MaybeAvailableEnvelope,
ExecutedEnvelope, gossip_verified_envelope::GossipVerifiedEnvelope,
};
use crate::{
AvailabilityProcessingStatus, BeaconChain, BeaconChainError, BeaconChainTypes,
NotifyExecutionLayer,
block_verification_types::{AsBlock, AvailableBlockData},
metrics,
payload_envelope_verification::ExecutionPendingEnvelope,
payload_envelope_verification::{ExecutionPendingEnvelope, MaybeAvailableEnvelope},
validator_monitor::{get_slot_delay_ms, timestamp_now},
};
use eth2::types::{EventKind, SseExecutionPayloadAvailable};
@@ -26,25 +26,20 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
/// Returns `Ok(block_root)` if the given `unverified_envelope` was successfully verified and
/// imported into the chain.
///
/// Items that implement `IntoExecutionPendingEnvelope` include:
///
/// - `GossipVerifiedEnvelope`
/// - TODO(gloas) implement for envelopes recieved over RPC
///
/// ## Errors
///
/// Returns an `Err` if the given block was invalid, or an error was encountered during
/// Returns an `Err` if the given payload envelope was invalid, or an error was encountered during
/// verification.
#[instrument(skip_all, fields(block_root = ?block_root, block_source = %block_source))]
pub async fn process_execution_payload_envelope<P: IntoExecutionPendingEnvelope<T>>(
pub async fn process_execution_payload_envelope(
self: &Arc<Self>,
block_root: Hash256,
unverified_envelope: P,
unverified_envelope: GossipVerifiedEnvelope<T>,
notify_execution_layer: NotifyExecutionLayer,
block_source: BlockImportSource,
publish_fn: impl FnOnce() -> Result<(), EnvelopeError>,
) -> Result<AvailabilityProcessingStatus, EnvelopeError> {
let block_slot = unverified_envelope.envelope().slot();
let block_slot = unverified_envelope.signed_envelope.slot();
// Set observed time if not already set. Usually this should be set by gossip or RPC,
// but just in case we set it again here (useful for tests).
@@ -110,9 +105,9 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
}
};
// Verify and import the block.
// Verify and import the payload envelope.
match import_envelope.await {
// The block was successfully verified and imported. Yay.
// The payload envelope was successfully verified and imported. Yay.
Ok(status @ AvailabilityProcessingStatus::Imported(block_root)) => {
info!(
?block_root,
@@ -126,7 +121,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
Ok(status)
}
Ok(status @ AvailabilityProcessingStatus::MissingComponents(slot, block_root)) => {
debug!(?block_root, %slot, "Beacon block awaiting blobs");
debug!(?block_root, %slot, "Payload envelope awaiting blobs");
Ok(status)
}
@@ -139,7 +134,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
);
}
_ => {
// There was an error whilst attempting to verify and import the block. The block might
// There was an error whilst attempting to verify and import the payload envelope. It might
// be partially verified or partially imported.
crit!(
error = ?e,
@@ -149,7 +144,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
};
Err(EnvelopeError::BeaconChainError(e))
}
// The block failed verification.
// The payload envelope failed verification.
Err(other) => {
warn!(
reason = other.to_string(),
@@ -165,7 +160,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
///
/// An error is returned if the verification handle couldn't be awaited.
#[instrument(skip_all, level = "debug")]
pub async fn into_executed_payload_envelope(
async fn into_executed_payload_envelope(
self: Arc<Self>,
pending_envelope: ExecutionPendingEnvelope<T::EthSpec>,
) -> Result<ExecutedEnvelope<T::EthSpec>, EnvelopeError> {
@@ -278,6 +273,8 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
return Err(EnvelopeError::BlockRootUnknown { block_root });
}
// TODO(gloas) no fork choice logic yet
// Take an exclusive write-lock on fork choice. It's very important to prevent deadlocks by
// avoiding taking other locks whilst holding this lock.
let mut fork_choice = parking_lot::RwLockUpgradableReadGuard::upgrade(fork_choice_reader);
@@ -349,6 +346,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
error = ?e,
"Database write failed!"
);
return Err(e.into());
// TODO(gloas) handle db write failure
// return Err(self
// .handle_import_block_db_write_error(fork_choice)

View File

@@ -3,27 +3,18 @@
//! types, starting at a `SignedExecutionPayloadEnvelope` and finishing with an `AvailableExecutedEnvelope` (see
//! diagram below).
//!
//! // TODO(gloas) we might want to update this diagram to include `AvailabelExecutedEnvelope`
//! ```ignore
//! START
//! |
//! ▼
//! SignedExecutionPayloadEnvelope
//! |
//! |---------------
//! | |
//! | ▼
//! | GossipVerifiedEnvelope
//! | |
//! |---------------
//!
//! GossipVerifiedEnvelope
//! |
//! ▼
//! ExecutionPendingEnvelope
//! |
//! await
//! |
//! ▼
//! END
//! ExecutedEnvelope
//!
//! ```
@@ -48,7 +39,7 @@ pub mod gossip_verified_envelope;
pub mod import;
mod payload_notifier;
pub use execution_pending_envelope::{ExecutionPendingEnvelope, IntoExecutionPendingEnvelope};
pub use execution_pending_envelope::ExecutionPendingEnvelope;
#[derive(PartialEq)]
pub struct EnvelopeImportData<E: EthSpec> {
@@ -63,7 +54,7 @@ pub struct AvailableEnvelope<E: EthSpec> {
execution_block_hash: ExecutionBlockHash,
envelope: Arc<SignedExecutionPayloadEnvelope<E>>,
columns: DataColumnSidecarList<E>,
/// Timestamp at which this block first became available (UNIX timestamp, time since 1970).
/// Timestamp at which this envelope first became available (UNIX timestamp, time since 1970).
columns_available_timestamp: Option<std::time::Duration>,
pub spec: Arc<ChainSpec>,
}
@@ -111,7 +102,7 @@ pub enum MaybeAvailableEnvelope<E: EthSpec> {
},
}
/// This snapshot is to be used for verifying a envelope of the block.
/// This snapshot is to be used for verifying a payload envelope.
#[derive(Debug, Clone)]
pub struct EnvelopeProcessingSnapshot<E: EthSpec> {
/// This state is equivalent to the `self.beacon_block.state_root()` before applying the envelope.
@@ -183,54 +174,41 @@ impl<E: EthSpec> AvailableExecutedEnvelope<E> {
#[derive(Debug)]
pub enum EnvelopeError {
/// The envelope's block root is unknown.
BlockRootUnknown {
block_root: Hash256,
},
BlockRootUnknown { block_root: Hash256 },
/// The signature is invalid.
BadSignature,
/// The builder index doesn't match the committed bid
BuilderIndexMismatch {
committed_bid: u64,
envelope: u64,
},
// The envelope slot doesn't match the block
SlotMismatch {
block: Slot,
envelope: Slot,
},
// The validator index is unknown
UnknownValidator {
builder_index: u64,
},
// The block hash doesn't match the committed bid
BuilderIndexMismatch { committed_bid: u64, envelope: u64 },
/// The envelope slot doesn't match the block
SlotMismatch { block: Slot, envelope: Slot },
/// The validator index is unknown
UnknownValidator { builder_index: u64 },
/// The block hash doesn't match the committed bid
BlockHashMismatch {
committed_bid: ExecutionBlockHash,
envelope: ExecutionBlockHash,
},
// The block's proposer_index does not match the locally computed proposer
IncorrectBlockProposer {
block: u64,
local_shuffling: u64,
},
// The slot belongs to a block that is from a slot prior than
// the most recently finalized slot
/// The block's proposer_index does not match the locally computed proposer
IncorrectBlockProposer { block: u64, local_shuffling: u64 },
/// The slot belongs to a block that is from a slot prior than
/// to most recently finalized slot
PriorToFinalization {
payload_slot: Slot,
latest_finalized_slot: Slot,
},
// Some Beacon Chain Error
/// Some Beacon Chain Error
BeaconChainError(Arc<BeaconChainError>),
// Some Beacon State error
/// Some Beacon State error
BeaconStateError(BeaconStateError),
// Some BlockProcessingError (for electra operations)
/// Some BlockProcessingError (for electra operations)
BlockProcessingError(BlockProcessingError),
// Some EnvelopeProcessingError
/// Some EnvelopeProcessingError
EnvelopeProcessingError(EnvelopeProcessingError),
// Error verifying the execution payload
/// Error verifying the execution payload
ExecutionPayloadError(ExecutionPayloadError),
// An error from block-level checks reused during envelope import
/// An error from block-level checks reused during envelope import
BlockError(BlockError),
// Internal error
/// Internal error
InternalError(String),
}