merge conflicts

This commit is contained in:
Eitan Seri-Levi
2026-04-28 16:38:11 +02:00
8 changed files with 543 additions and 40 deletions

View File

@@ -942,12 +942,18 @@ impl<T: BeaconChainTypes> GossipVerifiedBlock<T> {
// Check that we've received the parent envelope. If not, issue a single envelope
// lookup for the parent and queue this block in the reprocess queue.
//
// The anchor block (proto-array root) is implicitly considered to have its payload
// received: there is no envelope to fetch for the anchor (per spec, the anchor is
// never added to `store.payloads`), and the anchor is trusted by definition.
let parent_is_gloas = chain
.spec
.fork_name_at_slot::<T::EthSpec>(parent_block.slot)
.gloas_enabled();
let parent_is_anchor = parent_block.parent_root.is_none();
if parent_is_gloas
&& !parent_is_anchor
&& !fork_choice_read_lock.is_payload_received(&block.message().parent_root())
{
return Err(BlockError::ParentEnvelopeUnknown {

View File

@@ -14,7 +14,8 @@ use super::{
};
use crate::{
AvailabilityProcessingStatus, BeaconChain, BeaconChainError, BeaconChainTypes,
NotifyExecutionLayer, block_verification_types::AvailableBlockData, metrics,
NotifyExecutionLayer, block_verification::PayloadVerificationOutcome,
block_verification_types::AvailableBlockData, metrics,
payload_envelope_verification::ExecutionPendingEnvelope, validator_monitor::get_slot_delay_ms,
};
@@ -99,9 +100,18 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
self.import_available_execution_payload_envelope(Box::new(envelope))
.await
}
ExecutedEnvelope::AvailabilityPending() => Err(EnvelopeError::InternalError(
"Pending payload envelope not yet implemented".to_owned(),
)),
ExecutedEnvelope::AvailabilityPending {
signed_envelope,
import_data,
payload_verification_outcome,
} => {
self.import_pending_execution_payload_envelope(
signed_envelope,
import_data,
payload_verification_outcome,
)
.await
}
}
};
@@ -186,6 +196,39 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
))
}
/// Import an envelope whose data column availability has not yet been satisfied.
///
/// Marks the block's payload as received in fork choice and persists the envelope to the
/// store, but does not write data column ops. Columns are expected to arrive separately
/// (gossip, engineGetBlobs, or reconstruction).
#[instrument(skip_all)]
pub async fn import_pending_execution_payload_envelope(
self: &Arc<Self>,
signed_envelope: Arc<SignedExecutionPayloadEnvelope<T::EthSpec>>,
import_data: EnvelopeImportData<T::EthSpec>,
payload_verification_outcome: PayloadVerificationOutcome,
) -> Result<AvailabilityProcessingStatus, EnvelopeError> {
let EnvelopeImportData {
block_root,
_phantom,
} = import_data;
let block_root = {
let chain = self.clone();
self.spawn_blocking_handle(
move || {
chain.import_execution_payload_envelope_pending_columns(
signed_envelope,
block_root,
payload_verification_outcome.payload_verification_status,
)
},
"payload_verification_handle",
)
.await??
};
Ok(AvailabilityProcessingStatus::Imported(block_root))
}
#[instrument(skip_all)]
pub async fn import_available_execution_payload_envelope(
self: &Arc<Self>,
@@ -220,6 +263,50 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
Ok(AvailabilityProcessingStatus::Imported(block_root))
}
/// Same as `import_execution_payload_envelope` but for envelopes whose data columns
/// have not yet been received. Marks the payload as received in fork choice and
/// persists the envelope; columns are persisted separately as they arrive.
#[instrument(skip_all)]
fn import_execution_payload_envelope_pending_columns(
&self,
signed_envelope: Arc<SignedExecutionPayloadEnvelope<T::EthSpec>>,
block_root: Hash256,
payload_verification_status: PayloadVerificationStatus,
) -> Result<Hash256, EnvelopeError> {
let fork_choice_reader = self.canonical_head.fork_choice_upgradable_read_lock();
if !fork_choice_reader.contains_block(&block_root) {
return Err(EnvelopeError::BlockRootUnknown { block_root });
}
let mut fork_choice = parking_lot::RwLockUpgradableReadGuard::upgrade(fork_choice_reader);
fork_choice
.on_valid_payload_envelope_received(block_root)
.map_err(|e| EnvelopeError::InternalError(format!("{e:?}")))?;
let db_write_timer = metrics::start_timer(&metrics::ENVELOPE_PROCESSING_DB_WRITE);
let ops = vec![StoreOp::PutPayloadEnvelope(
block_root,
signed_envelope.clone(),
)];
let db_span = info_span!("persist_envelope_pending_columns").entered();
if let Err(e) = self.store.do_atomically_with_block_and_blobs_cache(ops) {
error!(error = ?e, "Database write failed for pending-columns envelope");
return Err(e.into());
}
drop(db_span);
drop(fork_choice);
let envelope_time_imported = self.slot_clock.now_duration().unwrap_or(Duration::MAX);
metrics::stop_timer(db_write_timer);
self.import_envelope_update_metrics_and_events(
signed_envelope,
block_root,
payload_verification_status,
envelope_time_imported,
);
Ok(block_root)
}
/// Accepts a fully-verified and available envelope and imports it into the chain without performing any
/// additional verification.
///

View File

@@ -119,12 +119,16 @@ pub struct EnvelopeProcessingSnapshot<E: EthSpec> {
/// 1. `Available`: This envelope has been executed and also contains all data to consider it
/// fully available.
/// 2. `AvailabilityPending`: This envelope hasn't received all required blobs to consider it
/// fully available.
#[allow(dead_code)]
/// fully available. The envelope is still imported (fork-choice marks the block's payload
/// as received and the envelope is persisted); column persistence is handled separately
/// via gossip / engineGetBlobs as columns arrive.
pub enum ExecutedEnvelope<E: EthSpec> {
Available(AvailableExecutedEnvelope<E>),
// TODO(gloas): check data column availability via DA checker
AvailabilityPending(),
AvailabilityPending {
signed_envelope: Arc<SignedExecutionPayloadEnvelope<E>>,
import_data: EnvelopeImportData<E>,
payload_verification_outcome: PayloadVerificationOutcome,
},
}
impl<E: EthSpec> ExecutedEnvelope<E> {
@@ -142,15 +146,14 @@ impl<E: EthSpec> ExecutedEnvelope<E> {
payload_verification_outcome,
))
}
// TODO(gloas): check data column availability via DA checker
MaybeAvailableEnvelope::AvailabilityPending {
block_hash,
envelope,
} => Self::Available(AvailableExecutedEnvelope::new(
AvailableEnvelope::new(block_hash, envelope, vec![], None, spec),
block_hash: _,
envelope: signed_envelope,
} => Self::AvailabilityPending {
signed_envelope,
import_data,
payload_verification_outcome,
)),
},
}
}
}