error handling and wiring up

This commit is contained in:
Daniel Knopik
2026-04-29 15:35:31 +02:00
parent 58fd3dde40
commit 2d3354551e
15 changed files with 132 additions and 84 deletions

View File

@@ -1,5 +1,5 @@
use beacon_chain::{
AvailabilityProcessingStatus, BlockError, attestation_verification::Error as AttnError,
AvailabilityProcessingStatus, attestation_verification::Error as AttnError,
light_client_finality_update_verification::Error as LightClientFinalityUpdateError,
light_client_optimistic_update_verification::Error as LightClientOptimisticUpdateError,
sync_committee_verification::Error as SyncCommitteeError,
@@ -733,7 +733,7 @@ pub fn register_sync_committee_error(error: &SyncCommitteeError) {
}
pub(crate) fn register_process_result_metrics(
result: &std::result::Result<AvailabilityProcessingStatus, BlockError>,
result: &std::result::Result<AvailabilityProcessingStatus, impl AsRef<str>>,
source: BlockSource,
block_component: &'static str,
) {

View File

@@ -14,8 +14,8 @@ use beacon_chain::payload_bid_verification::PayloadBidError;
use beacon_chain::proposer_preferences_verification::ProposerPreferencesError;
use beacon_chain::store::Error;
use beacon_chain::{
AvailabilityProcessingStatus, BeaconChainError, BeaconChainTypes, BlockError, ForkChoiceError,
GossipVerifiedBlock, NotifyExecutionLayer,
AvailabilityProcessingStatus, BeaconChainError, BeaconChainTypes, BlockError,
BlockOrEnvelopeError, ForkChoiceError, GossipVerifiedBlock, NotifyExecutionLayer,
attestation_verification::{self, Error as AttnError, VerifiedAttestation},
data_availability_checker::AvailabilityCheckErrorCategory,
light_client_finality_update_verification::Error as LightClientFinalityUpdateError,
@@ -1387,7 +1387,7 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
self.check_reconstruction_trigger(slot, &block_root).await;
}
},
Err(BlockError::DuplicateFullyImported(_)) => {
Err(BlockOrEnvelopeError::BlockError(BlockError::DuplicateFullyImported(_))) => {
debug!(
?block_root,
data_column_index, "Ignoring gossip column already imported"
@@ -1518,7 +1518,7 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
self.check_reconstruction_trigger(*slot, block_root).await;
}
},
Err(BlockError::DuplicateFullyImported(_)) => {
Err(BlockOrEnvelopeError::BlockError(BlockError::DuplicateFullyImported(_))) => {
debug!(
?block_root,
data_column_index, "Ignoring completed gossip column already imported"

View File

@@ -7,7 +7,9 @@ use beacon_chain::data_column_verification::{GossipDataColumnError, observe_goss
use beacon_chain::fetch_blobs::{
EngineGetBlobsOutput, FetchEngineBlobError, fetch_and_process_engine_blobs,
};
use beacon_chain::{AvailabilityProcessingStatus, BeaconChain, BeaconChainTypes, BlockError};
use beacon_chain::{
AvailabilityProcessingStatus, BeaconChain, BeaconChainTypes, BlockError, BlockOrEnvelopeError,
};
use beacon_processor::{
BeaconProcessorSend, DuplicateCache, GossipAggregatePackage, GossipAttestationPackage, Work,
WorkEvent as BeaconWorkEvent,
@@ -980,9 +982,10 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
"Fetch blobs completed without import"
);
}
Err(FetchEngineBlobError::BlobProcessingError(BlockError::DuplicateFullyImported(
..,
))) => {
Err(FetchEngineBlobError::BlobProcessingError(e))
if let BlockOrEnvelopeError::BlockError(BlockError::DuplicateFullyImported(..)) =
*e =>
{
debug!(
%block_root,
"Fetch blobs duplicate import"
@@ -1050,7 +1053,7 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
"Reconstruction not required for block"
);
}
Err(BlockError::DuplicateFullyImported(_)) => {
Err(BlockOrEnvelopeError::BlockError(BlockError::DuplicateFullyImported(_))) => {
debug!("Block already imported in parallel with reconstruction");
}
Err(e) => {

View File

@@ -11,8 +11,9 @@ use beacon_chain::block_verification_types::{AsBlock, RangeSyncBlock};
use beacon_chain::data_availability_checker::AvailabilityCheckError;
use beacon_chain::historical_data_columns::HistoricalDataColumnError;
use beacon_chain::{
AvailabilityProcessingStatus, BeaconChainTypes, BlockError, ChainSegmentResult,
HistoricalBlockError, NotifyExecutionLayer, validator_monitor::get_slot_delay_ms,
AvailabilityProcessingStatus, BeaconChainTypes, BlockError, BlockOrEnvelopeError,
ChainSegmentResult, HistoricalBlockError, NotifyExecutionLayer,
validator_monitor::get_slot_delay_ms,
};
use beacon_processor::{
AsyncFn, BlockingFn, DuplicateCache,
@@ -234,7 +235,7 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
// Sync handles these results
self.send_sync_message(SyncMessage::BlockComponentProcessed {
process_type,
result: result.into(),
result: result.map_err(Into::into).into(),
});
// Drop the handle to remove the entry from the cache
@@ -345,7 +346,7 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
// Sync handles these results
self.send_sync_message(SyncMessage::BlockComponentProcessed {
process_type,
result: result.into(),
result: result.map_err(Into::into).into(),
});
}
@@ -410,7 +411,7 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
);
}
},
Err(BlockError::DuplicateFullyImported(_)) => {
Err(BlockOrEnvelopeError::BlockError(BlockError::DuplicateFullyImported(_))) => {
debug!(
block_hash = %block_root,
"Custody columns have already been imported"

View File

@@ -33,7 +33,9 @@ use beacon_chain::block_verification_types::AsBlock;
use beacon_chain::data_availability_checker::{
AvailabilityCheckError, AvailabilityCheckErrorCategory,
};
use beacon_chain::{AvailabilityProcessingStatus, BeaconChainTypes, BlockError};
use beacon_chain::{
AvailabilityProcessingStatus, BeaconChainTypes, BlockError, BlockOrEnvelopeError,
};
pub use common::RequestState;
use fnv::FnvHashMap;
use lighthouse_network::service::api_types::SingleLookupReqId;
@@ -589,8 +591,12 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
let action = match result {
BlockProcessingResult::Ok(AvailabilityProcessingStatus::Imported(_))
| BlockProcessingResult::Err(BlockError::DuplicateFullyImported(..))
| BlockProcessingResult::Err(BlockError::GenesisBlock) => {
| BlockProcessingResult::Err(BlockOrEnvelopeError::BlockError(
BlockError::DuplicateFullyImported(..),
))
| BlockProcessingResult::Err(BlockOrEnvelopeError::BlockError(
BlockError::GenesisBlock,
)) => {
// Successfully imported
request_state.on_processing_success()?;
Action::Continue
@@ -614,7 +620,9 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
Action::Retry
}
}
BlockProcessingResult::Err(BlockError::DuplicateImportStatusUnknown(..)) => {
BlockProcessingResult::Err(BlockOrEnvelopeError::BlockError(
BlockError::DuplicateImportStatusUnknown(..),
)) => {
// This is unreachable because RPC blocks do not undergo gossip verification, and
// this error can *only* come from gossip verification.
error!(?block_root, "Single block lookup hit unreachable condition");
@@ -630,6 +638,11 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
Action::Drop("Block processing ignored".to_owned())
}
BlockProcessingResult::Err(e) => {
let BlockOrEnvelopeError::BlockError(e) = e else {
// TODO(gloas): handle properly
return Err(LookupRequestError::Failed(format!("{e:?}")));
};
match e {
BlockError::BeaconChainError(e) => {
// Internal error

View File

@@ -50,7 +50,8 @@ use crate::sync::custody_backfill_sync::CustodyBackFillSync;
use crate::sync::network_context::{PeerGroup, RpcResponseResult};
use beacon_chain::block_verification_types::AsBlock;
use beacon_chain::{
AvailabilityProcessingStatus, BeaconChain, BeaconChainTypes, BlockError, EngineState,
AvailabilityProcessingStatus, BeaconChain, BeaconChainTypes, BlockError, BlockOrEnvelopeError,
EngineState,
};
use futures::StreamExt;
use lighthouse_network::SyncInfo;
@@ -206,7 +207,7 @@ impl BlockProcessType {
#[derive(Debug)]
pub enum BlockProcessingResult {
Ok(AvailabilityProcessingStatus),
Err(BlockError),
Err(BlockOrEnvelopeError),
Ignored,
}
@@ -1449,8 +1450,8 @@ impl<T: BeaconChainTypes> SyncManager<T> {
}
}
impl From<Result<AvailabilityProcessingStatus, BlockError>> for BlockProcessingResult {
fn from(result: Result<AvailabilityProcessingStatus, BlockError>) -> Self {
impl From<Result<AvailabilityProcessingStatus, BlockOrEnvelopeError>> for BlockProcessingResult {
fn from(result: Result<AvailabilityProcessingStatus, BlockOrEnvelopeError>) -> Self {
match result {
Ok(status) => BlockProcessingResult::Ok(status),
Err(e) => BlockProcessingResult::Err(e),
@@ -1458,8 +1459,14 @@ impl From<Result<AvailabilityProcessingStatus, BlockError>> for BlockProcessingR
}
}
impl From<BlockError> for BlockProcessingResult {
fn from(e: BlockError) -> Self {
impl From<BlockOrEnvelopeError> for BlockProcessingResult {
fn from(e: BlockOrEnvelopeError) -> Self {
BlockProcessingResult::Err(e)
}
}
impl From<BlockError> for BlockProcessingResult {
fn from(e: BlockError) -> Self {
BlockProcessingResult::Err(BlockOrEnvelopeError::BlockError(e))
}
}

View File

@@ -2089,8 +2089,7 @@ async fn too_many_processing_failures(depth: usize) {
r.build_chain_and_trigger_last_block(depth).await;
// Simulate that a peer always returns empty
r.simulate(
SimulateConfig::new()
.with_process_result(|| BlockProcessingResult::Err(BlockError::BlockSlotLimitReached)),
SimulateConfig::new().with_process_result(|| BlockError::BlockSlotLimitReached.into()),
)
.await;
// We register multiple penalties, the lookup fails and sync does not progress
@@ -2158,9 +2157,10 @@ async fn test_single_block_lookup_duplicate_response() {
let mut r = TestRig::default();
r.build_chain_and_trigger_last_block(1).await;
// Send a DuplicateFullyImported response, the lookup should complete successfully
r.simulate(SimulateConfig::new().with_process_result(|| {
BlockProcessingResult::Err(BlockError::DuplicateFullyImported(Hash256::ZERO))
}))
r.simulate(
SimulateConfig::new()
.with_process_result(|| BlockError::DuplicateFullyImported(Hash256::ZERO).into()),
)
.await;
// The block was not actually imported
r.assert_head_slot(0);