Skip to content

Commit

Permalink
broadcast optimistic light client updates
Browse files Browse the repository at this point in the history
After proposing a new block, broadcasts a `OptimisticLightClientUpdate`.
Works for both locally proposed blocks as well as VC submitted ones.
  • Loading branch information
etan-status committed Mar 15, 2022
1 parent a92b175 commit ad2a56e
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 1 deletion.
14 changes: 14 additions & 0 deletions beacon_chain/networking/eth2_network.nim
Original file line number Diff line number Diff line change
Expand Up @@ -2319,3 +2319,17 @@ proc broadcastSignedContributionAndProof*(
node: Eth2Node, msg: SignedContributionAndProof) =
let topic = getSyncCommitteeContributionAndProofTopic(node.forkDigests.altair)
node.broadcast(topic, msg)

proc broadcastOptimisticLightClientUpdate*(
node: Eth2Node, msg: OptimisticLightClientUpdate) =
let
forkDigest =
if msg.fork_version == node.cfg.SHARDING_FORK_VERSION:
node.forkDigests.sharding
elif msg.fork_version == node.cfg.BELLATRIX_FORK_VERSION:
node.forkDigests.bellatrix
else:
doAssert msg.fork_version == node.cfg.ALTAIR_FORK_VERSION
node.forkDigests.altair
topic = getOptimisticLightClientUpdateTopic(forkDigest)
node.broadcast(topic, msg)
9 changes: 9 additions & 0 deletions beacon_chain/spec/beacon_time.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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/[hashes, typetraits],
chronicles,
Expand Down Expand Up @@ -146,6 +150,9 @@ const
# https://github.com/ethereum/consensus-specs/blob/v1.1.10/specs/altair/validator.md#broadcast-sync-committee-contribution
syncContributionSlotOffset* = TimeDiff(nanoseconds:
NANOSECONDS_PER_SLOT.int64 * 2 div INTERVALS_PER_SLOT)
# https://github.com/ethereum/consensus-specs/blob/vFuture/specs/altair/sync-protocol.md#block-proposal
optimisticLightClientUpdateSlotOffset* = TimeDiff(nanoseconds:
NANOSECONDS_PER_SLOT.int64 div INTERVALS_PER_SLOT)

func toFloatSeconds*(t: TimeDiff): float =
float(t.nanoseconds) / 1_000_000_000.0
Expand All @@ -167,6 +174,8 @@ func sync_committee_message_deadline*(s: Slot): BeaconTime =
s.start_beacon_time + syncCommitteeMessageSlotOffset
func sync_contribution_deadline*(s: Slot): BeaconTime =
s.start_beacon_time + syncContributionSlotOffset
func optimistic_light_client_update_time*(s: Slot): BeaconTime =
s.start_beacon_time + optimisticLightClientUpdateSlotOffset

func slotOrZero*(time: BeaconTime): Slot =
let exSlot = time.toSlot
Expand Down
50 changes: 49 additions & 1 deletion beacon_chain/validators/validator_duties.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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
# Standard library
std/[os, osproc, sequtils, streams, tables],
Expand Down Expand Up @@ -737,6 +741,18 @@ proc handleSyncCommitteeMessages(node: BeaconNode, head: BlockRef, slot: Slot) =
asyncSpawn createAndSendSyncCommitteeMessage(node, slot, validator,
subcommitteeIdx, head)

proc handleOptimisticLightClientUpdates(
node: BeaconNode, head: BlockRef, slot: Slot) =
if slot < node.dag.cfg.ALTAIR_FORK_EPOCH.start_slot():
return
let msg = node.dag.lightClientCache.optimisticUpdate
if msg.attested_header.slot != head.parent.bid.slot:
notice "No optimistic light client update for proposed block",
slot = slot, block_root = shortLog(head.root)
return
node.network.broadcastOptimisticLightClientUpdate(msg)
notice "Sent optimistic light client update", message = shortLog(msg)

proc signAndSendContribution(node: BeaconNode,
validator: AttachedValidator,
contribution: SyncCommitteeContribution,
Expand Down Expand Up @@ -1069,7 +1085,10 @@ proc handleValidatorDuties*(node: BeaconNode, lastSlot, slot: Slot) {.async.} =

curSlot += 1

head = await handleProposal(node, head, slot)
let
newHead = await handleProposal(node, head, slot)
didSubmitBlock = (newHead != head)
head = newHead

let
# The latest point in time when we'll be sending out attestations
Expand Down Expand Up @@ -1119,6 +1138,16 @@ proc handleValidatorDuties*(node: BeaconNode, lastSlot, slot: Slot) {.async.} =
handleAttestations(node, head, slot)
handleSyncCommitteeMessages(node, head, slot)

if node.config.serveLightClientData and didSubmitBlock:
let cutoff = node.beaconClock.fromNow(
slot.optimistic_light_client_update_time())
if cutoff.inFuture:
debug "Waiting to send optimistic light client update",
head = shortLog(head),
optimisticLightClientUpdateCutoff = shortLog(cutoff.offset)
await sleepAsync(cutoff.offset)
handleOptimisticLightClientUpdates(node, head, slot)

updateValidatorMetrics(node) # the important stuff is done, update the vanity numbers

# https://github.com/ethereum/consensus-specs/blob/v1.1.10/specs/phase0/validator.md#broadcast-aggregate
Expand Down Expand Up @@ -1276,6 +1305,25 @@ proc sendBeaconBlock*(node: BeaconNode, forked: ForkedSignedBeaconBlock
notice "Block published",
blockRoot = shortLog(blck.root), blck = shortLog(blck.message),
signature = shortLog(blck.signature)

if node.config.serveLightClientData:
# The optimistic light client update is sent with a delay because it
# only validates once the new block has been processed by the peers.
# https://github.com/ethereum/consensus-specs/blob/vFuture/specs/altair/sync-protocol.md#block-proposal
proc publishOptimisticLightClientUpdate() {.async.} =
let cutoff = node.beaconClock.fromNow(
wallTime.slotOrZero.optimistic_light_client_update_time())
if cutoff.inFuture:
debug "Waiting to publish optimistic light client update",
blockRoot = shortLog(blck.root), blck = shortLog(blck.message),
signature = shortLog(blck.signature),
optimisticLightClientUpdateCutoff = shortLog(cutoff.offset)
await sleepAsync(cutoff.offset)
handleOptimisticLightClientUpdates(
node, newBlockRef.get, wallTime.slotOrZero)

asyncSpawn publishOptimisticLightClientUpdate()

true
else:
warn "Unable to add proposed block to block pool",
Expand Down

0 comments on commit ad2a56e

Please sign in to comment.