send LC finality update on event stream on supermajority (#5602)
When new finality is reached without supermajority sync committee support, trigger another event push on beacon-API and libp2p once the finality gains supermajority support. - https://github.com/ethereum/consensus-specs/pull/3549
This commit is contained in:
parent
98e969084d
commit
b9a693d5fe
|
@ -563,6 +563,11 @@ proc createLightClientUpdates(
|
|||
var finalized_slot = attested_data.finalized_slot
|
||||
if finalized_slot == forkyLatest.finalized_header.beacon.slot:
|
||||
forkyLatest.finality_branch = attested_data.finality_branch
|
||||
let old_num_active_participants =
|
||||
forkyLatest.sync_aggregate.num_active_participants.uint64
|
||||
if not hasSupermajoritySyncParticipation(old_num_active_participants) and
|
||||
hasSupermajoritySyncParticipation(num_active_participants):
|
||||
newFinality = true
|
||||
elif finalized_slot < dag.tail.slot or
|
||||
not load_finalized_bid(finalized_slot):
|
||||
forkyLatest.finalized_header.reset()
|
||||
|
|
|
@ -19,6 +19,10 @@ type
|
|||
## Latest finality update that was forwarded on libp2p gossip.
|
||||
## Tracks `finality_update.finalized_header.beacon.slot`.
|
||||
|
||||
latestForwardedFinalityHasSupermajority*: bool
|
||||
## Whether or not the latest finality update that was forwarded on
|
||||
## libp2p gossip had supermajority (> 2/3) sync committee participation.
|
||||
|
||||
latestForwardedOptimisticSlot*: Slot
|
||||
## Latest optimistic update that was forwarded on libp2p gossip.
|
||||
## Tracks `optimistic_update.attested_header.beacon.slot`.
|
||||
|
|
|
@ -1371,15 +1371,28 @@ proc validateLightClientFinalityUpdate*(
|
|||
pool: var LightClientPool, dag: ChainDAGRef,
|
||||
finality_update: ForkedLightClientFinalityUpdate,
|
||||
wallTime: BeaconTime): Result[void, ValidationError] =
|
||||
# [IGNORE] The `finalized_header.beacon.slot` is greater than that of all
|
||||
# previously forwarded `finality_update`s, or it matches the highest
|
||||
# previously forwarded slot and also has a `sync_aggregate` indicating
|
||||
# supermajority (> 2/3) sync committee participation while the previously
|
||||
# forwarded `finality_update` for that slot did not indicate supermajority
|
||||
let finalized_slot = withForkyFinalityUpdate(finality_update):
|
||||
when lcDataFork > LightClientDataFork.None:
|
||||
forkyFinalityUpdate.finalized_header.beacon.slot
|
||||
else:
|
||||
GENESIS_SLOT
|
||||
if finalized_slot <= pool.latestForwardedFinalitySlot:
|
||||
# [IGNORE] The `finalized_header.beacon.slot` is greater than that of all
|
||||
# previously forwarded `finality_update`s
|
||||
if finalized_slot < pool.latestForwardedFinalitySlot:
|
||||
return errIgnore("LightClientFinalityUpdate: slot already forwarded")
|
||||
let has_supermajority = withForkyFinalityUpdate(finality_update):
|
||||
when lcDataFork > LightClientDataFork.None:
|
||||
forkyFinalityUpdate.sync_aggregate.hasSupermajoritySyncParticipation
|
||||
else:
|
||||
false
|
||||
if finalized_slot == pool.latestForwardedFinalitySlot:
|
||||
if pool.latestForwardedFinalityHasSupermajority:
|
||||
return errIgnore("LightClientFinalityUpdate: already have supermajority")
|
||||
if not has_supermajority:
|
||||
return errIgnore("LightClientFinalityUpdate: no new supermajority")
|
||||
|
||||
let
|
||||
signature_slot = withForkyFinalityUpdate(finality_update):
|
||||
|
@ -1400,6 +1413,7 @@ proc validateLightClientFinalityUpdate*(
|
|||
return errIgnore("LightClientFinalityUpdate: not matching local")
|
||||
|
||||
pool.latestForwardedFinalitySlot = finalized_slot
|
||||
pool.latestForwardedFinalityHasSupermajority = has_supermajority
|
||||
ok()
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.4/specs/altair/light-client/p2p-interface.md#light_client_optimistic_update
|
||||
|
|
|
@ -638,6 +638,14 @@ func init*(T: type SyncAggregate): SyncAggregate =
|
|||
func num_active_participants*(v: SomeSyncAggregate): int =
|
||||
countOnes(v.sync_committee_bits)
|
||||
|
||||
func hasSupermajoritySyncParticipation*(
|
||||
num_active_participants: uint64): bool =
|
||||
const max_active_participants = SYNC_COMMITTEE_SIZE.uint64
|
||||
num_active_participants * 3 >= static(max_active_participants * 2)
|
||||
|
||||
func hasSupermajoritySyncParticipation*(v: SomeSyncAggregate): bool =
|
||||
hasSupermajoritySyncParticipation(v.num_active_participants.uint64)
|
||||
|
||||
func shortLog*(v: SyncAggregate): auto =
|
||||
$(v.sync_committee_bits)
|
||||
|
||||
|
|
|
@ -303,12 +303,11 @@ template toMeta*(update: ForkedLightClientUpdate): LightClientUpdateMetadata =
|
|||
|
||||
func is_better_data*(new_meta, old_meta: LightClientUpdateMetadata): bool =
|
||||
# Compare supermajority (> 2/3) sync committee participation
|
||||
const max_active_participants = SYNC_COMMITTEE_SIZE.uint64
|
||||
let
|
||||
new_has_supermajority =
|
||||
new_meta.num_active_participants * 3 >= max_active_participants * 2
|
||||
hasSupermajoritySyncParticipation(new_meta.num_active_participants)
|
||||
old_has_supermajority =
|
||||
old_meta.num_active_participants * 3 >= max_active_participants * 2
|
||||
hasSupermajoritySyncParticipation(old_meta.num_active_participants)
|
||||
if new_has_supermajority != old_has_supermajority:
|
||||
return new_has_supermajority > old_has_supermajority
|
||||
if not new_has_supermajority:
|
||||
|
|
|
@ -261,6 +261,8 @@ proc isSynced*(node: BeaconNode, head: BlockRef): bool =
|
|||
head.slot + node.config.syncHorizon >= wallSlot.slot
|
||||
|
||||
proc handleLightClientUpdates*(node: BeaconNode, slot: Slot) {.async.} =
|
||||
template pool: untyped = node.lightClientPool[]
|
||||
|
||||
static: doAssert lightClientFinalityUpdateSlotOffset ==
|
||||
lightClientOptimisticUpdateSlotOffset
|
||||
let sendTime = node.beaconClock.fromNow(
|
||||
|
@ -280,14 +282,28 @@ proc handleLightClientUpdates*(node: BeaconNode, slot: Slot) {.async.} =
|
|||
if num_active_participants < MIN_SYNC_COMMITTEE_PARTICIPANTS:
|
||||
return
|
||||
|
||||
let finalized_slot = forkyFinalityUpdate.finalized_header.beacon.slot
|
||||
if finalized_slot > node.lightClientPool[].latestForwardedFinalitySlot:
|
||||
let
|
||||
finalized_slot =
|
||||
forkyFinalityUpdate.finalized_header.beacon.slot
|
||||
has_supermajority =
|
||||
hasSupermajoritySyncParticipation(num_active_participants.uint64)
|
||||
newFinality =
|
||||
if finalized_slot > pool.latestForwardedFinalitySlot:
|
||||
true
|
||||
elif finalized_slot < pool.latestForwardedFinalitySlot:
|
||||
false
|
||||
elif pool.latestForwardedFinalityHasSupermajority:
|
||||
false
|
||||
else:
|
||||
has_supermajority
|
||||
if newFinality:
|
||||
template msg(): auto = forkyFinalityUpdate
|
||||
let sendResult =
|
||||
await node.network.broadcastLightClientFinalityUpdate(msg)
|
||||
|
||||
# Optimization for message with ephemeral validity, whether sent or not
|
||||
node.lightClientPool[].latestForwardedFinalitySlot = finalized_slot
|
||||
pool.latestForwardedFinalitySlot = finalized_slot
|
||||
pool.latestForwardedFinalityHasSupermajority = has_supermajority
|
||||
|
||||
if sendResult.isOk:
|
||||
beacon_light_client_finality_updates_sent.inc()
|
||||
|
@ -297,13 +313,13 @@ proc handleLightClientUpdates*(node: BeaconNode, slot: Slot) {.async.} =
|
|||
error = sendResult.error()
|
||||
|
||||
let attested_slot = forkyFinalityUpdate.attested_header.beacon.slot
|
||||
if attested_slot > node.lightClientPool[].latestForwardedOptimisticSlot:
|
||||
if attested_slot > pool.latestForwardedOptimisticSlot:
|
||||
let msg = forkyFinalityUpdate.toOptimistic
|
||||
let sendResult =
|
||||
await node.network.broadcastLightClientOptimisticUpdate(msg)
|
||||
|
||||
# Optimization for message with ephemeral validity, whether sent or not
|
||||
node.lightClientPool[].latestForwardedOptimisticSlot = attested_slot
|
||||
pool.latestForwardedOptimisticSlot = attested_slot
|
||||
|
||||
if sendResult.isOk:
|
||||
beacon_light_client_optimistic_updates_sent.inc()
|
||||
|
|
Loading…
Reference in New Issue