@@ -421,10 +421,7 @@ struct IndexerClient {
421421
422422const INTERVAL : Duration = Duration :: from_millis ( 500 ) ;
423423
424- /// Consecutive non-syncing polls, over which the head advances, required before
425- /// we treat the node as caught up. At [`INTERVAL`] spacing this is a short
426- /// stability window that outlasts the transient `syncing == false` reported at
427- /// boot.
424+ /// Consecutive non-syncing polls with head progress before the node counts as caught up.
428425const REQUIRED_STABLE_POLLS : u32 = 4 ;
429426
430427impl IndexerClient {
@@ -458,29 +455,17 @@ impl IndexerClient {
458455 }
459456}
460457
461- /// Decides when the node has caught up to the chain tip from its own head
462- /// progress.
463- ///
464- /// `syncing` alone is insufficient: a freshly state-syncing node reports it
465- /// `false` at boot before it has learned it is behind, which would pin the
466- /// streamer's `LatestSynced` cursor at the stale genesis head. So we wait for a
467- /// sustained run of non-syncing polls over which the head advances. Bulk sync
468- /// sets `syncing == true`, and the pre-sync boot window leaves the head static,
469- /// so only a node following the live chain tip clears both gates.
470- ///
471- /// A fully halted chain (head not advancing) defers startup, which is
472- /// acceptable: there would be nothing to stream.
458+ /// Detects catch-up from head progress alone: a freshly state-syncing node
459+ /// briefly reports `syncing == false` at the genesis head, and returning then
460+ /// pins the streamer's `LatestSynced` cursor at that stale head. So we require a
461+ /// run of non-syncing polls over which the head actually advances.
473462#[ derive( Default ) ]
474463struct SyncProgress {
475- /// Head height when the current non-syncing run began, or `None` if the last
476- /// observed poll reported syncing.
477464 run_start_head : Option < BlockHeight > ,
478- /// Number of consecutive non-syncing polls in the current run.
479465 run_polls : u32 ,
480466}
481467
482468impl SyncProgress {
483- /// Feeds one status sample; returns `true` once the node is caught up.
484469 fn observe ( & mut self , syncing : bool , head_height : BlockHeight ) -> bool {
485470 if syncing {
486471 self . run_start_head = None ;
@@ -562,8 +547,6 @@ pub struct IndexerAPI<TransactionSender, ForeignChainPolicyReader> {
562547mod tests {
563548 use super :: { BlockHeight , REQUIRED_STABLE_POLLS , SyncProgress } ;
564549
565- /// Feeds `(syncing, head_height)` samples in order and returns the index of
566- /// the first sample after which the node is reported caught up, or `None`.
567550 fn first_caught_up_poll ( samples : & [ ( bool , BlockHeight ) ] ) -> Option < usize > {
568551 let mut progress = SyncProgress :: default ( ) ;
569552 samples
@@ -583,9 +566,6 @@ mod tests {
583566 assert_eq ! ( caught_up_at, None ) ;
584567 }
585568
586- /// The wedge: at boot the node sits at genesis reporting `syncing == false`
587- /// before it learns it is behind. A static head must never be mistaken for
588- /// being caught up.
589569 #[ test]
590570 fn observe__should_never_report_caught_up_with_static_head_at_genesis ( ) {
591571 // Given
@@ -628,8 +608,6 @@ mod tests {
628608 assert_eq ! ( caught_up_at, Some ( expected) ) ;
629609 }
630610
631- /// Even after enough non-syncing polls, a head that has not advanced past
632- /// the start of the run is not yet caught up; it must wait for a new block.
633611 #[ test]
634612 fn observe__should_wait_for_head_to_advance_past_run_start ( ) {
635613 // Given
@@ -646,8 +624,6 @@ mod tests {
646624 assert_eq ! ( caught_up_at, Some ( samples. len( ) - 1 ) ) ;
647625 }
648626
649- /// A resumed sync resets the run, so non-syncing polls seen before it do not
650- /// count toward the stability window.
651627 #[ test]
652628 fn observe__should_reset_run_when_syncing_resumes ( ) {
653629 // Given
0 commit comments