@@ -63,7 +63,8 @@ type Sequencer struct {
6363 // It is set when we detect (via GetLatestDAHeight) that the DA layer is more
6464 // than one epoch ahead of our checkpoint, and cleared when we hit
6565 // ErrHeightFromFuture (meaning we've reached the DA head).
66- catchingUp bool
66+
67+ catchingUp atomic.Bool
6768 // currentDAEndTime is the DA epoch end timestamp from the last fetched epoch.
6869 // Used as the block timestamp during catch-up to match based sequencing behavior.
6970 currentDAEndTime time.Time
@@ -235,7 +236,7 @@ func (c *Sequencer) GetNextBatch(ctx context.Context, req coresequencer.GetNextB
235236 // During catch-up, the sequencer must produce blocks identical to what base
236237 // sequencing would produce (forced inclusion txs only, no mempool).
237238 var mempoolBatch * coresequencer.Batch
238- if ! c .catchingUp {
239+ if ! c .catchingUp . Load () {
239240 var err error
240241 mempoolBatch , err = c .queue .Next (ctx )
241242 if err != nil {
@@ -353,7 +354,7 @@ func (c *Sequencer) GetNextBatch(ctx context.Context, req coresequencer.GetNextB
353354 Uint64 ("consumed_count" , forcedTxConsumedCount ).
354355 Uint64 ("checkpoint_tx_index" , c .checkpoint .TxIndex ).
355356 Uint64 ("checkpoint_da_height" , c .checkpoint .DAHeight ).
356- Bool ("catching_up" , c .catchingUp ).
357+ Bool ("catching_up" , c .catchingUp . Load () ).
357358 Msg ("updated checkpoint after processing forced inclusion transactions" )
358359 }
359360
@@ -365,12 +366,15 @@ func (c *Sequencer) GetNextBatch(ctx context.Context, req coresequencer.GetNextB
365366 // During catch-up, use the DA epoch end timestamp to match based sequencing behavior.
366367 // Replicates based sequencing nodes' behavior of timestamping blocks during catchingUp.
367368 timestamp := time .Now ()
368- if c .catchingUp && ! c .currentDAEndTime .IsZero () {
369- var remainingForcedTxs uint64
370- if len (c .cachedForcedInclusionTxs ) > 0 {
371- remainingForcedTxs = uint64 (len (c .cachedForcedInclusionTxs )) - c .checkpoint .TxIndex
369+ if c .catchingUp .Load () {
370+ daEndTime := c .currentDAEndTime
371+ if ! daEndTime .IsZero () {
372+ var remainingForcedTxs uint64
373+ if len (c .cachedForcedInclusionTxs ) > 0 {
374+ remainingForcedTxs = uint64 (len (c .cachedForcedInclusionTxs )) - c .checkpoint .TxIndex
375+ }
376+ timestamp = daEndTime .Add (- time .Duration (remainingForcedTxs ) * time .Millisecond )
372377 }
373- timestamp = c .currentDAEndTime .Add (- time .Duration (remainingForcedTxs ) * time .Millisecond )
374378 }
375379
376380 return & coresequencer.GetNextBatchResponse {
@@ -426,7 +430,7 @@ func (c *Sequencer) GetDAHeight() uint64 {
426430// with only forced inclusion transactions (no mempool), matching the blocks
427431// that base sequencing nodes would have produced during sequencer downtime.
428432func (c * Sequencer ) IsCatchingUp () bool {
429- return c .catchingUp
433+ return c .catchingUp . Load ()
430434}
431435
432436// fetchNextDAEpoch fetches transactions from the next DA epoch using checkpoint.
@@ -447,7 +451,7 @@ func (c *Sequencer) fetchNextDAEpoch(ctx context.Context, maxBytes uint64) (uint
447451 c .logger .Debug ().
448452 Uint64 ("da_height" , currentDAHeight ).
449453 Uint64 ("tx_index" , c .checkpoint .TxIndex ).
450- Bool ("catching_up" , c .catchingUp ).
454+ Bool ("catching_up" , c .catchingUp . Load () ).
451455 Msg ("fetching forced inclusion transactions from DA" )
452456
453457 forcedTxsEvent , err := c .fiRetriever .RetrieveForcedIncludedTxs (ctx , currentDAHeight )
@@ -458,18 +462,18 @@ func (c *Sequencer) fetchNextDAEpoch(ctx context.Context, maxBytes uint64) (uint
458462 Msg ("DA height from future, waiting for DA to produce block" )
459463
460464 // We've reached the DA head — exit catch-up mode
461- if c .catchingUp {
465+ if c .catchingUp . Load () {
462466 c .logger .Info ().
463467 Uint64 ("da_height" , currentDAHeight ).
464468 Msg ("catch-up complete: reached DA head, resuming normal sequencing" )
465- c .catchingUp = false
469+ c .catchingUp . Store ( false )
466470 }
467471
468472 return 0 , nil
469473 } else if errors .Is (err , block .ErrForceInclusionNotConfigured ) {
470474 // Forced inclusion not configured, continue without forced txs
471475 c .cachedForcedInclusionTxs = [][]byte {}
472- c .catchingUp = false
476+ c .catchingUp . Store ( false )
473477 return 0 , nil
474478 }
475479
@@ -502,7 +506,7 @@ func (c *Sequencer) fetchNextDAEpoch(ctx context.Context, maxBytes uint64) (uint
502506 Int ("skipped_tx_count" , skippedTxs ).
503507 Uint64 ("da_height_start" , forcedTxsEvent .StartDaHeight ).
504508 Uint64 ("da_height_end" , forcedTxsEvent .EndDaHeight ).
505- Bool ("catching_up" , c .catchingUp ).
509+ Bool ("catching_up" , c .catchingUp . Load () ).
506510 Msg ("fetched forced inclusion transactions from DA" )
507511
508512 // Cache the transactions
@@ -528,7 +532,7 @@ func (c *Sequencer) fetchNextDAEpoch(ctx context.Context, maxBytes uint64) (uint
528532// overhead.
529533func (c * Sequencer ) updateCatchUpState (ctx context.Context ) {
530534 // Already catching up — nothing to do. We'll exit via ErrHeightFromFuture.
531- if c .catchingUp {
535+ if c .catchingUp . Load () {
532536 return
533537 }
534538
@@ -574,7 +578,7 @@ func (c *Sequencer) updateCatchUpState(ctx context.Context) {
574578 }
575579
576580 // The DA layer is more than one epoch ahead. Enter catch-up mode.
577- c .catchingUp = true
581+ c .catchingUp . Store ( true )
578582 c .logger .Warn ().
579583 Uint64 ("checkpoint_da_height" , currentDAHeight ).
580584 Uint64 ("latest_da_height" , latestDAHeight ).
0 commit comments