@@ -54,12 +54,19 @@ func (s *Syncer[H]) networkHead(ctx context.Context) (H, bool, error) {
54
54
if err != nil {
55
55
return sbjHead , false , fmt .Errorf ("subjective head: %w" , err )
56
56
}
57
- if isRecent (sbjHead , s .Params .blockTime , s .Params .recencyThreshold ) || initialized {
57
+ recent , timeDiff := isRecent (sbjHead , s .Params .blockTime , s .Params .recencyThreshold )
58
+ if recent || initialized {
58
59
return sbjHead , initialized , nil
59
60
}
60
61
61
62
s .metrics .outdatedHead (ctx )
62
- log .Warnw ("outdated subjective head" , "outdated_height" , sbjHead .Height ())
63
+ log .Warnw (
64
+ "non recent subjective head" ,
65
+ "height" ,
66
+ sbjHead .Height (),
67
+ "non_recent_for" ,
68
+ timeDiff .String (),
69
+ )
63
70
log .Warnw ("attempting to request the most recent network head..." )
64
71
65
72
// cap the max blocking time for the request call
@@ -85,9 +92,15 @@ func (s *Syncer[H]) networkHead(ctx context.Context) (H, bool, error) {
85
92
86
93
return sbjHead , false , nil
87
94
}
88
- // still check if even the newly requested head is outdated
89
- if ! isRecent (newHead , s .Params .blockTime , s .Params .recencyThreshold ) {
90
- log .Warnw ("non recent head from trusted peers" , "height" , newHead .Height ())
95
+ // still check if even the newly requested head is not recent
96
+ if recent , timeDiff = isRecent (newHead , s .Params .blockTime , s .Params .recencyThreshold ); ! recent {
97
+ log .Warnw (
98
+ "non recent head from trusted peers" ,
99
+ "height" ,
100
+ newHead .Height (),
101
+ "non_recent_for" ,
102
+ timeDiff .String (),
103
+ )
91
104
log .Error ("trusted peers are out of sync" )
92
105
s .metrics .trustedPeersOutOufSync (ctx )
93
106
}
@@ -115,15 +128,18 @@ func (s *Syncer[H]) networkHead(ctx context.Context) (H, bool, error) {
115
128
// Reports true if initialization was performed, false otherwise.
116
129
func (s * Syncer [H ]) subjectiveHead (ctx context.Context ) (H , bool , error ) {
117
130
sbjHead , err := s .localHead (ctx )
118
- switch {
119
- case errors .Is (err , header .ErrEmptyStore ):
120
- log .Info ("empty store, initializing..." )
121
- case ! sbjHead .IsZero () && isExpired (sbjHead , s .Params .TrustingPeriod ):
131
+
132
+ switch expired , expiredFor := isExpired (sbjHead , s .Params .TrustingPeriod ); {
133
+ case expired :
122
134
log .Infow (
123
135
"subjective head expired, reinitializing..." ,
124
136
"expired_height" ,
125
137
sbjHead .Height (),
138
+ "expired_for" ,
139
+ expiredFor .String (),
126
140
)
141
+ case errors .Is (err , header .ErrEmptyStore ):
142
+ log .Info ("empty store, initializing..." )
127
143
case err != nil :
128
144
return sbjHead , false , fmt .Errorf ("local head: %w" , err )
129
145
default :
@@ -136,9 +152,13 @@ func (s *Syncer[H]) subjectiveHead(ctx context.Context) (H, bool, error) {
136
152
return newHead , false , fmt .Errorf ("exchange head: %w" , err )
137
153
}
138
154
// still check if even the newly requested head is expired
139
- if isExpired (newHead , s .Params .TrustingPeriod ) {
155
+ if expired , expiredFor := isExpired (newHead , s .Params .TrustingPeriod ); expired {
140
156
// forbid initializing off an expired header
141
- err := fmt .Errorf ("subjective initialization with an expired header(%d)" , newHead .Height ())
157
+ err := fmt .Errorf (
158
+ "subjective initialization with header(%d) expired for %s" ,
159
+ newHead .Height (),
160
+ expiredFor .String (),
161
+ )
142
162
log .Error (err )
143
163
log .Error ("trusted peers are out of sync" )
144
164
s .metrics .trustedPeersOutOufSync (ctx )
@@ -304,16 +324,29 @@ func (s *Syncer[H]) verifyBifurcating(ctx context.Context, subjHead, newHead H)
304
324
}
305
325
}
306
326
307
- // isExpired checks if header is expired against trusting period.
308
- func isExpired [H header.Header [H ]](header H , period time.Duration ) bool {
327
+ // isExpired checks if header is expired against trusting period and reports duration it is
328
+ // expired for.
329
+ func isExpired [H header.Header [H ]](header H , period time.Duration ) (bool , time.Duration ) {
330
+ if header .IsZero () {
331
+ return false , 0
332
+ }
333
+
309
334
expirationTime := header .Time ().Add (period )
310
- return expirationTime .Before (time .Now ())
335
+ diff := time .Since (expirationTime )
336
+ return diff > 0 , diff
311
337
}
312
338
313
- // isRecent checks if header is recent against the given recency threshold.
314
- func isRecent [H header.Header [H ]](header H , blockTime , recencyThreshold time.Duration ) bool {
339
+ // isRecent checks if the given header is close to the tip against the given recency threshold and reports duration
340
+ // it is outdated for.
341
+ func isRecent [H header.Header [H ]](
342
+ header H ,
343
+ blockTime , recencyThreshold time.Duration ,
344
+ ) (bool , time.Duration ) {
315
345
if recencyThreshold == 0 {
316
346
recencyThreshold = blockTime * 2 // allow some drift by adding additional buffer of 2 blocks
317
347
}
318
- return time .Since (header .Time ()) <= recencyThreshold
348
+
349
+ recencyTime := header .Time ().Add (recencyThreshold )
350
+ diff := time .Since (recencyTime )
351
+ return diff <= 0 , diff
319
352
}
0 commit comments