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.
This commit is contained in:
parent
1bc9f3a67a
commit
8a853fc4e4
|
@ -9,7 +9,6 @@
|
|||
|
||||
import chronos, chronicles
|
||||
import
|
||||
eth/p2p/discoveryv5/random2,
|
||||
../spec/network,
|
||||
../networking/eth2_network,
|
||||
../beacon_clock,
|
||||
|
@ -107,13 +106,9 @@ proc isGossipSupported*(
|
|||
if not self.isLightClientStoreInitialized():
|
||||
return false
|
||||
|
||||
let
|
||||
finalizedPeriod = self.getFinalizedPeriod()
|
||||
isNextSyncCommitteeKnown = self.isNextSyncCommitteeKnown()
|
||||
if isNextSyncCommitteeKnown:
|
||||
period <= finalizedPeriod + 1
|
||||
else:
|
||||
period <= finalizedPeriod
|
||||
period.isGossipSupported(
|
||||
finalizedPeriod = self.getFinalizedPeriod(),
|
||||
isNextSyncCommitteeKnown = self.isNextSyncCommitteeKnown())
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-alpha.3/specs/altair/light-client/p2p-interface.md#getlightclientbootstrap
|
||||
proc doRequest(
|
||||
|
@ -340,45 +335,13 @@ template query[E](
|
|||
): Future[bool] =
|
||||
self.query(e, Nothing())
|
||||
|
||||
type SchedulingMode = enum
|
||||
Now,
|
||||
Soon,
|
||||
CurrentPeriod,
|
||||
NextPeriod
|
||||
|
||||
func fetchTime(
|
||||
self: LightClientManager,
|
||||
wallTime: BeaconTime,
|
||||
schedulingMode: SchedulingMode
|
||||
): BeaconTime =
|
||||
let
|
||||
remainingTime =
|
||||
case schedulingMode:
|
||||
of Now:
|
||||
return wallTime
|
||||
of Soon:
|
||||
chronos.seconds(0)
|
||||
of CurrentPeriod:
|
||||
let
|
||||
wallPeriod = wallTime.slotOrZero().sync_committee_period
|
||||
deadlineSlot = (wallPeriod + 1).start_slot - 1
|
||||
deadline = deadlineSlot.start_beacon_time()
|
||||
chronos.nanoseconds((deadline - wallTime).nanoseconds)
|
||||
of NextPeriod:
|
||||
chronos.seconds(
|
||||
(SLOTS_PER_SYNC_COMMITTEE_PERIOD * SECONDS_PER_SLOT).int64)
|
||||
minDelay = max(remainingTime div 8, chronos.seconds(10))
|
||||
jitterSeconds = (minDelay * 2).seconds
|
||||
jitterDelay = chronos.seconds(self.rng[].rand(jitterSeconds).int64)
|
||||
return wallTime + minDelay + jitterDelay
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-alpha.3/specs/altair/light-client/light-client.md#light-client-sync-process
|
||||
proc loop(self: LightClientManager) {.async.} =
|
||||
var nextFetchTime = self.getBeaconTime()
|
||||
var nextSyncTaskTime = self.getBeaconTime()
|
||||
while true:
|
||||
# Periodically wake and check for changes
|
||||
let wallTime = self.getBeaconTime()
|
||||
if wallTime < nextFetchTime or
|
||||
if wallTime < nextSyncTaskTime or
|
||||
self.network.peerPool.lenAvailable < 1:
|
||||
await sleepAsync(chronos.seconds(2))
|
||||
continue
|
||||
|
@ -391,8 +354,11 @@ proc loop(self: LightClientManager) {.async.} =
|
|||
continue
|
||||
|
||||
let didProgress = await self.query(Bootstrap, trustedBlockRoot.get)
|
||||
if not didProgress:
|
||||
nextFetchTime = self.fetchTime(wallTime, Soon)
|
||||
nextSyncTaskTime =
|
||||
if didProgress:
|
||||
wallTime
|
||||
else:
|
||||
wallTime + self.rng.computeDelayWithJitter(chronos.seconds(0))
|
||||
continue
|
||||
|
||||
# Fetch updates
|
||||
|
@ -400,9 +366,9 @@ proc loop(self: LightClientManager) {.async.} =
|
|||
current = wallTime.slotOrZero().sync_committee_period
|
||||
|
||||
syncTask = nextLightClientSyncTask(
|
||||
current = current,
|
||||
finalized = self.getFinalizedPeriod(),
|
||||
optimistic = self.getOptimisticPeriod(),
|
||||
current = current,
|
||||
isNextSyncCommitteeKnown = self.isNextSyncCommitteeKnown())
|
||||
|
||||
didProgress =
|
||||
|
@ -415,18 +381,12 @@ proc loop(self: LightClientManager) {.async.} =
|
|||
of LcSyncKind.OptimisticUpdate:
|
||||
await self.query(OptimisticUpdate)
|
||||
|
||||
schedulingMode =
|
||||
if not self.isGossipSupported(current):
|
||||
if didProgress:
|
||||
Now
|
||||
else:
|
||||
Soon
|
||||
elif self.getFinalizedPeriod() != self.getOptimisticPeriod():
|
||||
CurrentPeriod
|
||||
else:
|
||||
NextPeriod
|
||||
|
||||
nextFetchTime = self.fetchTime(wallTime, schedulingMode)
|
||||
nextSyncTaskTime = wallTime + self.rng.nextLcSyncTaskDelay(
|
||||
wallTime,
|
||||
finalized = self.getFinalizedPeriod(),
|
||||
optimistic = self.getOptimisticPeriod(),
|
||||
isNextSyncCommitteeKnown = self.isNextSyncCommitteeKnown(),
|
||||
didLatestSyncTaskProgress = didProgress)
|
||||
|
||||
proc start*(self: var LightClientManager) =
|
||||
## Start light client manager's loop.
|
||||
|
|
|
@ -11,7 +11,9 @@ import
|
|||
std/typetraits,
|
||||
chronos,
|
||||
stew/base10,
|
||||
../spec/[forks_light_client, network]
|
||||
eth/p2p/discoveryv5/random2,
|
||||
../spec/[forks_light_client, network],
|
||||
../beacon_clock
|
||||
|
||||
func checkLightClientUpdates*(
|
||||
updates: openArray[ForkedLightClientUpdate],
|
||||
|
@ -49,6 +51,15 @@ func checkLightClientUpdates*(
|
|||
return err("Invalid context bytes")
|
||||
ok()
|
||||
|
||||
func isGossipSupported*(
|
||||
period: SyncCommitteePeriod,
|
||||
finalizedPeriod: SyncCommitteePeriod,
|
||||
isNextSyncCommitteeKnown: bool): bool =
|
||||
if isNextSyncCommitteeKnown:
|
||||
period <= finalizedPeriod + 1
|
||||
else:
|
||||
period <= finalizedPeriod
|
||||
|
||||
type
|
||||
LcSyncKind* {.pure.} = enum
|
||||
UpdatesByRange
|
||||
|
@ -64,9 +75,9 @@ type
|
|||
discard
|
||||
|
||||
func nextLightClientSyncTask*(
|
||||
current: SyncCommitteePeriod,
|
||||
finalized: SyncCommitteePeriod,
|
||||
optimistic: SyncCommitteePeriod,
|
||||
current: SyncCommitteePeriod,
|
||||
isNextSyncCommitteeKnown: bool): LcSyncTask =
|
||||
if finalized == optimistic and not isNextSyncCommitteeKnown:
|
||||
if finalized >= current:
|
||||
|
@ -88,3 +99,41 @@ func nextLightClientSyncTask*(
|
|||
LcSyncTask(kind: LcSyncKind.FinalityUpdate)
|
||||
else:
|
||||
LcSyncTask(kind: LcSyncKind.OptimisticUpdate)
|
||||
|
||||
func computeDelayWithJitter*(
|
||||
rng: ref HmacDrbgContext, duration: Duration): Duration =
|
||||
let
|
||||
minDelay = max(duration div 8, chronos.seconds(10))
|
||||
jitterSeconds = (minDelay * 2).seconds
|
||||
jitterDelay = chronos.seconds(rng[].rand(jitterSeconds).int64)
|
||||
minDelay + jitterDelay
|
||||
|
||||
func nextLcSyncTaskDelay*(
|
||||
rng: ref HmacDrbgContext,
|
||||
wallTime: BeaconTime,
|
||||
finalized: SyncCommitteePeriod,
|
||||
optimistic: SyncCommitteePeriod,
|
||||
isNextSyncCommitteeKnown: bool,
|
||||
didLatestSyncTaskProgress: bool
|
||||
): Duration =
|
||||
let
|
||||
current = wallTime.slotOrZero().sync_committee_period
|
||||
remainingDuration =
|
||||
if not current.isGossipSupported(finalized, isNextSyncCommitteeKnown):
|
||||
if didLatestSyncTaskProgress:
|
||||
# Now
|
||||
return chronos.seconds(0)
|
||||
# Soon
|
||||
chronos.seconds(0)
|
||||
elif finalized != optimistic:
|
||||
# Current sync committee period
|
||||
let
|
||||
wallPeriod = wallTime.slotOrZero().sync_committee_period
|
||||
deadlineSlot = (wallPeriod + 1).start_slot - 1
|
||||
deadline = deadlineSlot.start_beacon_time()
|
||||
chronos.nanoseconds((deadline - wallTime).nanoseconds)
|
||||
else:
|
||||
# Next sync committee period
|
||||
chronos.seconds(
|
||||
(SLOTS_PER_SYNC_COMMITTEE_PERIOD * SECONDS_PER_SLOT).int64)
|
||||
rng.computeDelayWithJitter(remainingDuration)
|
||||
|
|
Loading…
Reference in New Issue