@@ -451,7 +451,7 @@ impl DashSpvClient {
451451
452452 // Timer for filter gap checking
453453 let mut last_filter_gap_check = Instant :: now ( ) ;
454- let filter_gap_check_interval = std:: time:: Duration :: from_secs ( 10 ) ;
454+ let filter_gap_check_interval = std:: time:: Duration :: from_secs ( self . config . cfheader_gap_check_interval_secs ) ;
455455
456456 loop {
457457 // Check if we should stop
@@ -510,6 +510,17 @@ impl DashSpvClient {
510510 if last_status_update. elapsed ( ) >= status_update_interval {
511511 self . update_status_display ( ) . await ;
512512
513+ // Report CFHeader gap information if enabled
514+ if self . config . enable_filters {
515+ if let Ok ( ( has_gap, block_height, filter_height, gap_size) ) =
516+ self . sync_manager . filter_sync ( ) . check_cfheader_gap ( & * self . storage ) . await {
517+ if has_gap && gap_size >= 100 { // Only log significant gaps
518+ tracing:: info!( "📏 CFHeader Gap: {} block headers vs {} filter headers (gap: {})" ,
519+ block_height, filter_height, gap_size) ;
520+ }
521+ }
522+ }
523+
513524 // Report enhanced filter sync progress if active
514525 let ( filters_requested, filters_received, basic_progress, timeout, total_missing, actual_coverage, missing_ranges) =
515526 crate :: sync:: filters:: FilterSyncManager :: get_filter_sync_status_with_gaps ( & self . stats , self . sync_manager . filter_sync ( ) ) . await ;
@@ -587,6 +598,68 @@ impl DashSpvClient {
587598 . check_and_retry_missing_filters ( & mut * self . network , & * self . storage ) . await {
588599 tracing:: warn!( "Failed to check and retry missing filters: {}" , e) ;
589600 }
601+
602+ // Check for CFHeader gaps and auto-restart if needed
603+ if self . config . enable_cfheader_gap_restart {
604+ match self . sync_manager . filter_sync_mut ( )
605+ . maybe_restart_cfheader_sync_for_gap ( & mut * self . network , & mut * self . storage ) . await {
606+ Ok ( restarted) => {
607+ if restarted {
608+ tracing:: info!( "🔄 Auto-restarted CFHeader sync due to detected gap" ) ;
609+ }
610+ }
611+ Err ( e) => {
612+ tracing:: warn!( "Failed to check/restart CFHeader sync for gap: {}" , e) ;
613+ }
614+ }
615+ }
616+
617+ // Check for filter gaps and auto-restart if needed
618+ if self . config . enable_filter_gap_restart && !self . watch_items . read ( ) . await . is_empty ( ) {
619+ // Get current sync progress
620+ let progress = self . sync_progress ( ) . await ?;
621+
622+ // Check if there's a gap between synced filters and filter headers
623+ match self . sync_manager . filter_sync ( )
624+ . check_filter_gap ( & * self . storage , & progress) . await {
625+ Ok ( ( has_gap, filter_header_height, last_synced_filter, gap_size) ) => {
626+ if has_gap && gap_size >= self . config . min_filter_gap_size {
627+ tracing:: info!( "🔍 Detected filter gap: filter headers at {}, last synced filter at {} (gap: {} blocks)" ,
628+ filter_header_height, last_synced_filter, gap_size) ;
629+
630+ // Check if we're not already syncing filters
631+ if !self . sync_manager . filter_sync ( ) . is_syncing_filters ( ) {
632+ // Start filter sync for the missing range
633+ let start_height = last_synced_filter + 1 ;
634+
635+ // Limit the sync size to avoid overwhelming the system
636+ let max_sync_size = self . config . max_filter_gap_sync_size ;
637+ let sync_count = gap_size. min ( max_sync_size) ;
638+
639+ if sync_count < gap_size {
640+ tracing:: info!( "🔄 Auto-starting filter sync for gap from height {} ({} blocks of {} total gap)" ,
641+ start_height, sync_count, gap_size) ;
642+ } else {
643+ tracing:: info!( "🔄 Auto-starting filter sync for gap from height {} ({} blocks)" ,
644+ start_height, sync_count) ;
645+ }
646+
647+ match self . sync_filters_range ( Some ( start_height) , Some ( sync_count) ) . await {
648+ Ok ( _) => {
649+ tracing:: info!( "✅ Successfully started filter sync for gap" ) ;
650+ }
651+ Err ( e) => {
652+ tracing:: warn!( "Failed to start filter sync for gap: {}" , e) ;
653+ }
654+ }
655+ }
656+ }
657+ }
658+ Err ( e) => {
659+ tracing:: debug!( "Failed to check filter gap: {}" , e) ;
660+ }
661+ }
662+ }
590663 }
591664 last_filter_gap_check = Instant :: now ( ) ;
592665 }
@@ -1271,6 +1344,19 @@ impl DashSpvClient {
12711344 ) ;
12721345 coordinator. sync_and_check_filters ( num_blocks) . await
12731346 }
1347+
1348+ /// Sync filters for a specific height range.
1349+ pub async fn sync_filters_range ( & mut self , start_height : Option < u32 > , count : Option < u32 > ) -> Result < ( ) > {
1350+ let mut coordinator = FilterSyncCoordinator :: new (
1351+ & mut self . sync_manager ,
1352+ & mut * self . storage ,
1353+ & mut * self . network ,
1354+ & self . watch_items ,
1355+ & self . stats ,
1356+ & self . running ,
1357+ ) ;
1358+ coordinator. sync_filters_range ( start_height, count) . await
1359+ }
12741360
12751361 /// Initialize genesis block if not already present in storage.
12761362 async fn initialize_genesis_block ( & mut self ) -> Result < ( ) > {
0 commit comments