broadcast optimistic light client updates (#3499)
After proposing a new block, broadcasts a `OptimisticLightClientUpdate`. Works for both locally proposed blocks as well as VC submitted ones.
This commit is contained in:
parent
05ffe7b2bf
commit
9f8894fb43
|
@ -2355,3 +2355,17 @@ proc broadcastSignedContributionAndProof*(
|
||||||
node: Eth2Node, msg: SignedContributionAndProof) =
|
node: Eth2Node, msg: SignedContributionAndProof) =
|
||||||
let topic = getSyncCommitteeContributionAndProofTopic(node.forkDigests.altair)
|
let topic = getSyncCommitteeContributionAndProofTopic(node.forkDigests.altair)
|
||||||
node.broadcast(topic, msg)
|
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)
|
||||||
|
|
|
@ -7,6 +7,10 @@
|
||||||
|
|
||||||
{.push raises: [Defect].}
|
{.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
|
import
|
||||||
std/[hashes, typetraits],
|
std/[hashes, typetraits],
|
||||||
chronicles,
|
chronicles,
|
||||||
|
@ -146,6 +150,9 @@ const
|
||||||
# https://github.com/ethereum/consensus-specs/blob/v1.1.10/specs/altair/validator.md#broadcast-sync-committee-contribution
|
# https://github.com/ethereum/consensus-specs/blob/v1.1.10/specs/altair/validator.md#broadcast-sync-committee-contribution
|
||||||
syncContributionSlotOffset* = TimeDiff(nanoseconds:
|
syncContributionSlotOffset* = TimeDiff(nanoseconds:
|
||||||
NANOSECONDS_PER_SLOT.int64 * 2 div INTERVALS_PER_SLOT)
|
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 =
|
func toFloatSeconds*(t: TimeDiff): float =
|
||||||
float(t.nanoseconds) / 1_000_000_000.0
|
float(t.nanoseconds) / 1_000_000_000.0
|
||||||
|
@ -167,6 +174,8 @@ func sync_committee_message_deadline*(s: Slot): BeaconTime =
|
||||||
s.start_beacon_time + syncCommitteeMessageSlotOffset
|
s.start_beacon_time + syncCommitteeMessageSlotOffset
|
||||||
func sync_contribution_deadline*(s: Slot): BeaconTime =
|
func sync_contribution_deadline*(s: Slot): BeaconTime =
|
||||||
s.start_beacon_time + syncContributionSlotOffset
|
s.start_beacon_time + syncContributionSlotOffset
|
||||||
|
func optimistic_light_client_update_time*(s: Slot): BeaconTime =
|
||||||
|
s.start_beacon_time + optimisticLightClientUpdateSlotOffset
|
||||||
|
|
||||||
func slotOrZero*(time: BeaconTime): Slot =
|
func slotOrZero*(time: BeaconTime): Slot =
|
||||||
let exSlot = time.toSlot
|
let exSlot = time.toSlot
|
||||||
|
|
|
@ -7,6 +7,10 @@
|
||||||
|
|
||||||
{.push raises: [Defect].}
|
{.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
|
import
|
||||||
# Standard library
|
# Standard library
|
||||||
std/[os, osproc, sequtils, streams, tables],
|
std/[os, osproc, sequtils, streams, tables],
|
||||||
|
@ -738,6 +742,19 @@ proc handleSyncCommitteeMessages(node: BeaconNode, head: BlockRef, slot: Slot) =
|
||||||
asyncSpawn createAndSendSyncCommitteeMessage(node, slot, validator,
|
asyncSpawn createAndSendSyncCommitteeMessage(node, slot, validator,
|
||||||
subcommitteeIdx, head)
|
subcommitteeIdx, head)
|
||||||
|
|
||||||
|
proc handleOptimisticLightClientUpdates(
|
||||||
|
node: BeaconNode, head: BlockRef, slot: Slot) =
|
||||||
|
if slot < node.dag.cfg.ALTAIR_FORK_EPOCH.start_slot():
|
||||||
|
return
|
||||||
|
doAssert head.parent != nil, "Newly proposed block lacks parent reference"
|
||||||
|
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,
|
proc signAndSendContribution(node: BeaconNode,
|
||||||
validator: AttachedValidator,
|
validator: AttachedValidator,
|
||||||
contribution: SyncCommitteeContribution,
|
contribution: SyncCommitteeContribution,
|
||||||
|
@ -1070,7 +1087,10 @@ proc handleValidatorDuties*(node: BeaconNode, lastSlot, slot: Slot) {.async.} =
|
||||||
|
|
||||||
curSlot += 1
|
curSlot += 1
|
||||||
|
|
||||||
head = await handleProposal(node, head, slot)
|
let
|
||||||
|
newHead = await handleProposal(node, head, slot)
|
||||||
|
didSubmitBlock = (newHead != head)
|
||||||
|
head = newHead
|
||||||
|
|
||||||
let
|
let
|
||||||
# The latest point in time when we'll be sending out attestations
|
# The latest point in time when we'll be sending out attestations
|
||||||
|
@ -1120,6 +1140,16 @@ proc handleValidatorDuties*(node: BeaconNode, lastSlot, slot: Slot) {.async.} =
|
||||||
handleAttestations(node, head, slot)
|
handleAttestations(node, head, slot)
|
||||||
handleSyncCommitteeMessages(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
|
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
|
# https://github.com/ethereum/consensus-specs/blob/v1.1.10/specs/phase0/validator.md#broadcast-aggregate
|
||||||
|
@ -1277,6 +1307,25 @@ proc sendBeaconBlock*(node: BeaconNode, forked: ForkedSignedBeaconBlock
|
||||||
notice "Block published",
|
notice "Block published",
|
||||||
blockRoot = shortLog(blck.root), blck = shortLog(blck.message),
|
blockRoot = shortLog(blck.root), blck = shortLog(blck.message),
|
||||||
signature = shortLog(blck.signature)
|
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
|
true
|
||||||
else:
|
else:
|
||||||
warn "Unable to add proposed block to block pool",
|
warn "Unable to add proposed block to block pool",
|
||||||
|
|
Loading…
Reference in New Issue