@@ -23,24 +23,27 @@ import (
23
23
24
24
var ErrFinalizedHeaderUnchanged = errors .New ("finalized header unchanged" )
25
25
var ErrFinalizedHeaderNotImported = errors .New ("finalized header not imported" )
26
+ var ErrInterimHeaderNotImported = errors .New ("interim finalized header not imported" )
26
27
var ErrSyncCommitteeNotImported = errors .New ("sync committee not imported" )
27
28
var ErrSyncCommitteeLatency = errors .New ("sync committee latency found" )
28
29
var ErrExecutionHeaderNotImported = errors .New ("execution header not imported" )
29
30
var ErrBeaconHeaderNotFinalized = errors .New ("beacon header not finalized" )
30
31
31
32
type Header struct {
32
- cache * cache.BeaconCache
33
- writer parachain.ChainWriter
34
- syncer * syncer.Syncer
35
- protocol * protocol.Protocol
33
+ cache * cache.BeaconCache
34
+ writer parachain.ChainWriter
35
+ syncer * syncer.Syncer
36
+ protocol * protocol.Protocol
37
+ batchCallSize uint64
36
38
}
37
39
38
- func New (writer parachain.ChainWriter , client api.BeaconAPI , setting config.SpecSettings , store store.BeaconStore , protocol * protocol.Protocol ) Header {
40
+ func New (writer parachain.ChainWriter , client api.BeaconAPI , setting config.SpecSettings , store store.BeaconStore , protocol * protocol.Protocol , batchCallSize uint64 ) Header {
39
41
return Header {
40
- cache : cache .New (setting .SlotsInEpoch , setting .EpochsPerSyncCommitteePeriod ),
41
- writer : writer ,
42
- syncer : syncer .New (client , store , protocol ),
43
- protocol : protocol ,
42
+ cache : cache .New (setting .SlotsInEpoch , setting .EpochsPerSyncCommitteePeriod ),
43
+ writer : writer ,
44
+ syncer : syncer .New (client , store , protocol ),
45
+ protocol : protocol ,
46
+ batchCallSize : batchCallSize ,
44
47
}
45
48
}
46
49
@@ -70,6 +73,7 @@ func (h *Header) Sync(ctx context.Context, eg *errgroup.Group) error {
70
73
// Special handling here for the initial checkpoint to sync the next sync committee which is not included in initial
71
74
// checkpoint.
72
75
if h .isInitialSyncPeriod () {
76
+ log .Info ("syncing next sync committee for initial checkpoint" )
73
77
err = h .SyncCommitteePeriodUpdate (ctx , latestSyncedPeriod )
74
78
if err != nil {
75
79
return fmt .Errorf ("sync next committee for initial sync period: %w" , err )
@@ -135,16 +139,27 @@ func (h *Header) SyncCommitteePeriodUpdate(ctx context.Context, period uint64) e
135
139
// finalized header
136
140
if uint64 (update .Payload .FinalizedHeader .Slot ) > h .cache .Finalized .LastSyncedSlot {
137
141
diff := uint64 (update .Payload .FinalizedHeader .Slot ) - h .cache .Finalized .LastSyncedSlot
138
- log .WithFields (log.Fields {"diff" : diff , "last_finalized_slot" : h .cache .Finalized .LastSyncedSlot , "new_finalized_slot" : uint64 (update .Payload .FinalizedHeader .Slot )}).Info ("checking max latency" )
139
- if diff > h .protocol .Settings .SlotsInEpoch * h .protocol .Settings .EpochsPerSyncCommitteePeriod {
140
- log .Info ("syncing an interim update" )
141
- err = h .syncInterimFinalizedUpdate (ctx , h .cache .Finalized .LastSyncedSlot , uint64 (update .Payload .FinalizedHeader .Slot ))
142
+ minSlot := h .cache .Finalized .LastSyncedSlot
143
+ for diff > h .protocol .Settings .SlotsInEpoch * h .protocol .Settings .EpochsPerSyncCommitteePeriod {
144
+ log .WithFields (log.Fields {
145
+ "diff" : diff ,
146
+ "last_finalized_slot" : h .cache .Finalized .LastSyncedSlot ,
147
+ "new_finalized_slot" : uint64 (update .Payload .FinalizedHeader .Slot ),
148
+ }).Info ("interim update required" )
149
+
150
+ interimUpdate , err := h .syncInterimFinalizedUpdate (ctx , minSlot , uint64 (update .Payload .FinalizedHeader .Slot ))
142
151
if err != nil {
143
152
return fmt .Errorf ("sync interim finalized header update: %w" , err )
144
153
}
154
+
155
+ diff = uint64 (update .Payload .FinalizedHeader .Slot ) - uint64 (interimUpdate .Payload .FinalizedHeader .Slot )
156
+ minSlot = uint64 (update .Payload .FinalizedHeader .Slot ) + h .protocol .Settings .SlotsInEpoch
157
+ log .WithFields (log.Fields {
158
+ "new_diff" : diff ,
159
+ "interim_finalized_slot" : uint64 (interimUpdate .Payload .FinalizedHeader .Slot ),
160
+ "new_finalized_slot" : uint64 (update .Payload .FinalizedHeader .Slot ),
161
+ }).Info ("interim update synced successfully" )
145
162
}
146
- } else {
147
- log .Info ("interim update not required" )
148
163
}
149
164
150
165
log .WithFields (log.Fields {
@@ -290,6 +305,7 @@ func (h *Header) SyncExecutionHeaders(ctx context.Context) error {
290
305
for currentSlot <= toSlot {
291
306
log .WithFields (log.Fields {
292
307
"currentSlot" : currentSlot ,
308
+ "remaining" : toSlot - currentSlot ,
293
309
}).Info ("fetching next header at slot" )
294
310
295
311
var nextHeaderUpdate scale.HeaderUpdatePayload
@@ -307,42 +323,57 @@ func (h *Header) SyncExecutionHeaders(ctx context.Context) error {
307
323
308
324
headersToSync = append (headersToSync , headerUpdate )
309
325
// last slot to be synced, sync headers
310
- if currentSlot >= toSlot {
326
+ if currentSlot % h .batchCallSize == 0 || currentSlot >= toSlot {
327
+ slotsToSync := []uint64 {}
328
+ for _ , h := range headersToSync {
329
+ slotsToSync = append (slotsToSync , uint64 (h .Header .Slot ))
330
+ }
331
+ log .WithFields (log.Fields {
332
+ "slotsToSync" : slotsToSync ,
333
+ }).Info ("syncing batch of headers" )
311
334
err = h .batchSyncHeaders (ctx , headersToSync )
312
335
if err != nil {
313
336
return fmt .Errorf ("batch sync headers failed: %w" , err )
314
337
}
338
+
339
+ // waiting for all batch calls to be executed on chain
340
+ err = h .waitingForBatchCallFinished (slotsToSync [len (slotsToSync )- 1 ])
341
+ if err != nil {
342
+ return err
343
+ }
344
+
345
+ headersToSync = []scale.HeaderUpdatePayload {}
315
346
}
316
347
headerUpdate = nextHeaderUpdate
317
348
currentSlot = uint64 (headerUpdate .Header .Slot )
318
349
}
319
- // waiting for all batch calls to be executed on chain
320
- err = h .waitingForBatchCallFinished (toSlot )
321
- if err != nil {
322
- return err
323
- }
324
- h .cache .SetLastSyncedExecutionSlot (toSlot )
350
+
325
351
return nil
326
352
}
327
353
328
- func (h * Header ) syncInterimFinalizedUpdate (ctx context.Context , lastSyncedSlot , newCheckpointSlot uint64 ) error {
354
+ func (h * Header ) syncInterimFinalizedUpdate (ctx context.Context , lastSyncedSlot , newCheckpointSlot uint64 ) (scale.Update , error ) {
355
+ currentPeriod := h .protocol .ComputeSyncPeriodAtSlot (lastSyncedSlot )
356
+
329
357
// Calculate the range that the interim finalized header update may be in
330
358
minSlot := newCheckpointSlot - h .protocol .SlotsPerHistoricalRoot
331
- maxSlot := lastSyncedSlot + h .protocol .SlotsPerHistoricalRoot
359
+ maxSlot := (( currentPeriod + 1 ) * h .protocol .SlotsPerHistoricalRoot ) - h . protocol . Settings . SlotsInEpoch // just before the new sync committee boundary
332
360
333
361
finalizedUpdate , err := h .syncer .GetFinalizedUpdateAtAttestedSlot (minSlot , maxSlot , false )
334
362
if err != nil {
335
- return fmt .Errorf ("get interim checkpoint to update chain (last synced slot %d, new slot: %d): %w" , lastSyncedSlot , newCheckpointSlot , err )
363
+ return scale. Update {}, fmt .Errorf ("get interim checkpoint to update chain (last synced slot %d, new slot: %d): %w" , lastSyncedSlot , newCheckpointSlot , err )
336
364
}
337
365
338
366
log .WithField ("slot" , finalizedUpdate .Payload .FinalizedHeader .Slot ).Info ("syncing an interim update to on-chain" )
339
367
340
368
err = h .updateFinalizedHeaderOnchain (ctx , finalizedUpdate )
341
- if err != nil {
342
- return fmt .Errorf ("update interim finalized header on-chain: %w" , err )
369
+ switch {
370
+ case errors .Is (err , ErrFinalizedHeaderNotImported ):
371
+ return scale.Update {}, ErrInterimHeaderNotImported
372
+ case err != nil :
373
+ return scale.Update {}, fmt .Errorf ("update interim finalized header on-chain: %w" , err )
343
374
}
344
375
345
- return nil
376
+ return finalizedUpdate , nil
346
377
}
347
378
348
379
func (h * Header ) syncLaggingSyncCommitteePeriods (ctx context.Context , latestSyncedPeriod , currentSyncPeriod uint64 ) error {
@@ -515,6 +546,7 @@ func (h *Header) waitingForBatchCallFinished(toSlot uint64) error {
515
546
if err != nil {
516
547
return fmt .Errorf ("fetch last execution hash: %w" , err )
517
548
}
549
+ h .cache .SetLastSyncedExecutionSlot (executionHeaderState .BeaconSlot )
518
550
if executionHeaderState .BeaconSlot == toSlot {
519
551
batchCallFinished = true
520
552
break
0 commit comments