Unknown block for envelope (#8992)

Add a queue that allows us to reprocess an envelope when it arrives over gossip references a unknown block root. When the block is finally imported, we immediately reprocess the queued envelope.

Note that we don't trigger a block lookup sync. Incoming attestations for this block root will already trigger a lookup for us. I think thats good enough


  


Co-Authored-By: Eitan Seri- Levi <eserilev@gmail.com>
This commit is contained in:
Eitan Seri-Levi
2026-03-17 16:35:05 +09:00
committed by GitHub
parent 95b99ee724
commit 17d183eb5b
5 changed files with 383 additions and 4 deletions

View File

@@ -20,7 +20,9 @@ use beacon_chain::{
};
use beacon_chain::{
blob_verification::{GossipBlobError, GossipVerifiedBlob},
payload_envelope_verification::gossip_verified_envelope::GossipVerifiedEnvelope,
payload_envelope_verification::{
EnvelopeError, gossip_verified_envelope::GossipVerifiedEnvelope,
},
};
use beacon_processor::{Work, WorkEvent};
use lighthouse_network::{Client, MessageAcceptance, MessageId, PeerAction, PeerId, ReportSource};
@@ -49,8 +51,8 @@ use beacon_processor::work_reprocessing_queue::QueuedColumnReconstruction;
use beacon_processor::{
DuplicateCache, GossipAggregatePackage, GossipAttestationBatch,
work_reprocessing_queue::{
QueuedAggregate, QueuedGossipBlock, QueuedLightClientUpdate, QueuedUnaggregate,
ReprocessQueueMessage,
QueuedAggregate, QueuedGossipBlock, QueuedGossipEnvelope, QueuedLightClientUpdate,
QueuedUnaggregate, ReprocessQueueMessage,
},
};
@@ -3332,6 +3334,61 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
verified_envelope
}
Err(EnvelopeError::BlockRootUnknown { block_root }) => {
let envelope_slot = envelope.slot();
debug!(
?block_root,
%envelope_slot,
"Envelope references unknown block, deferring to reprocess queue"
);
self.propagate_validation_result(message_id, peer_id, MessageAcceptance::Ignore);
let inner_self = self.clone();
let chain = self.chain.clone();
let process_fn = Box::pin(async move {
match chain.verify_envelope_for_gossip(envelope).await {
Ok(verified_envelope) => {
inner_self
.process_gossip_verified_execution_payload_envelope(
peer_id,
verified_envelope,
)
.await;
}
Err(e) => {
debug!(
error = ?e,
"Deferred envelope failed verification"
);
}
}
});
if self
.beacon_processor_send
.try_send(WorkEvent {
drop_during_sync: false,
work: Work::Reprocess(ReprocessQueueMessage::UnknownBlockForEnvelope(
QueuedGossipEnvelope {
beacon_block_slot: envelope_slot,
beacon_block_root: block_root,
process_fn,
},
)),
})
.is_err()
{
error!(
%envelope_slot,
?block_root,
"Failed to defer envelope import"
);
}
return None;
}
// TODO(gloas) penalize peers accordingly
Err(_) => return None,
};

View File

@@ -2090,3 +2090,8 @@ async fn test_data_columns_by_range_no_duplicates_with_skip_slots() {
unique_roots.len(),
);
}
// TODO(ePBS): Add integration tests for envelope deferral (UnknownBlockForEnvelope):
// 1. Gossip envelope arrives before its block → queued via UnknownBlockForEnvelope
// 2. Block imported → envelope released and processed successfully
// 3. Timeout path → envelope released and re-verified