Skip to content

Commit 8a853fc

Browse files
authored
extract LC sync task scheduling helper function (#5117)
The helper function to compute delay until next light client sync task can be useful from more general purpose contexts. Move to helpers, and change it to return `Duration` instead of `BeaconTime` for flexibility.
1 parent 1bc9f3a commit 8a853fc

File tree

2 files changed

+68
-59
lines changed

2 files changed

+68
-59
lines changed

beacon_chain/sync/light_client_manager.nim

Lines changed: 17 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99

1010
import chronos, chronicles
1111
import
12-
eth/p2p/discoveryv5/random2,
1312
../spec/network,
1413
../networking/eth2_network,
1514
../beacon_clock,
@@ -107,13 +106,9 @@ proc isGossipSupported*(
107106
if not self.isLightClientStoreInitialized():
108107
return false
109108

110-
let
111-
finalizedPeriod = self.getFinalizedPeriod()
112-
isNextSyncCommitteeKnown = self.isNextSyncCommitteeKnown()
113-
if isNextSyncCommitteeKnown:
114-
period <= finalizedPeriod + 1
115-
else:
116-
period <= finalizedPeriod
109+
period.isGossipSupported(
110+
finalizedPeriod = self.getFinalizedPeriod(),
111+
isNextSyncCommitteeKnown = self.isNextSyncCommitteeKnown())
117112

118113
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-alpha.3/specs/altair/light-client/p2p-interface.md#getlightclientbootstrap
119114
proc doRequest(
@@ -340,45 +335,13 @@ template query[E](
340335
): Future[bool] =
341336
self.query(e, Nothing())
342337
343-
type SchedulingMode = enum
344-
Now,
345-
Soon,
346-
CurrentPeriod,
347-
NextPeriod
348-
349-
func fetchTime(
350-
self: LightClientManager,
351-
wallTime: BeaconTime,
352-
schedulingMode: SchedulingMode
353-
): BeaconTime =
354-
let
355-
remainingTime =
356-
case schedulingMode:
357-
of Now:
358-
return wallTime
359-
of Soon:
360-
chronos.seconds(0)
361-
of CurrentPeriod:
362-
let
363-
wallPeriod = wallTime.slotOrZero().sync_committee_period
364-
deadlineSlot = (wallPeriod + 1).start_slot - 1
365-
deadline = deadlineSlot.start_beacon_time()
366-
chronos.nanoseconds((deadline - wallTime).nanoseconds)
367-
of NextPeriod:
368-
chronos.seconds(
369-
(SLOTS_PER_SYNC_COMMITTEE_PERIOD * SECONDS_PER_SLOT).int64)
370-
minDelay = max(remainingTime div 8, chronos.seconds(10))
371-
jitterSeconds = (minDelay * 2).seconds
372-
jitterDelay = chronos.seconds(self.rng[].rand(jitterSeconds).int64)
373-
return wallTime + minDelay + jitterDelay
374-
375338
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-alpha.3/specs/altair/light-client/light-client.md#light-client-sync-process
376339
proc loop(self: LightClientManager) {.async.} =
377-
var nextFetchTime = self.getBeaconTime()
340+
var nextSyncTaskTime = self.getBeaconTime()
378341
while true:
379342
# Periodically wake and check for changes
380343
let wallTime = self.getBeaconTime()
381-
if wallTime < nextFetchTime or
344+
if wallTime < nextSyncTaskTime or
382345
self.network.peerPool.lenAvailable < 1:
383346
await sleepAsync(chronos.seconds(2))
384347
continue
@@ -391,18 +354,21 @@ proc loop(self: LightClientManager) {.async.} =
391354
continue
392355
393356
let didProgress = await self.query(Bootstrap, trustedBlockRoot.get)
394-
if not didProgress:
395-
nextFetchTime = self.fetchTime(wallTime, Soon)
357+
nextSyncTaskTime =
358+
if didProgress:
359+
wallTime
360+
else:
361+
wallTime + self.rng.computeDelayWithJitter(chronos.seconds(0))
396362
continue
397363
398364
# Fetch updates
399365
let
400366
current = wallTime.slotOrZero().sync_committee_period
401367
402368
syncTask = nextLightClientSyncTask(
369+
current = current,
403370
finalized = self.getFinalizedPeriod(),
404371
optimistic = self.getOptimisticPeriod(),
405-
current = current,
406372
isNextSyncCommitteeKnown = self.isNextSyncCommitteeKnown())
407373
408374
didProgress =
@@ -415,18 +381,12 @@ proc loop(self: LightClientManager) {.async.} =
415381
of LcSyncKind.OptimisticUpdate:
416382
await self.query(OptimisticUpdate)
417383
418-
schedulingMode =
419-
if not self.isGossipSupported(current):
420-
if didProgress:
421-
Now
422-
else:
423-
Soon
424-
elif self.getFinalizedPeriod() != self.getOptimisticPeriod():
425-
CurrentPeriod
426-
else:
427-
NextPeriod
428-
429-
nextFetchTime = self.fetchTime(wallTime, schedulingMode)
384+
nextSyncTaskTime = wallTime + self.rng.nextLcSyncTaskDelay(
385+
wallTime,
386+
finalized = self.getFinalizedPeriod(),
387+
optimistic = self.getOptimisticPeriod(),
388+
isNextSyncCommitteeKnown = self.isNextSyncCommitteeKnown(),
389+
didLatestSyncTaskProgress = didProgress)
430390
431391
proc start*(self: var LightClientManager) =
432392
## Start light client manager's loop.

beacon_chain/sync/light_client_sync_helpers.nim

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ import
1111
std/typetraits,
1212
chronos,
1313
stew/base10,
14-
../spec/[forks_light_client, network]
14+
eth/p2p/discoveryv5/random2,
15+
../spec/[forks_light_client, network],
16+
../beacon_clock
1517

1618
func checkLightClientUpdates*(
1719
updates: openArray[ForkedLightClientUpdate],
@@ -49,6 +51,15 @@ func checkLightClientUpdates*(
4951
return err("Invalid context bytes")
5052
ok()
5153

54+
func isGossipSupported*(
55+
period: SyncCommitteePeriod,
56+
finalizedPeriod: SyncCommitteePeriod,
57+
isNextSyncCommitteeKnown: bool): bool =
58+
if isNextSyncCommitteeKnown:
59+
period <= finalizedPeriod + 1
60+
else:
61+
period <= finalizedPeriod
62+
5263
type
5364
LcSyncKind* {.pure.} = enum
5465
UpdatesByRange
@@ -64,9 +75,9 @@ type
6475
discard
6576

6677
func nextLightClientSyncTask*(
78+
current: SyncCommitteePeriod,
6779
finalized: SyncCommitteePeriod,
6880
optimistic: SyncCommitteePeriod,
69-
current: SyncCommitteePeriod,
7081
isNextSyncCommitteeKnown: bool): LcSyncTask =
7182
if finalized == optimistic and not isNextSyncCommitteeKnown:
7283
if finalized >= current:
@@ -88,3 +99,41 @@ func nextLightClientSyncTask*(
8899
LcSyncTask(kind: LcSyncKind.FinalityUpdate)
89100
else:
90101
LcSyncTask(kind: LcSyncKind.OptimisticUpdate)
102+
103+
func computeDelayWithJitter*(
104+
rng: ref HmacDrbgContext, duration: Duration): Duration =
105+
let
106+
minDelay = max(duration div 8, chronos.seconds(10))
107+
jitterSeconds = (minDelay * 2).seconds
108+
jitterDelay = chronos.seconds(rng[].rand(jitterSeconds).int64)
109+
minDelay + jitterDelay
110+
111+
func nextLcSyncTaskDelay*(
112+
rng: ref HmacDrbgContext,
113+
wallTime: BeaconTime,
114+
finalized: SyncCommitteePeriod,
115+
optimistic: SyncCommitteePeriod,
116+
isNextSyncCommitteeKnown: bool,
117+
didLatestSyncTaskProgress: bool
118+
): Duration =
119+
let
120+
current = wallTime.slotOrZero().sync_committee_period
121+
remainingDuration =
122+
if not current.isGossipSupported(finalized, isNextSyncCommitteeKnown):
123+
if didLatestSyncTaskProgress:
124+
# Now
125+
return chronos.seconds(0)
126+
# Soon
127+
chronos.seconds(0)
128+
elif finalized != optimistic:
129+
# Current sync committee period
130+
let
131+
wallPeriod = wallTime.slotOrZero().sync_committee_period
132+
deadlineSlot = (wallPeriod + 1).start_slot - 1
133+
deadline = deadlineSlot.start_beacon_time()
134+
chronos.nanoseconds((deadline - wallTime).nanoseconds)
135+
else:
136+
# Next sync committee period
137+
chronos.seconds(
138+
(SLOTS_PER_SYNC_COMMITTEE_PERIOD * SECONDS_PER_SLOT).int64)
139+
rng.computeDelayWithJitter(remainingDuration)

0 commit comments

Comments
 (0)