add hooks for observing LC progress (#4401)
For Fluffy injection, add observer callbacks that get called whenever new light client data is sucecssfully processed. ``` proc onLightClientObject( lightClient: LightClient, obj: SomeLightClientObject) = info "New LC object", obj lightClient.bootstrapObserver = proc(lightClient: LightClient, obj: altair.LightClientBootstrap) = lightClient.onLightClientObject(obj) lightClient.updateObserver = proc(lightClient: LightClient, obj: altair.LightClientUpdate) = lightClient.onLightClientObject(obj) lightClient.finalityUpdateObserver = proc(lightClient: LightClient, obj: altair.LightClientFinalityUpdate) = lightClient.onLightClientObject(obj) lightClient.optimisticUpdateObserver = proc(lightClient: LightClient, obj: altair.LightClientOptimisticUpdate) = lightClient.onLightClientObject(obj) ```
This commit is contained in:
parent
dee5af58d6
commit
bbf1d6030c
|
@ -31,11 +31,24 @@ declareHistogram light_client_store_object_duration_seconds,
|
|||
"storeObject() duration", buckets = [0.25, 0.5, 1, 2, 4, 8, Inf]
|
||||
|
||||
type
|
||||
Nothing = object
|
||||
|
||||
GetTrustedBlockRootCallback* =
|
||||
proc(): Option[Eth2Digest] {.gcsafe, raises: [Defect].}
|
||||
VoidCallback* =
|
||||
proc() {.gcsafe, raises: [Defect].}
|
||||
|
||||
ValueObserver[V] =
|
||||
proc(v: V) {.gcsafe, raises: [Defect].}
|
||||
BootstrapObserver* =
|
||||
ValueObserver[altair.LightClientBootstrap]
|
||||
UpdateObserver* =
|
||||
ValueObserver[altair.LightClientUpdate]
|
||||
FinalityUpdateObserver* =
|
||||
ValueObserver[altair.LightClientFinalityUpdate]
|
||||
OptimisticUpdateObserver* =
|
||||
ValueObserver[altair.LightClientOptimisticUpdate]
|
||||
|
||||
LightClientFinalizationMode* {.pure.} = enum
|
||||
Strict
|
||||
## Only finalize light client data that:
|
||||
|
@ -91,6 +104,10 @@ type
|
|||
getBeaconTime: GetBeaconTimeFn
|
||||
getTrustedBlockRoot: GetTrustedBlockRootCallback
|
||||
onStoreInitialized, onFinalizedHeader, onOptimisticHeader: VoidCallback
|
||||
bootstrapObserver: BootstrapObserver
|
||||
updateObserver: UpdateObserver
|
||||
finalityUpdateObserver: FinalityUpdateObserver
|
||||
optimisticUpdateObserver: OptimisticUpdateObserver
|
||||
|
||||
cfg: RuntimeConfig
|
||||
genesis_validators_root: Eth2Digest
|
||||
|
@ -127,7 +144,11 @@ proc new*(
|
|||
getTrustedBlockRoot: GetTrustedBlockRootCallback,
|
||||
onStoreInitialized: VoidCallback = nil,
|
||||
onFinalizedHeader: VoidCallback = nil,
|
||||
onOptimisticHeader: VoidCallback = nil
|
||||
onOptimisticHeader: VoidCallback = nil,
|
||||
bootstrapObserver: BootstrapObserver = nil,
|
||||
updateObserver: UpdateObserver = nil,
|
||||
finalityUpdateObserver: FinalityUpdateObserver = nil,
|
||||
optimisticUpdateObserver: OptimisticUpdateObserver = nil
|
||||
): ref LightClientProcessor =
|
||||
(ref LightClientProcessor)(
|
||||
dumpEnabled: dumpEnabled,
|
||||
|
@ -139,6 +160,10 @@ proc new*(
|
|||
onStoreInitialized: onStoreInitialized,
|
||||
onFinalizedHeader: onFinalizedHeader,
|
||||
onOptimisticHeader: onOptimisticHeader,
|
||||
bootstrapObserver: bootstrapObserver,
|
||||
updateObserver: updateObserver,
|
||||
finalityUpdateObserver: finalityUpdateObserver,
|
||||
optimisticUpdateObserver: optimisticUpdateObserver,
|
||||
cfg: cfg,
|
||||
genesis_validators_root: genesis_validators_root,
|
||||
finalizationMode: finalizationMode)
|
||||
|
@ -252,10 +277,16 @@ proc processObject(
|
|||
|
||||
res
|
||||
|
||||
template withReportedProgress(expectFinalityUpdate: bool, body: untyped): bool =
|
||||
template withReportedProgress(
|
||||
obj: SomeLightClientObject | Nothing, body: untyped): bool =
|
||||
block:
|
||||
let
|
||||
previousWasInitialized = store[].isSome
|
||||
previousNextCommitteeKnown =
|
||||
if store[].isSome:
|
||||
store[].get.is_next_sync_committee_known
|
||||
else:
|
||||
false
|
||||
previousFinalized =
|
||||
if store[].isSome:
|
||||
store[].get.finalized_header
|
||||
|
@ -269,29 +300,55 @@ template withReportedProgress(expectFinalityUpdate: bool, body: untyped): bool =
|
|||
|
||||
body
|
||||
|
||||
var didProgress = false
|
||||
var
|
||||
didProgress = false
|
||||
didSignificantProgress = false
|
||||
|
||||
if store[].isSome != previousWasInitialized:
|
||||
didProgress = true
|
||||
didSignificantProgress = true
|
||||
if self.onStoreInitialized != nil:
|
||||
self.onStoreInitialized()
|
||||
self.onStoreInitialized = nil
|
||||
|
||||
if store[].get.optimistic_header != previousOptimistic:
|
||||
when not expectFinalityUpdate:
|
||||
if store[].isSome:
|
||||
if store[].get.optimistic_header != previousOptimistic:
|
||||
didProgress = true
|
||||
if self.onOptimisticHeader != nil:
|
||||
self.onOptimisticHeader()
|
||||
when obj isnot SomeLightClientUpdateWithFinality:
|
||||
didSignificantProgress = true
|
||||
if self.onOptimisticHeader != nil:
|
||||
self.onOptimisticHeader()
|
||||
|
||||
if store[].get.finalized_header != previousFinalized:
|
||||
didProgress = true
|
||||
if self.onFinalizedHeader != nil:
|
||||
self.onFinalizedHeader()
|
||||
if store[].get.finalized_header != previousFinalized:
|
||||
didProgress = true
|
||||
didSignificantProgress = true
|
||||
if self.onFinalizedHeader != nil:
|
||||
self.onFinalizedHeader()
|
||||
|
||||
didProgress
|
||||
if store[].get.is_next_sync_committee_known != previousNextCommitteeKnown:
|
||||
didProgress = true
|
||||
|
||||
if didProgress:
|
||||
when obj is Nothing:
|
||||
discard
|
||||
elif obj is altair.LightClientBootstrap:
|
||||
if self.bootstrapObserver != nil:
|
||||
self.bootstrapObserver(obj)
|
||||
elif obj is altair.LightClientUpdate:
|
||||
if self.updateObserver != nil:
|
||||
self.updateObserver(obj)
|
||||
elif obj is altair.LightClientFinalityUpdate:
|
||||
if self.finalityUpdateObserver != nil:
|
||||
self.finalityUpdateObserver(obj)
|
||||
elif obj is altair.LightClientOptimisticUpdate:
|
||||
if self.optimisticUpdateObserver != nil:
|
||||
self.optimisticUpdateObserver(obj)
|
||||
else: raiseAssert "Unreachable"
|
||||
|
||||
didSignificantProgress
|
||||
|
||||
template withReportedProgress(body: untyped): bool =
|
||||
withReportedProgress(false, body)
|
||||
withReportedProgress(Nothing(), body)
|
||||
|
||||
proc storeObject*(
|
||||
self: var LightClientProcessor,
|
||||
|
@ -304,8 +361,8 @@ proc storeObject*(
|
|||
startTick = Moment.now()
|
||||
store = self.store
|
||||
|
||||
didProgress =
|
||||
withReportedProgress(obj is SomeLightClientUpdateWithFinality):
|
||||
didSignificantProgress =
|
||||
withReportedProgress(obj):
|
||||
? self.processObject(obj, wallTime)
|
||||
|
||||
let
|
||||
|
@ -328,7 +385,7 @@ proc storeObject*(
|
|||
kind = typeof(obj).name,
|
||||
objectSlot = objSlot,
|
||||
storeObjectDur
|
||||
ok didProgress
|
||||
ok didSignificantProgress
|
||||
|
||||
proc resetToFinalizedHeader*(
|
||||
self: var LightClientProcessor,
|
||||
|
@ -393,8 +450,8 @@ func toValidationError(
|
|||
wallTime: BeaconTime,
|
||||
obj: SomeLightClientObject): Result[void, ValidationError] =
|
||||
if r.isOk:
|
||||
let didProgress = r.get
|
||||
if didProgress:
|
||||
let didSignificantProgress = r.get
|
||||
if didSignificantProgress:
|
||||
let
|
||||
signature_slot = obj.signature_slot
|
||||
currentTime = wallTime + MAXIMUM_GOSSIP_CLOCK_DISPARITY
|
||||
|
|
|
@ -29,6 +29,17 @@ type
|
|||
proc(lightClient: LightClient, header: BeaconBlockHeader) {.
|
||||
gcsafe, raises: [Defect].}
|
||||
|
||||
LightClientValueObserver[V] =
|
||||
proc(lightClient: LightClient, v: V) {.gcsafe, raises: [Defect].}
|
||||
LightClientBootstrapObserver* =
|
||||
LightClientValueObserver[altair.LightClientBootstrap]
|
||||
LightClientUpdateObserver* =
|
||||
LightClientValueObserver[altair.LightClientUpdate]
|
||||
LightClientFinalityUpdateObserver* =
|
||||
LightClientValueObserver[altair.LightClientFinalityUpdate]
|
||||
LightClientOptimisticUpdateObserver* =
|
||||
LightClientValueObserver[altair.LightClientOptimisticUpdate]
|
||||
|
||||
LightClient* = ref object
|
||||
network: Eth2Node
|
||||
cfg: RuntimeConfig
|
||||
|
@ -39,6 +50,10 @@ type
|
|||
manager: LightClientManager
|
||||
gossipState: GossipState
|
||||
onFinalizedHeader*, onOptimisticHeader*: LightClientHeaderCallback
|
||||
bootstrapObserver*: LightClientBootstrapObserver
|
||||
updateObserver*: LightClientUpdateObserver
|
||||
finalityUpdateObserver*: LightClientFinalityUpdateObserver
|
||||
optimisticUpdateObserver*: LightClientOptimisticUpdateObserver
|
||||
trustedBlockRoot*: Option[Eth2Digest]
|
||||
|
||||
func finalizedHeader*(lightClient: LightClient): Opt[BeaconBlockHeader] =
|
||||
|
@ -94,11 +109,28 @@ proc createLightClient(
|
|||
lightClient.onOptimisticHeader(
|
||||
lightClient, lightClient.optimisticHeader.get)
|
||||
|
||||
proc bootstrapObserver(obj: altair.LightClientBootstrap) =
|
||||
if lightClient.bootstrapObserver != nil:
|
||||
lightClient.bootstrapObserver(lightClient, obj)
|
||||
|
||||
proc updateObserver(obj: altair.LightClientUpdate) =
|
||||
if lightClient.updateObserver != nil:
|
||||
lightClient.updateObserver(lightClient, obj)
|
||||
|
||||
proc finalityObserver(obj: altair.LightClientFinalityUpdate) =
|
||||
if lightClient.finalityUpdateObserver != nil:
|
||||
lightClient.finalityUpdateObserver(lightClient, obj)
|
||||
|
||||
proc optimisticObserver(obj: altair.LightClientOptimisticUpdate) =
|
||||
if lightClient.optimisticUpdateObserver != nil:
|
||||
lightClient.optimisticUpdateObserver(lightClient, obj)
|
||||
|
||||
lightClient.processor = LightClientProcessor.new(
|
||||
dumpEnabled, dumpDirInvalid, dumpDirIncoming,
|
||||
cfg, genesis_validators_root, finalizationMode,
|
||||
lightClient.store, getBeaconTime, getTrustedBlockRoot,
|
||||
onStoreInitialized, onFinalizedHeader, onOptimisticHeader)
|
||||
onStoreInitialized, onFinalizedHeader, onOptimisticHeader,
|
||||
bootstrapObserver, updateObserver, finalityObserver, optimisticObserver)
|
||||
|
||||
proc lightClientVerifier(obj: SomeLightClientObject):
|
||||
Future[Result[void, VerifierError]] =
|
||||
|
|
Loading…
Reference in New Issue