@@ -30,13 +30,6 @@ type p2pHandler interface {
30
30
ProcessDataRange (ctx context.Context , fromHeight , toHeight uint64 ) []common.DAHeightEvent
31
31
}
32
32
33
- const (
34
- // maxRetriesBeforeHalt is the maximum number of retries against the execution client before halting the syncer.
35
- maxRetriesBeforeHalt = 3
36
- // maxRetriesTimeout is the maximum time to wait for a retry before halting the syncer.
37
- maxRetriesTimeout = time .Second * 10
38
- )
39
-
40
33
// Syncer handles block synchronization from DA and P2P sources.
41
34
type Syncer struct {
42
35
// Core components
@@ -76,10 +69,9 @@ type Syncer struct {
76
69
logger zerolog.Logger
77
70
78
71
// Lifecycle
79
- ctx context.Context
80
- cancel context.CancelFunc
81
- wg sync.WaitGroup
82
- retriesBeforeHalt map [uint64 ]uint64
72
+ ctx context.Context
73
+ cancel context.CancelFunc
74
+ wg sync.WaitGroup
83
75
}
84
76
85
77
// NewSyncer creates a new block syncer
@@ -98,21 +90,20 @@ func NewSyncer(
98
90
errorCh chan <- error ,
99
91
) * Syncer {
100
92
return & Syncer {
101
- store : store ,
102
- exec : exec ,
103
- da : da ,
104
- cache : cache ,
105
- metrics : metrics ,
106
- config : config ,
107
- genesis : genesis ,
108
- options : options ,
109
- headerStore : headerStore ,
110
- dataStore : dataStore ,
111
- lastStateMtx : & sync.RWMutex {},
112
- heightInCh : make (chan common.DAHeightEvent , 10_000 ),
113
- errorCh : errorCh ,
114
- logger : logger .With ().Str ("component" , "syncer" ).Logger (),
115
- retriesBeforeHalt : make (map [uint64 ]uint64 ),
93
+ store : store ,
94
+ exec : exec ,
95
+ da : da ,
96
+ cache : cache ,
97
+ metrics : metrics ,
98
+ config : config ,
99
+ genesis : genesis ,
100
+ options : options ,
101
+ headerStore : headerStore ,
102
+ dataStore : dataStore ,
103
+ lastStateMtx : & sync.RWMutex {},
104
+ heightInCh : make (chan common.DAHeightEvent , 10_000 ),
105
+ errorCh : errorCh ,
106
+ logger : logger .With ().Str ("component" , "syncer" ).Logger (),
116
107
}
117
108
}
118
109
@@ -489,19 +480,11 @@ func (s *Syncer) applyBlock(header types.Header, data *types.Data, currentState
489
480
490
481
// Execute transactions
491
482
ctx := context .WithValue (s .ctx , types .HeaderContextKey , header )
492
- newAppHash , _ , err := s .exec .ExecuteTxs (ctx , rawTxs , header .Height (),
493
- header .Time (), currentState .AppHash )
483
+ newAppHash , err := s .executeTxsWithRetry (ctx , rawTxs , header , currentState )
494
484
if err != nil {
495
- s .retriesBeforeHalt [header .Height ()]++
496
- if s .retriesBeforeHalt [header .Height ()] > maxRetriesBeforeHalt {
497
- s .sendCriticalError (fmt .Errorf ("failed to execute transactions: %w" , err ))
498
- return types.State {}, fmt .Errorf ("failed to execute transactions: %w" , err )
499
- }
500
-
501
- time .Sleep (maxRetriesTimeout ) // sleep before retrying
502
- return types.State {}, fmt .Errorf ("failed to execute transactions (retry %d / %d): %w" , s .retriesBeforeHalt [header .Height ()], maxRetriesBeforeHalt , err )
485
+ s .sendCriticalError (fmt .Errorf ("failed to execute transactions: %w" , err ))
486
+ return types.State {}, fmt .Errorf ("failed to execute transactions: %w" , err )
503
487
}
504
- delete (s .retriesBeforeHalt , header .Height ())
505
488
506
489
// Create new state
507
490
newState , err := currentState .NextState (header , newAppHash )
@@ -512,6 +495,35 @@ func (s *Syncer) applyBlock(header types.Header, data *types.Data, currentState
512
495
return newState , nil
513
496
}
514
497
498
+ // executeTxsWithRetry executes transactions with retry logic
499
+ func (s * Syncer ) executeTxsWithRetry (ctx context.Context , rawTxs [][]byte , header types.Header , currentState types.State ) ([]byte , error ) {
500
+ for attempt := 1 ; attempt <= common .MaxRetriesBeforeHalt ; attempt ++ {
501
+ newAppHash , _ , err := s .exec .ExecuteTxs (ctx , rawTxs , header .Height (), header .Time (), currentState .AppHash )
502
+ if err != nil {
503
+ if attempt == common .MaxRetriesBeforeHalt {
504
+ return nil , fmt .Errorf ("failed to execute transactions: %w" , err )
505
+ }
506
+
507
+ s .logger .Error ().Err (err ).
508
+ Int ("attempt" , attempt ).
509
+ Int ("max_attempts" , common .MaxRetriesBeforeHalt ).
510
+ Uint64 ("height" , header .Height ()).
511
+ Msg ("failed to execute transactions, retrying" )
512
+
513
+ select {
514
+ case <- time .After (common .MaxRetriesTimeout ):
515
+ continue
516
+ case <- s .ctx .Done ():
517
+ return nil , fmt .Errorf ("context cancelled during retry: %w" , s .ctx .Err ())
518
+ }
519
+ }
520
+
521
+ return newAppHash , nil
522
+ }
523
+
524
+ return nil , nil
525
+ }
526
+
515
527
// validateBlock validates a synced block
516
528
func (s * Syncer ) validateBlock (
517
529
lastState types.State ,
0 commit comments