diff --git a/beacon_chain/gossip_processing/eth2_processor.nim b/beacon_chain/gossip_processing/eth2_processor.nim index cf9a9c5df..3e9f86891 100644 --- a/beacon_chain/gossip_processing/eth2_processor.nim +++ b/beacon_chain/gossip_processing/eth2_processor.nim @@ -7,6 +7,10 @@ {.push raises: [Defect].} +# References to `vFuture` refer to the pre-release proposal of the libp2p based +# light client sync protocol. Conflicting release versions are not in use. +# https://github.com/ethereum/consensus-specs/pull/2802 + import std/tables, stew/results, bearssl, @@ -58,6 +62,10 @@ declareCounter beacon_sync_committee_contributions_received, "Number of valid sync committee contributions processed by this node" declareCounter beacon_sync_committee_contributions_dropped, "Number of invalid sync committee contributions dropped by this node", labels = ["reason"] +declareCounter beacon_optimistic_light_client_updates_received, + "Number of valid optimistic light client updates processed by this node" +declareCounter beacon_optimistic_light_client_updates_dropped, + "Number of invalid optimistic light client updates dropped by this node", labels = ["reason"] const delayBuckets = [2.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0, Inf] @@ -529,3 +537,24 @@ proc contributionValidator*( beacon_sync_committee_contributions_dropped.inc(1, [$v.error[0]]) err(v.error()) + +# https://github.com/ethereum/consensus-specs/blob/vFuture/specs/altair/sync-protocol.md#optimistic_light_client_update +proc optimisticLightClientUpdateValidator*( + self: var Eth2Processor, src: MsgSource, + optimistic_update: OptimisticLightClientUpdate +): Result[void, ValidationError] = + logScope: + optimistic_update + + debug "Optimistic light client update received" + + let v = self.dag.validateOptimisticLightClientUpdate(optimistic_update) + if v.isOk(): + trace "Optimistic light client update validated" + + beacon_optimistic_light_client_updates_received.inc() + else: + debug "Dropping optimistic light client update", error = v.error + beacon_optimistic_light_client_updates_dropped.inc(1, [$v.error[0]]) + + v diff --git a/beacon_chain/gossip_processing/gossip_validation.nim b/beacon_chain/gossip_processing/gossip_validation.nim index d18fad79b..c6293c049 100644 --- a/beacon_chain/gossip_processing/gossip_validation.nim +++ b/beacon_chain/gossip_processing/gossip_validation.nim @@ -7,6 +7,10 @@ {.push raises: [Defect].} +# References to `vFuture` refer to the pre-release proposal of the libp2p based +# light client sync protocol. Conflicting release versions are not in use. +# https://github.com/ethereum/consensus-specs/pull/2802 + import # Status chronicles, chronos, metrics, @@ -1028,3 +1032,20 @@ proc validateContribution*( sig.get() return ok((sig, participants)) + +# https://github.com/ethereum/consensus-specs/blob/vFuture/specs/altair/sync-protocol.md#optimistic_light_client_update +proc validateOptimisticLightClientUpdate*( + dag: ChainDAGRef, optimistic_update: OptimisticLightClientUpdate): + Result[void, ValidationError] = + template local_update(): auto = dag.lightClientCache.optimisticUpdate + + if optimistic_update != local_update: + # [IGNORE] The optimistic update is not attesting to the latest block's + # parent block. + if optimistic_update.attested_header != local_update.attested_header: + return errIgnore("OptimisticLightClientUpdate: not attesting to latest") + + # [REJECT] The optimistic update does not match the expected value. + return errReject("OptimisticLightClientUpdate: not matching expected value") + + ok() diff --git a/beacon_chain/nimbus_beacon_node.nim b/beacon_chain/nimbus_beacon_node.nim index 825a118eb..bacd9880b 100644 --- a/beacon_chain/nimbus_beacon_node.nim +++ b/beacon_chain/nimbus_beacon_node.nim @@ -814,6 +814,10 @@ proc addAltairMessageHandlers(node: BeaconNode, forkDigest: ForkDigest, slot: Sl node.network.updateSyncnetsMetadata(currentSyncCommitteeSubnets) + if node.config.serveLightClientData: + node.network.subscribe( + getOptimisticLightClientUpdateTopic(forkDigest), basicParams) + proc removeAltairMessageHandlers(node: BeaconNode, forkDigest: ForkDigest) = node.removePhase0MessageHandlers(forkDigest) @@ -825,6 +829,9 @@ proc removeAltairMessageHandlers(node: BeaconNode, forkDigest: ForkDigest) = node.network.unsubscribe( getSyncCommitteeContributionAndProofTopic(forkDigest)) + if node.config.serveLightClientData: + node.network.unsubscribe(getOptimisticLightClientUpdateTopic(forkDigest)) + proc trackCurrentSyncCommitteeTopics(node: BeaconNode, slot: Slot) = # Unlike trackNextSyncCommitteeTopics, just snap to the currently correct # set of subscriptions, and use current_sync_committee. Furthermore, this @@ -1323,6 +1330,21 @@ proc installMessageValidators(node: BeaconNode) = installSyncCommitteeeValidators(node.dag.forkDigests.altair) installSyncCommitteeeValidators(node.dag.forkDigests.bellatrix) + template installOptimisticLightClientUpdateValidator(digest: auto) = + node.network.addValidator( + getOptimisticLightClientUpdateTopic(digest), + proc(msg: OptimisticLightClientUpdate): ValidationResult = + if node.config.serveLightClientData: + toValidationResult( + node.processor[].optimisticLightClientUpdateValidator( + MsgSource.gossip, msg)) + else: + debug "Ignoring optimistic light client update: Feature disabled" + ValidationResult.Ignore) + + installOptimisticLightClientUpdateValidator(node.dag.forkDigests.altair) + installOptimisticLightClientUpdateValidator(node.dag.forkDigests.bellatrix) + proc stop(node: BeaconNode) = bnStatus = BeaconNodeStatus.Stopping notice "Graceful shutdown" diff --git a/beacon_chain/spec/network.nim b/beacon_chain/spec/network.nim index 1fbd14ea7..e9c0ec729 100644 --- a/beacon_chain/spec/network.nim +++ b/beacon_chain/spec/network.nim @@ -7,6 +7,10 @@ {.push raises: [Defect].} +# References to `vFuture` refer to the pre-release proposal of the libp2p based +# light client sync protocol. Conflicting release versions are not in use. +# https://github.com/ethereum/consensus-specs/pull/2802 + import "."/[helpers, forks], "."/datatypes/base @@ -94,6 +98,11 @@ func getSyncCommitteeContributionAndProofTopic*(forkDigest: ForkDigest): string ## For subscribing and unsubscribing to/from a subnet. eth2Prefix(forkDigest) & "sync_committee_contribution_and_proof/ssz_snappy" +# https://github.com/ethereum/consensus-specs/blob/vFuture/specs/altair/sync-protocol.md#optimistic_light_client_update +func getOptimisticLightClientUpdateTopic*(forkDigest: ForkDigest): string = + ## For broadcasting or obtaining the latest `OptimisticLightClientUpdate`. + eth2Prefix(forkDigest) & "optimistic_light_client_update_v0/ssz_snappy" + func getENRForkID*(cfg: RuntimeConfig, epoch: Epoch, genesis_validators_root: Eth2Digest): ENRForkID =