diff --git a/crates/client/flashblocks/src/error.rs b/crates/client/flashblocks/src/error.rs index 3af9b0db..e9e4449d 100644 --- a/crates/client/flashblocks/src/error.rs +++ b/crates/client/flashblocks/src/error.rs @@ -24,9 +24,8 @@ pub enum ProtocolError { #[derive(Debug, Clone, Eq, PartialEq, Error)] pub enum ProviderError { /// Missing canonical header for a given block number. - #[error( - "missing canonical header for block {block_number}. This can be ignored if the node has recently restarted, restored from a snapshot or is still syncing." - )] + /// This typically occurs during node startup, snapshot restore, or while syncing. + #[error("missing canonical header for block {block_number}")] MissingCanonicalHeader { /// The block number for which the header is missing. block_number: u64, @@ -169,7 +168,7 @@ mod tests { #[rstest] #[case::missing_canonical_header( ProviderError::MissingCanonicalHeader { block_number: 12345 }, - "missing canonical header for block 12345. This can be ignored if the node has recently restarted, restored from a snapshot or is still syncing." + "missing canonical header for block 12345" )] #[case::state_provider( ProviderError::StateProvider("connection failed".to_string()), diff --git a/crates/client/flashblocks/src/metrics.rs b/crates/client/flashblocks/src/metrics.rs index 7c8d511e..50fa5dbf 100644 --- a/crates/client/flashblocks/src/metrics.rs +++ b/crates/client/flashblocks/src/metrics.rs @@ -39,6 +39,12 @@ pub struct Metrics { #[metric(describe = "Count of times flashblocks are unable to be converted to blocks")] pub block_processing_error: Counter, + /// Count of times Flashblock processing was paused waiting for canonical chain sync. + #[metric( + describe = "Count of times Flashblock processing was paused waiting for canonical chain sync" + )] + pub canonical_sync_wait: Counter, + /// Count of times pending snapshot was cleared because canonical caught up. #[metric( describe = "Number of times pending snapshot was cleared because canonical caught up" diff --git a/crates/client/flashblocks/src/processor.rs b/crates/client/flashblocks/src/processor.rs index 3310c9a3..bfc649d6 100644 --- a/crates/client/flashblocks/src/processor.rs +++ b/crates/client/flashblocks/src/processor.rs @@ -29,7 +29,7 @@ use tokio::sync::{Mutex, broadcast::Sender, mpsc::UnboundedReceiver}; use crate::{ ExecutionError, Metrics, PendingBlocks, PendingBlocksBuilder, PendingStateBuilder, - ProtocolError, ProviderError, Result, + ProtocolError, ProviderError, Result, StateProcessorError, validation::{ CanonicalBlockReconciler, FlashblockSequenceValidator, ReconciliationStrategy, ReorgDetector, SequenceValidationResult, @@ -108,8 +108,26 @@ where self.metrics.block_processing_duration.record(start_time.elapsed()); } Err(e) => { - error!(message = "could not process Flashblock", error = %e); - self.metrics.block_processing_error.increment(1); + // Handle missing canonical header separately - this is expected during + // node startup, snapshot restore, or when still syncing + if let StateProcessorError::Provider( + ProviderError::MissingCanonicalHeader { block_number }, + ) = &e + { + // Use WARN level so operators can see this, but it won't trigger error alerts + // Include detailed context so operators understand exactly what's happening + warn!( + message = "Flashblock processing paused - waiting for canonical chain sync", + required_block = block_number, + flashblock_block = flashblock.metadata.block_number, + flashblock_index = flashblock.index, + hint = "node will resume Flashblock processing once canonical chain syncs to required height" + ); + self.metrics.canonical_sync_wait.increment(1); + } else { + error!(message = "could not process Flashblock", error = %e); + self.metrics.block_processing_error.increment(1); + } } } }