@@ -17,6 +17,7 @@ import (
1717 datypes "github.com/evstack/ev-node/pkg/da/types"
1818 "github.com/evstack/ev-node/pkg/genesis"
1919 seqcommon "github.com/evstack/ev-node/pkg/sequencers/common"
20+ "github.com/evstack/ev-node/pkg/store"
2021)
2122
2223var _ coresequencer.Sequencer = (* BasedSequencer )(nil )
@@ -39,6 +40,10 @@ type BasedSequencer struct {
3940 currentDAEndTime time.Time
4041 // Total number of transactions in the current DA epoch (used for timestamp jitter)
4142 currentEpochTxCount uint64
43+ // lastTimestamp is the floor for timestamps to guarantee monotonicity
44+ // after a restart on a node that already had blocks produced with wall-clock time.
45+ // Initialised from the last block time in the store at construction.
46+ lastTimestamp time.Time
4247}
4348
4449// NewBasedSequencer creates a new based sequencer instance
@@ -56,6 +61,20 @@ func NewBasedSequencer(
5661 executor : executor ,
5762 currentDAEndTime : genesis .StartTime ,
5863 }
64+
65+ // Read the last block time from the store so that timestamps are
66+ // guaranteed to be strictly after any previously produced or synced block.
67+ // This handles the case where a node that already had blocks (produced with
68+ // wall-clock time) restarts as a based sequencer.
69+ initCtx , initCancel := context .WithTimeout (context .Background (), 10 * time .Second )
70+ defer initCancel ()
71+ s := store .New (store .NewEvNodeKVStore (db ))
72+ if state , err := s .GetState (initCtx ); err == nil && ! state .LastBlockTime .IsZero () {
73+ bs .lastTimestamp = state .LastBlockTime
74+ bs .logger .Debug ().
75+ Time ("last_block_time" , state .LastBlockTime ).
76+ Msg ("initialized timestamp floor from last block time" )
77+ }
5978 // based sequencers need community consensus about the da start height given no submission are done
6079 bs .SetDAHeight (genesis .DAStartHeight )
6180
@@ -194,6 +213,14 @@ doneProcessing:
194213 epochStart := s .currentDAEndTime .Add (- time .Duration (s .currentEpochTxCount ) * time .Millisecond )
195214 timestamp := epochStart .Add (time .Duration (txIndexForTimestamp ) * time .Millisecond )
196215
216+ // Clamp: the DA-derived timestamp may predate blocks that were
217+ // produced or synced with wall-clock time before the node restarted
218+ // as a based sequencer. Ensure strict monotonicity.
219+ if ! s .lastTimestamp .IsZero () && ! timestamp .After (s .lastTimestamp ) {
220+ timestamp = s .lastTimestamp .Add (time .Millisecond )
221+ }
222+ s .lastTimestamp = timestamp
223+
197224 return & coresequencer.GetNextBatchResponse {
198225 Batch : & coresequencer.Batch {Transactions : validTxs },
199226 Timestamp : timestamp ,
0 commit comments