mirror of
https://github.com/sigp/lighthouse.git
synced 2026-06-30 19:34:37 +00:00
Gloas attestation payload reprocess (#9440)
Handle payload-present attestations before the payload is seen (gloas) A gloas beacon_attestation with index == 1 claims a past block's payload is already present. If we haven't seen that block's payload envelope yet, we shouldn't reject it the envelope may just be in flight. So instead we IGNORE it (new AttnError::UnknownPayloadEnvelope), ask sync to fetch the envelope, and park the attestation in the reprocess queue. When the envelope is imported, the parked attestations are released and re-verified. The envelope lookup itself is stubbed here and wired up in #9155 or a follow up PR Co-Authored-By: dapplion <35266934+dapplion@users.noreply.github.com> Co-Authored-By: Eitan Seri-Levi <eserilev@ucsc.edu>
This commit is contained in:
@@ -163,7 +163,7 @@ pub async fn publish_execution_payload_envelope<T: BeaconChainTypes>(
|
||||
.await;
|
||||
|
||||
let mut envelope_imported = match &import_result {
|
||||
Ok(AvailabilityProcessingStatus::Imported(_)) => true,
|
||||
Ok(AvailabilityProcessingStatus::Imported(_, _)) => true,
|
||||
Ok(AvailabilityProcessingStatus::MissingComponents(_, _)) => false,
|
||||
Err(e) => {
|
||||
warn!(%slot, error = ?e, "Failed to import execution payload envelope");
|
||||
@@ -210,7 +210,7 @@ pub async fn publish_execution_payload_envelope<T: BeaconChainTypes>(
|
||||
if !sampling_columns.is_empty() {
|
||||
match Box::pin(chain.process_gossip_data_columns(sampling_columns, || Ok(()))).await
|
||||
{
|
||||
Ok(AvailabilityProcessingStatus::Imported(_)) => envelope_imported = true,
|
||||
Ok(AvailabilityProcessingStatus::Imported(_, _)) => envelope_imported = true,
|
||||
Ok(AvailabilityProcessingStatus::MissingComponents(_, _)) => {}
|
||||
Err(e) => {
|
||||
error!(
|
||||
|
||||
@@ -189,6 +189,46 @@ pub async fn publish_attestations<T: BeaconChainTypes>(
|
||||
PublishAttestationResult::Reprocessing(rx)
|
||||
}
|
||||
}
|
||||
Err(Error::Validation(AttestationError::UnknownPayloadEnvelope {
|
||||
beacon_block_root,
|
||||
})) => {
|
||||
if !allow_reprocess {
|
||||
return PublishAttestationResult::Failure(Error::ReprocessDisabled);
|
||||
};
|
||||
// Re-process once the block's payload envelope is seen (Gloas).
|
||||
let (tx, rx) = oneshot::channel();
|
||||
let reprocess_chain = chain.clone();
|
||||
let reprocess_network_tx = network_tx.clone();
|
||||
let reprocess_fn = move || {
|
||||
let result = verify_and_publish_attestation(
|
||||
&reprocess_chain,
|
||||
&attestation,
|
||||
seen_timestamp,
|
||||
&reprocess_network_tx,
|
||||
);
|
||||
// Ignore failure on the oneshot that reports the result. This
|
||||
// shouldn't happen unless some catastrophe befalls the waiting
|
||||
// thread which causes it to drop.
|
||||
let _ = tx.send(result);
|
||||
};
|
||||
let reprocess_msg = ReprocessQueueMessage::UnknownPayloadUnaggregate(
|
||||
QueuedUnaggregate {
|
||||
beacon_block_root,
|
||||
process_fn: Box::new(reprocess_fn),
|
||||
},
|
||||
);
|
||||
if task_spawner
|
||||
.try_send(WorkEvent {
|
||||
drop_during_sync: false,
|
||||
work: Work::Reprocess(reprocess_msg),
|
||||
})
|
||||
.is_err()
|
||||
{
|
||||
PublishAttestationResult::Failure(Error::ReprocessFull)
|
||||
} else {
|
||||
PublishAttestationResult::Reprocessing(rx)
|
||||
}
|
||||
}
|
||||
Err(Error::Validation(AttestationError::PriorAttestationKnown {
|
||||
..
|
||||
})) => PublishAttestationResult::AlreadyKnown,
|
||||
|
||||
@@ -266,7 +266,7 @@ pub async fn publish_block<T: BeaconChainTypes, B: IntoGossipVerifiedBlock<T>>(
|
||||
Err(BlockError::DuplicateFullyImported(root)) => {
|
||||
if publish_fn_completed.load(Ordering::SeqCst) {
|
||||
post_block_import_logging_and_response(
|
||||
Ok(AvailabilityProcessingStatus::Imported(root)),
|
||||
Ok(AvailabilityProcessingStatus::Imported(slot, root)),
|
||||
validation_level,
|
||||
block,
|
||||
is_locally_built_block,
|
||||
@@ -474,7 +474,7 @@ async fn post_block_import_logging_and_response<T: BeaconChainTypes>(
|
||||
// result of the block being imported from gossip, OR it could be that it finished importing
|
||||
// after processing of a gossip blob. In the latter case we MUST run fork choice to
|
||||
// re-compute the head.
|
||||
Ok(AvailabilityProcessingStatus::Imported(root))
|
||||
Ok(AvailabilityProcessingStatus::Imported(_, root))
|
||||
| Err(BlockError::DuplicateFullyImported(root)) => {
|
||||
let delay = get_block_delay_ms(seen_timestamp, block.message(), &chain.slot_clock);
|
||||
info!(
|
||||
|
||||
@@ -876,7 +876,6 @@ async fn queue_attestations_from_http() {
|
||||
|
||||
// In parallel, apply the block. We need to manually notify the reprocess queue, because the
|
||||
// `beacon_chain` does not know about the queue and will not update it for us.
|
||||
let parent_root = block.0.parent_root();
|
||||
harness
|
||||
.process_block(attestation_slot, block_root, block)
|
||||
.await
|
||||
@@ -888,10 +887,7 @@ async fn queue_attestations_from_http() {
|
||||
.unwrap()
|
||||
.try_send(WorkEvent {
|
||||
drop_during_sync: false,
|
||||
work: Work::Reprocess(ReprocessQueueMessage::BlockImported {
|
||||
block_root,
|
||||
parent_root,
|
||||
}),
|
||||
work: Work::Reprocess(ReprocessQueueMessage::BlockImported { block_root }),
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user