mirror of
https://github.com/status-im/nimbus-eth2.git
synced 2025-02-02 09:46:26 +00:00
add LightClientHeader
wrapper (#4481)
The light client data structures were changed to accommodate additional fields in future forks (e.g., to also hold execution data). There is a minor change to the JSON serialization, where the `header` properties are now nested inside a `LightClientHeader`. The SSZ serialization remains compatible. See https://github.com/ethereum/consensus-specs/pull/3190 and https://github.com/ethereum/beacon-APIs/pull/287
This commit is contained in:
parent
77530841e3
commit
2324136552
@ -34,8 +34,8 @@ logScope: topics = "lcdata"
|
||||
# libp2p request is handled. However, the space savings are quite small.
|
||||
# Furthermore, `LightClientUpdate` is consulted on each new block to attempt
|
||||
# improving it. Continuously decompressing and recompressing seems inefficient.
|
||||
# Finally, the libp2p context bytes depend on `attested_header.slot` to derive
|
||||
# the underlying fork digest; the `kind` column is not sufficient to derive
|
||||
# Finally, the libp2p context bytes depend on `attested_header.beacon.slot` for
|
||||
# deriving the fork digest; the `kind` column is not sufficient to derive
|
||||
# the fork digest, because the same storage format may be used across forks.
|
||||
# SSZ storage selected due to the small size and reduced logic complexity.
|
||||
#
|
||||
|
@ -1,5 +1,5 @@
|
||||
# beacon_chain
|
||||
# Copyright (c) 2022 Status Research & Development GmbH
|
||||
# Copyright (c) 2022-2023 Status Research & Development GmbH
|
||||
# Licensed and distributed under either of
|
||||
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
||||
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
||||
@ -12,6 +12,7 @@ else:
|
||||
|
||||
import
|
||||
chronicles,
|
||||
./spec/datatypes/altair,
|
||||
./beacon_node
|
||||
|
||||
logScope: topics = "beacnde"
|
||||
@ -23,7 +24,7 @@ func shouldSyncOptimistically*(node: BeaconNode, wallSlot: Slot): bool =
|
||||
return false
|
||||
|
||||
shouldSyncOptimistically(
|
||||
optimisticSlot = optimisticHeader.slot,
|
||||
optimisticSlot = optimisticHeader.beacon.slot,
|
||||
dagSlot = getStateField(node.dag.headState, slot),
|
||||
wallSlot = wallSlot)
|
||||
|
||||
@ -85,8 +86,9 @@ proc initLightClient*(
|
||||
|
||||
if config.syncLightClient:
|
||||
proc onOptimisticHeader(
|
||||
lightClient: LightClient, optimisticHeader: BeaconBlockHeader) =
|
||||
optimisticProcessor.setOptimisticHeader(optimisticHeader)
|
||||
lightClient: LightClient,
|
||||
optimisticHeader: altair.LightClientHeader) =
|
||||
optimisticProcessor.setOptimisticHeader(optimisticHeader.beacon)
|
||||
|
||||
lightClient.onOptimisticHeader = onOptimisticHeader
|
||||
lightClient.trustedBlockRoot = config.trustedBlockRoot
|
||||
@ -145,13 +147,14 @@ proc updateLightClientFromDag*(node: BeaconNode) =
|
||||
|
||||
let lcHeader = node.lightClient.finalizedHeader
|
||||
if lcHeader.isSome:
|
||||
if dagPeriod <= lcHeader.get.slot.sync_committee_period:
|
||||
if dagPeriod <= lcHeader.get.beacon.slot.sync_committee_period:
|
||||
return
|
||||
|
||||
let
|
||||
bdata = node.dag.getForkedBlock(dagHead.blck.bid).valueOr:
|
||||
return
|
||||
header = bdata.toBeaconBlockHeader
|
||||
header = withBlck(bdata):
|
||||
blck.toLightClientHeader(LightClientStore.kind)
|
||||
current_sync_committee = block:
|
||||
let tmpState = assignClone(node.dag.headState)
|
||||
node.dag.currentSyncCommitteeForPeriod(tmpState[], dagPeriod).valueOr:
|
||||
|
@ -359,7 +359,7 @@ proc initLightClientUpdateForPeriod(
|
||||
const lcDataFork = LightClientDataFork.Altair
|
||||
update = ForkedLightClientUpdate(kind: lcDataFork)
|
||||
template forkyUpdate: untyped = update.forky(lcDataFork)
|
||||
forkyUpdate.attested_header = blck.toBeaconBlockHeader()
|
||||
forkyUpdate.attested_header = blck.toLightClientHeader(lcDataFork)
|
||||
forkyUpdate.next_sync_committee = forkyState.data.next_sync_committee
|
||||
forkyUpdate.next_sync_committee_branch =
|
||||
forkyState.data.build_proof(altair.NEXT_SYNC_COMMITTEE_INDEX).get
|
||||
@ -377,7 +377,7 @@ proc initLightClientUpdateForPeriod(
|
||||
withBlck(bdata):
|
||||
withForkyUpdate(update):
|
||||
when lcDataFork >= LightClientDataFork.Altair:
|
||||
forkyUpdate.finalized_header = blck.toBeaconBlockHeader()
|
||||
forkyUpdate.finalized_header = blck.toLightClientHeader(lcDataFork)
|
||||
let bdata = dag.getExistingForkedBlock(signatureBid).valueOr:
|
||||
dag.handleUnexpectedLightClientError(signatureBid.slot)
|
||||
return err()
|
||||
@ -465,7 +465,8 @@ template lazy_header(name: untyped): untyped {.dirty.} =
|
||||
dag.handleUnexpectedLightClientError(bid.slot)
|
||||
`name _ ok` = false
|
||||
else:
|
||||
obj.name = bdata.get.toBeaconBlockHeader()
|
||||
withBlck(bdata.get):
|
||||
obj.name = blck.toLightClientHeader(data_fork)
|
||||
`name _ ptr` = addr obj.name
|
||||
`name _ ok`
|
||||
template `assign _ name _ with_migration`(
|
||||
@ -480,7 +481,8 @@ template lazy_header(name: untyped): untyped {.dirty.} =
|
||||
`name _ ok` = false
|
||||
else:
|
||||
obj.migrateToDataFork(data_fork)
|
||||
obj.forky(data_fork).name = bdata.get.toBeaconBlockHeader()
|
||||
withBlck(bdata.get):
|
||||
obj.forky(data_fork).name = blck.toLightClientHeader(data_fork)
|
||||
`name _ ptr` = addr obj.forky(data_fork).name
|
||||
`name _ ok`
|
||||
|
||||
@ -545,8 +547,8 @@ proc createLightClientUpdates(
|
||||
signature_slot = blck.message.slot
|
||||
is_later = withForkyFinalityUpdate(latest):
|
||||
when lcDataFork >= LightClientDataFork.Altair:
|
||||
if attested_slot != forkyFinalityUpdate.attested_header.slot:
|
||||
attested_slot > forkyFinalityUpdate.attested_header.slot
|
||||
if attested_slot != forkyFinalityUpdate.attested_header.beacon.slot:
|
||||
attested_slot > forkyFinalityUpdate.attested_header.beacon.slot
|
||||
else:
|
||||
signature_slot > forkyFinalityUpdate.signature_slot
|
||||
else:
|
||||
@ -555,7 +557,7 @@ proc createLightClientUpdates(
|
||||
template forkyLatest: untyped = latest.forky(data_fork)
|
||||
load_attested_data(attested_bid)
|
||||
let finalized_slot = attested_data.finalized_slot
|
||||
if finalized_slot == forkyLatest.finalized_header.slot:
|
||||
if finalized_slot == forkyLatest.finalized_header.beacon.slot:
|
||||
forkyLatest.finality_branch = attested_data.finality_branch
|
||||
elif finalized_slot == GENESIS_SLOT:
|
||||
forkyLatest.finalized_header.reset()
|
||||
@ -605,7 +607,7 @@ proc createLightClientUpdates(
|
||||
forkyBest.next_sync_committee = next_sync_committee
|
||||
forkyBest.next_sync_committee_branch =
|
||||
attested_data.next_sync_committee_branch
|
||||
if finalized_slot == forkyBest.finalized_header.slot:
|
||||
if finalized_slot == forkyBest.finalized_header.beacon.slot:
|
||||
forkyBest.finality_branch = attested_data.finality_branch
|
||||
elif finalized_slot == GENESIS_SLOT:
|
||||
forkyBest.finalized_header.reset()
|
||||
@ -922,7 +924,7 @@ proc getLightClientBootstrap*(
|
||||
forkyBootstrap.current_sync_committee =
|
||||
dag.existingCurrentSyncCommitteeForPeriod(tmpState[], period).valueOr:
|
||||
return default(ForkedLightClientBootstrap)
|
||||
forkyBootstrap.header = blck.toBeaconBlockHeader()
|
||||
forkyBootstrap.header = blck.toLightClientHeader(lcDataFork)
|
||||
forkyBootstrap.current_sync_committee_branch = branch
|
||||
return bootstrap
|
||||
else:
|
||||
|
@ -1,5 +1,5 @@
|
||||
# beacon_chain
|
||||
# Copyright (c) 2022 Status Research & Development GmbH
|
||||
# Copyright (c) 2022-2023 Status Research & Development GmbH
|
||||
# Licensed and distributed under either of
|
||||
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
||||
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
||||
@ -20,11 +20,11 @@ type
|
||||
LightClientPool* = object
|
||||
latestForwardedFinalitySlot*: Slot
|
||||
## Latest finality update that was forwarded on libp2p gossip.
|
||||
## Tracks `finality_update.finalized_header.slot`.
|
||||
## Tracks `finality_update.finalized_header.beacon.slot`.
|
||||
|
||||
latestForwardedOptimisticSlot*: Slot
|
||||
## Latest optimistic update that was forwarded on libp2p gossip.
|
||||
## Tracks `optimistic_update.attested_header.slot`.
|
||||
## Tracks `optimistic_update.attested_header.beacon.slot`.
|
||||
|
||||
latestBroadcastedSlot*: Slot
|
||||
## Latest slot for which updates were broadcasted on libp2p gossip.
|
||||
|
@ -1098,11 +1098,11 @@ proc validateLightClientFinalityUpdate*(
|
||||
wallTime: BeaconTime): Result[void, ValidationError] =
|
||||
let finalized_slot = withForkyFinalityUpdate(finality_update):
|
||||
when lcDataFork >= LightClientDataFork.Altair:
|
||||
forkyFinalityUpdate.finalized_header.slot
|
||||
forkyFinalityUpdate.finalized_header.beacon.slot
|
||||
else:
|
||||
GENESIS_SLOT
|
||||
if finalized_slot <= pool.latestForwardedFinalitySlot:
|
||||
# [IGNORE] The `finalized_header.slot` is greater than that of all
|
||||
# [IGNORE] The `finalized_header.beacon.slot` is greater than that of all
|
||||
# previously forwarded `finality_update`s
|
||||
return errIgnore("LightClientFinalityUpdate: slot already forwarded")
|
||||
|
||||
@ -1134,11 +1134,11 @@ proc validateLightClientOptimisticUpdate*(
|
||||
wallTime: BeaconTime): Result[void, ValidationError] =
|
||||
let attested_slot = withForkyOptimisticUpdate(optimistic_update):
|
||||
when lcDataFork >= LightClientDataFork.Altair:
|
||||
forkyOptimisticUpdate.attested_header.slot
|
||||
forkyOptimisticUpdate.attested_header.beacon.slot
|
||||
else:
|
||||
GENESIS_SLOT
|
||||
if attested_slot <= pool.latestForwardedOptimisticSlot:
|
||||
# [IGNORE] The `attested_header.slot` is greater than that of all
|
||||
# [IGNORE] The `attested_header.beacon.slot` is greater than that of all
|
||||
# previously forwarded `optimistic_update`s
|
||||
return errIgnore("LightClientOptimisticUpdate: slot already forwarded")
|
||||
|
||||
|
@ -13,6 +13,7 @@ else:
|
||||
import
|
||||
stew/objects,
|
||||
chronos, metrics,
|
||||
../spec/datatypes/altair,
|
||||
../spec/light_client_sync,
|
||||
../consensus_object_pools/block_pools_types,
|
||||
".."/[beacon_clock, sszdump],
|
||||
@ -204,12 +205,12 @@ proc tryForceUpdate(
|
||||
discard
|
||||
of DidUpdateWithoutSupermajority:
|
||||
warn "Light client force-updated without supermajority",
|
||||
finalizedSlot = store[].get.finalized_header.slot,
|
||||
optimisticSlot = store[].get.optimistic_header.slot
|
||||
finalizedSlot = store[].get.finalized_header.beacon.slot,
|
||||
optimisticSlot = store[].get.optimistic_header.beacon.slot
|
||||
of DidUpdateWithoutFinality:
|
||||
warn "Light client force-updated without finality proof",
|
||||
finalizedSlot = store[].get.finalized_header.slot,
|
||||
optimisticSlot = store[].get.optimistic_header.slot
|
||||
finalizedSlot = store[].get.finalized_header.beacon.slot,
|
||||
optimisticSlot = store[].get.optimistic_header.beacon.slot
|
||||
|
||||
proc processObject(
|
||||
self: var LightClientProcessor,
|
||||
@ -299,12 +300,12 @@ template withReportedProgress(
|
||||
if store[].isSome:
|
||||
store[].get.finalized_header
|
||||
else:
|
||||
BeaconBlockHeader()
|
||||
altair.LightClientHeader()
|
||||
previousOptimistic =
|
||||
if store[].isSome:
|
||||
store[].get.optimistic_header
|
||||
else:
|
||||
BeaconBlockHeader()
|
||||
altair.LightClientHeader()
|
||||
|
||||
body
|
||||
|
||||
@ -383,16 +384,16 @@ proc storeObject*(
|
||||
let objSlot = withForkyObject(obj):
|
||||
when lcDataFork >= LightClientDataFork.Altair:
|
||||
when forkyObject is ForkyLightClientBootstrap:
|
||||
forkyObject.header.slot
|
||||
forkyObject.header.beacon.slot
|
||||
elif forkyObject is SomeForkyLightClientUpdateWithFinality:
|
||||
forkyObject.finalized_header.slot
|
||||
forkyObject.finalized_header.beacon.slot
|
||||
else:
|
||||
forkyObject.attested_header.slot
|
||||
forkyObject.attested_header.beacon.slot
|
||||
else:
|
||||
GENESIS_SLOT
|
||||
debug "LC object processed",
|
||||
finalizedSlot = store[].get.finalized_header.slot,
|
||||
optimisticSlot = store[].get.optimistic_header.slot,
|
||||
finalizedSlot = store[].get.finalized_header.beacon.slot,
|
||||
optimisticSlot = store[].get.optimistic_header.beacon.slot,
|
||||
kind = typeof(obj).name,
|
||||
objectSlot = objSlot,
|
||||
storeObjectDur
|
||||
@ -400,7 +401,7 @@ proc storeObject*(
|
||||
|
||||
proc resetToFinalizedHeader*(
|
||||
self: var LightClientProcessor,
|
||||
header: BeaconBlockHeader,
|
||||
header: altair.LightClientHeader,
|
||||
current_sync_committee: SyncCommittee) =
|
||||
let store = self.store
|
||||
|
||||
@ -411,8 +412,8 @@ proc resetToFinalizedHeader*(
|
||||
optimistic_header: header)
|
||||
|
||||
debug "LC reset to finalized header",
|
||||
finalizedSlot = store[].get.finalized_header.slot,
|
||||
optimisticSlot = store[].get.optimistic_header.slot
|
||||
finalizedSlot = store[].get.finalized_header.beacon.slot,
|
||||
optimisticSlot = store[].get.optimistic_header.beacon.slot
|
||||
|
||||
# Enqueue
|
||||
# ------------------------------------------------------------------------------
|
||||
@ -499,9 +500,9 @@ func toValidationError(
|
||||
of VerifierError.MissingParent,
|
||||
VerifierError.UnviableFork,
|
||||
VerifierError.Duplicate:
|
||||
# [IGNORE] The `finalized_header.slot` is greater than that of
|
||||
# [IGNORE] The `finalized_header.beacon.slot` is greater than that of
|
||||
# all previously forwarded `finality_update`s
|
||||
# [IGNORE] The `attested_header.slot` is greater than that of all
|
||||
# [IGNORE] The `attested_header.beacon.slot` is greater than that of all
|
||||
# previously forwarded `optimistic_update`s
|
||||
errIgnore($r.error)
|
||||
|
||||
@ -531,12 +532,12 @@ proc processLightClientOptimisticUpdate*(
|
||||
let
|
||||
latestFinalitySlot = withForkyOptimisticUpdate(self.latestFinalityUpdate):
|
||||
when lcDataFork >= LightClientDataFork.Altair:
|
||||
forkyOptimisticUpdate.attested_header.slot
|
||||
forkyOptimisticUpdate.attested_header.beacon.slot
|
||||
else:
|
||||
GENESIS_SLOT
|
||||
attestedSlot = withForkyOptimisticUpdate(optimistic_update):
|
||||
when lcDataFork >= LightClientDataFork.Altair:
|
||||
forkyOptimisticUpdate.attested_header.slot
|
||||
forkyOptimisticUpdate.attested_header.beacon.slot
|
||||
else:
|
||||
GENESIS_SLOT
|
||||
if attestedSlot >= latestFinalitySlot:
|
||||
|
@ -26,7 +26,7 @@ logScope: topics = "lightcl"
|
||||
|
||||
type
|
||||
LightClientHeaderCallback* =
|
||||
proc(lightClient: LightClient, header: BeaconBlockHeader) {.
|
||||
proc(lightClient: LightClient, header: altair.LightClientHeader) {.
|
||||
gcsafe, raises: [Defect].}
|
||||
|
||||
LightClientValueObserver[V] =
|
||||
@ -56,13 +56,15 @@ type
|
||||
optimisticUpdateObserver*: LightClientOptimisticUpdateObserver
|
||||
trustedBlockRoot*: Option[Eth2Digest]
|
||||
|
||||
func finalizedHeader*(lightClient: LightClient): Opt[BeaconBlockHeader] =
|
||||
func finalizedHeader*(
|
||||
lightClient: LightClient): Opt[altair.LightClientHeader] =
|
||||
if lightClient.store[].isSome:
|
||||
ok lightClient.store[].get.finalized_header
|
||||
else:
|
||||
err()
|
||||
|
||||
func optimisticHeader*(lightClient: LightClient): Opt[BeaconBlockHeader] =
|
||||
func optimisticHeader*(
|
||||
lightClient: LightClient): Opt[altair.LightClientHeader] =
|
||||
if lightClient.store[].isSome:
|
||||
ok lightClient.store[].get.optimistic_header
|
||||
else:
|
||||
@ -157,13 +159,15 @@ proc createLightClient(
|
||||
|
||||
func getFinalizedPeriod(): SyncCommitteePeriod =
|
||||
if lightClient.store[].isSome:
|
||||
lightClient.store[].get.finalized_header.slot.sync_committee_period
|
||||
lightClient.store[].get.finalized_header
|
||||
.beacon.slot.sync_committee_period
|
||||
else:
|
||||
GENESIS_SLOT.sync_committee_period
|
||||
|
||||
func getOptimisticPeriod(): SyncCommitteePeriod =
|
||||
if lightClient.store[].isSome:
|
||||
lightClient.store[].get.optimistic_header.slot.sync_committee_period
|
||||
lightClient.store[].get.optimistic_header
|
||||
.beacon.slot.sync_committee_period
|
||||
else:
|
||||
GENESIS_SLOT.sync_committee_period
|
||||
|
||||
@ -214,7 +218,7 @@ proc start*(lightClient: LightClient) =
|
||||
|
||||
proc resetToFinalizedHeader*(
|
||||
lightClient: LightClient,
|
||||
header: BeaconBlockHeader,
|
||||
header: altair.LightClientHeader,
|
||||
current_sync_committee: SyncCommittee) =
|
||||
lightClient.processor[].resetToFinalizedHeader(header, current_sync_committee)
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
# beacon_chain
|
||||
# Copyright (c) 2022 Status Research & Development GmbH
|
||||
# Copyright (c) 2022-2023 Status Research & Development GmbH
|
||||
# Licensed and distributed under either of
|
||||
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
||||
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
||||
@ -44,7 +44,7 @@ type
|
||||
## SQLite backend
|
||||
|
||||
headers: LightClientHeadersStore
|
||||
## LightClientHeaderKind -> BeaconBlockHeader
|
||||
## LightClientHeaderKind -> altair.LightClientHeader
|
||||
## Stores the latest light client headers.
|
||||
|
||||
syncCommittees: SyncCommitteeStore
|
||||
@ -57,7 +57,7 @@ func initLightClientHeadersStore(
|
||||
? backend.exec("""
|
||||
CREATE TABLE IF NOT EXISTS `""" & name & """` (
|
||||
`kind` INTEGER PRIMARY KEY, -- `LightClientHeaderKind`
|
||||
`header` BLOB -- `BeaconBlockHeader` (SSZ)
|
||||
`header` BLOB -- `altair.LightClientHeader` (SSZ)
|
||||
);
|
||||
""")
|
||||
|
||||
@ -81,26 +81,27 @@ func close(store: LightClientHeadersStore) =
|
||||
store.getStmt.dispose()
|
||||
store.putStmt.dispose()
|
||||
|
||||
proc getLatestFinalizedHeader*(db: LightClientDB): Opt[BeaconBlockHeader] =
|
||||
proc getLatestFinalizedHeader*(
|
||||
db: LightClientDB): Opt[altair.LightClientHeader] =
|
||||
var header: seq[byte]
|
||||
for res in db.headers.getStmt.exec(
|
||||
LightClientHeaderKind.Finalized.int64, header):
|
||||
res.expect("SQL query OK")
|
||||
try:
|
||||
return ok SSZ.decode(header, BeaconBlockHeader)
|
||||
return ok SSZ.decode(header, altair.LightClientHeader)
|
||||
except SszError as exc:
|
||||
error "LC store corrupted", store = "headers",
|
||||
kind = "Finalized", exc = exc.msg
|
||||
return err()
|
||||
|
||||
func putLatestFinalizedHeader*(
|
||||
db: LightClientDB, header: BeaconBlockHeader) =
|
||||
db: LightClientDB, header: altair.LightClientHeader) =
|
||||
block:
|
||||
let res = db.headers.putStmt.exec(
|
||||
(LightClientHeaderKind.Finalized.int64, SSZ.encode(header)))
|
||||
res.expect("SQL query OK")
|
||||
block:
|
||||
let period = header.slot.sync_committee_period
|
||||
let period = header.beacon.slot.sync_committee_period
|
||||
doAssert period.isSupportedBySQLite
|
||||
let res = db.syncCommittees.keepFromStmt.exec(period.int64)
|
||||
res.expect("SQL query OK")
|
||||
|
@ -1,5 +1,5 @@
|
||||
# beacon_chain
|
||||
# Copyright (c) 2022 Status Research & Development GmbH
|
||||
# Copyright (c) 2022-2023 Status Research & Development GmbH
|
||||
# Licensed and distributed under either of
|
||||
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
||||
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
||||
@ -158,21 +158,21 @@ programMain:
|
||||
waitFor network.start()
|
||||
|
||||
proc onFinalizedHeader(
|
||||
lightClient: LightClient, finalizedHeader: BeaconBlockHeader) =
|
||||
lightClient: LightClient, finalizedHeader: altair.LightClientHeader) =
|
||||
info "New LC finalized header",
|
||||
finalized_header = shortLog(finalizedHeader)
|
||||
|
||||
let
|
||||
period = finalizedHeader.slot.sync_committee_period
|
||||
period = finalizedHeader.beacon.slot.sync_committee_period
|
||||
syncCommittee = lightClient.finalizedSyncCommittee.expect("Bootstrap OK")
|
||||
db.putSyncCommittee(period, syncCommittee)
|
||||
db.putLatestFinalizedHeader(finalizedHeader)
|
||||
|
||||
proc onOptimisticHeader(
|
||||
lightClient: LightClient, optimisticHeader: BeaconBlockHeader) =
|
||||
lightClient: LightClient, optimisticHeader: altair.LightClientHeader) =
|
||||
info "New LC optimistic header",
|
||||
optimistic_header = shortLog(optimisticHeader)
|
||||
optimisticProcessor.setOptimisticHeader(optimisticHeader)
|
||||
optimisticProcessor.setOptimisticHeader(optimisticHeader.beacon)
|
||||
|
||||
lightClient.onFinalizedHeader = onFinalizedHeader
|
||||
lightClient.onOptimisticHeader = onOptimisticHeader
|
||||
@ -181,7 +181,7 @@ programMain:
|
||||
let latestHeader = db.getLatestFinalizedHeader()
|
||||
if latestHeader.isOk:
|
||||
let
|
||||
period = latestHeader.get.slot.sync_committee_period
|
||||
period = latestHeader.get.beacon.slot.sync_committee_period
|
||||
syncCommittee = db.getSyncCommittee(period)
|
||||
if syncCommittee.isErr:
|
||||
error "LC store lacks sync committee", finalized_header = latestHeader.get
|
||||
@ -192,8 +192,8 @@ programMain:
|
||||
# - EL clients may not sync when only driven with `forkChoiceUpdated`,
|
||||
# e.g., Geth: "Forkchoice requested unknown head"
|
||||
# - `newPayload` requires the full `ExecutionPayload` (most of block content)
|
||||
# - `ExecutionPayload` block root is not available in `BeaconBlockHeader`,
|
||||
# so won't be exchanged via light client gossip
|
||||
# - `ExecutionPayload` block root is not available in
|
||||
# `altair.LightClientHeader`, so won't be exchanged via light client gossip
|
||||
#
|
||||
# Future `ethereum/consensus-specs` versions may remove need for full blocks.
|
||||
# Therefore, this current mechanism is to be seen as temporary; it is not
|
||||
@ -206,7 +206,7 @@ programMain:
|
||||
|
||||
# Check whether light client has synced sufficiently close to wall slot
|
||||
const maxAge = 2 * SLOTS_PER_EPOCH
|
||||
if optimisticHeader.slot < max(wallSlot, maxAge.Slot) - maxAge:
|
||||
if optimisticHeader.beacon.slot < max(wallSlot, maxAge.Slot) - maxAge:
|
||||
return false
|
||||
|
||||
true
|
||||
@ -268,12 +268,12 @@ programMain:
|
||||
|
||||
finalizedBid =
|
||||
if finalizedHeader.isSome:
|
||||
finalizedHeader.get.toBlockId()
|
||||
finalizedHeader.get.beacon.toBlockId()
|
||||
else:
|
||||
BlockId(root: genesisBlockRoot, slot: GENESIS_SLOT)
|
||||
optimisticBid =
|
||||
if optimisticHeader.isSome:
|
||||
optimisticHeader.get.toBlockId()
|
||||
optimisticHeader.get.beacon.toBlockId()
|
||||
else:
|
||||
BlockId(root: genesisBlockRoot, slot: GENESIS_SLOT)
|
||||
|
||||
|
@ -160,26 +160,31 @@ type
|
||||
NextSyncCommitteeBranch* =
|
||||
array[log2trunc(NEXT_SYNC_COMMITTEE_INDEX), Eth2Digest]
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.3.0-rc.0/specs/altair/light-client/sync-protocol.md#lightclientheader
|
||||
LightClientHeader* = object
|
||||
beacon*: BeaconBlockHeader
|
||||
## Beacon block header
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.3.0-rc.0/specs/altair/light-client/sync-protocol.md#lightclientbootstrap
|
||||
LightClientBootstrap* = object
|
||||
header*: BeaconBlockHeader
|
||||
header*: LightClientHeader
|
||||
## Header matching the requested beacon block root
|
||||
|
||||
current_sync_committee*: SyncCommittee
|
||||
## Current sync committee corresponding to `header.state_root`
|
||||
## Current sync committee corresponding to `header.beacon.state_root`
|
||||
current_sync_committee_branch*: CurrentSyncCommitteeBranch
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.3.0-rc.0/specs/altair/light-client/sync-protocol.md#lightclientupdate
|
||||
LightClientUpdate* = object
|
||||
attested_header*: BeaconBlockHeader
|
||||
attested_header*: LightClientHeader
|
||||
## Header attested to by the sync committee
|
||||
|
||||
next_sync_committee*: SyncCommittee
|
||||
## Next sync committee corresponding to `attested_header.state_root`
|
||||
## Next sync committee corresponding to `attested_header.beacon.state_root`
|
||||
next_sync_committee_branch*: NextSyncCommitteeBranch
|
||||
|
||||
# Finalized header corresponding to `attested_header.state_root`
|
||||
finalized_header*: BeaconBlockHeader
|
||||
# Finalized header corresponding to `attested_header.beacon.state_root`
|
||||
finalized_header*: LightClientHeader
|
||||
finality_branch*: FinalityBranch
|
||||
|
||||
sync_aggregate*: SyncAggregate
|
||||
@ -190,10 +195,10 @@ type
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.3.0-rc.0/specs/altair/light-client/sync-protocol.md#lightclientfinalityupdate
|
||||
LightClientFinalityUpdate* = object
|
||||
# Header attested to by the sync committee
|
||||
attested_header*: BeaconBlockHeader
|
||||
attested_header*: LightClientHeader
|
||||
|
||||
# Finalized header corresponding to `attested_header.state_root`
|
||||
finalized_header*: BeaconBlockHeader
|
||||
# Finalized header corresponding to `attested_header.beacon.state_root`
|
||||
finalized_header*: LightClientHeader
|
||||
finality_branch*: FinalityBranch
|
||||
|
||||
# Sync committee aggregate signature
|
||||
@ -204,7 +209,7 @@ type
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.3.0-rc.0/specs/altair/light-client/sync-protocol.md#lightclientoptimisticupdate
|
||||
LightClientOptimisticUpdate* = object
|
||||
# Header attested to by the sync committee
|
||||
attested_header*: BeaconBlockHeader
|
||||
attested_header*: LightClientHeader
|
||||
|
||||
# Sync committee aggregate signature
|
||||
sync_aggregate*: SyncAggregate
|
||||
@ -229,7 +234,7 @@ type
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.3.0-rc.0/specs/altair/light-client/sync-protocol.md#lightclientstore
|
||||
LightClientStore* = object
|
||||
finalized_header*: BeaconBlockHeader
|
||||
finalized_header*: LightClientHeader
|
||||
## Header that is finalized
|
||||
|
||||
current_sync_committee*: SyncCommittee
|
||||
@ -239,7 +244,7 @@ type
|
||||
best_valid_update*: Opt[LightClientUpdate]
|
||||
## Best available header to switch finalized head to if we see nothing else
|
||||
|
||||
optimistic_header*: BeaconBlockHeader
|
||||
optimistic_header*: LightClientHeader
|
||||
## Most recent available reasonably-safe header
|
||||
|
||||
previous_max_active_participants*: uint64
|
||||
@ -696,6 +701,14 @@ chronicles.formatIt SyncCommitteeContribution: shortLog(it)
|
||||
chronicles.formatIt ContributionAndProof: shortLog(it)
|
||||
chronicles.formatIt SignedContributionAndProof: shortLog(it)
|
||||
|
||||
func is_valid_light_client_header*(v: LightClientHeader): bool =
|
||||
true
|
||||
|
||||
func shortLog*(v: LightClientHeader): auto =
|
||||
(
|
||||
beacon: shortLog(v.beacon)
|
||||
)
|
||||
|
||||
func shortLog*(v: LightClientBootstrap): auto =
|
||||
(
|
||||
header: shortLog(v.header)
|
||||
|
@ -11,7 +11,7 @@ else:
|
||||
{.push raises: [].}
|
||||
|
||||
import
|
||||
./datatypes/[phase0, altair]
|
||||
./datatypes/[phase0, altair, bellatrix, capella, eip4844]
|
||||
|
||||
type
|
||||
LightClientDataFork* {.pure.} = enum # Append only, used in DB data!
|
||||
@ -19,7 +19,7 @@ type
|
||||
Altair = 1
|
||||
|
||||
ForkyLightClientHeader* =
|
||||
BeaconBlockHeader
|
||||
altair.LightClientHeader
|
||||
|
||||
ForkyLightClientBootstrap* =
|
||||
altair.LightClientBootstrap
|
||||
@ -98,7 +98,7 @@ template kind*(x: typedesc[altair.LightClientStore]): LightClientDataFork =
|
||||
|
||||
template header*(kind: static LightClientDataFork): auto =
|
||||
when kind >= LightClientDataFork.Altair:
|
||||
typedesc[BeaconBlockHeader]
|
||||
typedesc[altair.LightClientHeader]
|
||||
else:
|
||||
static: raiseAssert "Unreachable"
|
||||
|
||||
@ -307,3 +307,14 @@ func migratingToDataFork*[T: SomeForkedLightClientObject](
|
||||
var upgradedObject = x
|
||||
upgradedObject.migrateToDataFork(newKind)
|
||||
upgradedObject
|
||||
|
||||
func toLightClientHeader*(
|
||||
blck: # `SomeSignedBeaconBlock` doesn't work here (Nim 1.6)
|
||||
phase0.SignedBeaconBlock | phase0.TrustedSignedBeaconBlock |
|
||||
altair.SignedBeaconBlock | altair.TrustedSignedBeaconBlock |
|
||||
bellatrix.SignedBeaconBlock | bellatrix.TrustedSignedBeaconBlock |
|
||||
capella.SignedBeaconBlock | capella.TrustedSignedBeaconBlock |
|
||||
eip4844.SignedBeaconBlock | eip4844.TrustedSignedBeaconBlock,
|
||||
kind: static LightClientDataFork): auto =
|
||||
when kind >= LightClientDataFork.Altair:
|
||||
kind.header(beacon: blck.message.toBeaconBlockHeader())
|
||||
|
@ -240,10 +240,10 @@ type LightClientUpdateMetadata* = object
|
||||
func toMeta*(update: SomeLightClientUpdate): LightClientUpdateMetadata =
|
||||
var meta {.noinit.}: LightClientUpdateMetadata
|
||||
meta.attested_slot =
|
||||
update.attested_header.slot
|
||||
update.attested_header.beacon.slot
|
||||
meta.finalized_slot =
|
||||
when update is SomeLightClientUpdateWithFinality:
|
||||
update.finalized_header.slot
|
||||
update.finalized_header.beacon.slot
|
||||
else:
|
||||
GENESIS_SLOT
|
||||
meta.signature_slot =
|
||||
@ -324,13 +324,13 @@ template is_better_update*[
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.1/specs/altair/light-client/p2p-interface.md#getlightclientbootstrap
|
||||
func contextEpoch*(bootstrap: altair.LightClientBootstrap): Epoch =
|
||||
bootstrap.header.slot.epoch
|
||||
bootstrap.header.beacon.slot.epoch
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.3.0-rc.0/specs/altair/light-client/p2p-interface.md#lightclientupdatesbyrange
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.3.0-rc.0/specs/altair/light-client/p2p-interface.md#getlightclientfinalityupdate
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.3.0-rc.0/specs/altair/light-client/p2p-interface.md#getlightclientoptimisticupdate
|
||||
func contextEpoch*(update: SomeLightClientUpdate): Epoch =
|
||||
update.attested_header.slot.epoch
|
||||
update.attested_header.beacon.slot.epoch
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.3.0-rc.0/specs/bellatrix/beacon-chain.md#is_merge_transition_complete
|
||||
func is_merge_transition_complete*(
|
||||
|
@ -23,6 +23,8 @@ func initialize_light_client_store*(
|
||||
trusted_block_root: Eth2Digest,
|
||||
bootstrap: altair.LightClientBootstrap
|
||||
): Result[LightClientStore, VerifierError] =
|
||||
if not is_valid_light_client_header(bootstrap.header):
|
||||
return err(VerifierError.Invalid)
|
||||
if hash_tree_root(bootstrap.header) != trusted_block_root:
|
||||
return err(VerifierError.Invalid)
|
||||
|
||||
@ -31,7 +33,7 @@ func initialize_light_client_store*(
|
||||
bootstrap.current_sync_committee_branch,
|
||||
log2trunc(altair.CURRENT_SYNC_COMMITTEE_INDEX),
|
||||
get_subtree_index(altair.CURRENT_SYNC_COMMITTEE_INDEX),
|
||||
bootstrap.header.state_root):
|
||||
bootstrap.header.beacon.state_root):
|
||||
return err(VerifierError.Invalid)
|
||||
|
||||
return ok(LightClientStore(
|
||||
@ -54,15 +56,17 @@ proc validate_light_client_update*(
|
||||
return err(VerifierError.Invalid)
|
||||
|
||||
# Verify update does not skip a sync committee period
|
||||
if not is_valid_light_client_header(update.attested_header):
|
||||
return err(VerifierError.Invalid)
|
||||
when update is SomeLightClientUpdateWithFinality:
|
||||
if update.attested_header.slot < update.finalized_header.slot:
|
||||
if update.attested_header.beacon.slot < update.finalized_header.beacon.slot:
|
||||
return err(VerifierError.Invalid)
|
||||
if update.signature_slot <= update.attested_header.slot:
|
||||
if update.signature_slot <= update.attested_header.beacon.slot:
|
||||
return err(VerifierError.Invalid)
|
||||
if current_slot < update.signature_slot:
|
||||
return err(VerifierError.UnviableFork)
|
||||
let
|
||||
store_period = store.finalized_header.slot.sync_committee_period
|
||||
store_period = store.finalized_header.beacon.slot.sync_committee_period
|
||||
signature_period = update.signature_slot.sync_committee_period
|
||||
is_next_sync_committee_known = store.is_next_sync_committee_known
|
||||
if is_next_sync_committee_known:
|
||||
@ -73,10 +77,10 @@ proc validate_light_client_update*(
|
||||
return err(VerifierError.MissingParent)
|
||||
|
||||
# Verify update is relevant
|
||||
let attested_period = update.attested_header.slot.sync_committee_period
|
||||
let attested_period = update.attested_header.beacon.slot.sync_committee_period
|
||||
when update is SomeLightClientUpdateWithSyncCommittee:
|
||||
let is_sync_committee_update = update.is_sync_committee_update
|
||||
if update.attested_header.slot <= store.finalized_header.slot:
|
||||
if update.attested_header.beacon.slot <= store.finalized_header.beacon.slot:
|
||||
when update is SomeLightClientUpdateWithSyncCommittee:
|
||||
if is_next_sync_committee_known:
|
||||
return err(VerifierError.Duplicate)
|
||||
@ -89,13 +93,15 @@ proc validate_light_client_update*(
|
||||
# finalized header saved in the state of the `attested_header`
|
||||
when update is SomeLightClientUpdateWithFinality:
|
||||
if not update.is_finality_update:
|
||||
if not update.finalized_header.isZeroMemory:
|
||||
if update.finalized_header != altair.LightClientHeader():
|
||||
return err(VerifierError.Invalid)
|
||||
else:
|
||||
var finalized_root {.noinit.}: Eth2Digest
|
||||
if update.finalized_header.slot != GENESIS_SLOT:
|
||||
finalized_root = hash_tree_root(update.finalized_header)
|
||||
elif update.finalized_header.isZeroMemory:
|
||||
if update.finalized_header.beacon.slot != GENESIS_SLOT:
|
||||
if not is_valid_light_client_header(update.finalized_header):
|
||||
return err(VerifierError.Invalid)
|
||||
finalized_root = hash_tree_root(update.finalized_header.beacon)
|
||||
elif update.finalized_header == altair.LightClientHeader():
|
||||
finalized_root.reset()
|
||||
else:
|
||||
return err(VerifierError.Invalid)
|
||||
@ -104,14 +110,14 @@ proc validate_light_client_update*(
|
||||
update.finality_branch,
|
||||
log2trunc(altair.FINALIZED_ROOT_INDEX),
|
||||
get_subtree_index(altair.FINALIZED_ROOT_INDEX),
|
||||
update.attested_header.state_root):
|
||||
update.attested_header.beacon.state_root):
|
||||
return err(VerifierError.Invalid)
|
||||
|
||||
# Verify that the `next_sync_committee`, if present, actually is the
|
||||
# next sync committee saved in the state of the `attested_header`
|
||||
when update is SomeLightClientUpdateWithSyncCommittee:
|
||||
if not is_sync_committee_update:
|
||||
if not update.next_sync_committee.isZeroMemory:
|
||||
if update.next_sync_committee != altair.SyncCommittee():
|
||||
return err(VerifierError.Invalid)
|
||||
else:
|
||||
if attested_period == store_period and is_next_sync_committee_known:
|
||||
@ -122,7 +128,7 @@ proc validate_light_client_update*(
|
||||
update.next_sync_committee_branch,
|
||||
log2trunc(altair.NEXT_SYNC_COMMITTEE_INDEX),
|
||||
get_subtree_index(altair.NEXT_SYNC_COMMITTEE_INDEX),
|
||||
update.attested_header.state_root):
|
||||
update.attested_header.beacon.state_root):
|
||||
return err(VerifierError.Invalid)
|
||||
|
||||
# Verify sync committee aggregate signature
|
||||
@ -140,7 +146,7 @@ proc validate_light_client_update*(
|
||||
fork_version = cfg.forkVersionAtEpoch(update.signature_slot.epoch)
|
||||
domain = compute_domain(
|
||||
DOMAIN_SYNC_COMMITTEE, fork_version, genesis_validators_root)
|
||||
signing_root = compute_signing_root(update.attested_header, domain)
|
||||
signing_root = compute_signing_root(update.attested_header.beacon, domain)
|
||||
if not blsFastAggregateVerify(
|
||||
participant_pubkeys, signing_root.data,
|
||||
sync_aggregate.sync_committee_signature):
|
||||
@ -154,8 +160,8 @@ func apply_light_client_update(
|
||||
update: SomeLightClientUpdate): bool =
|
||||
var didProgress = false
|
||||
let
|
||||
store_period = store.finalized_header.slot.sync_committee_period
|
||||
finalized_period = update.finalized_header.slot.sync_committee_period
|
||||
store_period = store.finalized_header.beacon.slot.sync_committee_period
|
||||
finalized_period = update.finalized_header.beacon.slot.sync_committee_period
|
||||
if not store.is_next_sync_committee_known:
|
||||
assert finalized_period == store_period
|
||||
when update is SomeLightClientUpdateWithSyncCommittee:
|
||||
@ -172,9 +178,9 @@ func apply_light_client_update(
|
||||
store.current_max_active_participants
|
||||
store.current_max_active_participants = 0
|
||||
didProgress = true
|
||||
if update.finalized_header.slot > store.finalized_header.slot:
|
||||
if update.finalized_header.beacon.slot > store.finalized_header.beacon.slot:
|
||||
store.finalized_header = update.finalized_header
|
||||
if store.finalized_header.slot > store.optimistic_header.slot:
|
||||
if store.finalized_header.beacon.slot > store.optimistic_header.beacon.slot:
|
||||
store.optimistic_header = store.finalized_header
|
||||
didProgress = true
|
||||
didProgress
|
||||
@ -191,10 +197,15 @@ func process_light_client_store_force_update*(
|
||||
current_slot: Slot): ForceUpdateResult {.discardable.} =
|
||||
var res = NoUpdate
|
||||
if store.best_valid_update.isSome and
|
||||
current_slot > store.finalized_header.slot + UPDATE_TIMEOUT:
|
||||
current_slot > store.finalized_header.beacon.slot + UPDATE_TIMEOUT:
|
||||
# Forced best update when the update timeout has elapsed
|
||||
# Because the apply logic waits for `finalized_header.beacon.slot`
|
||||
# to indicate sync committee finality, the `attested_header` may be
|
||||
# treated as `finalized_header` in extended periods of non-finality
|
||||
# to guarantee progression into later sync committee periods according
|
||||
# to `is_better_update`.
|
||||
template best(): auto = store.best_valid_update.get
|
||||
if best.finalized_header.slot <= store.finalized_header.slot:
|
||||
if best.finalized_header.beacon.slot <= store.finalized_header.beacon.slot:
|
||||
best.finalized_header = best.attested_header
|
||||
if apply_light_client_update(store, best):
|
||||
template sync_aggregate(): auto = best.sync_aggregate
|
||||
@ -235,7 +246,7 @@ proc process_light_client_update*(
|
||||
|
||||
# Update the optimistic header
|
||||
if num_active_participants > get_safety_threshold(store) and
|
||||
update.attested_header.slot > store.optimistic_header.slot:
|
||||
update.attested_header.beacon.slot > store.optimistic_header.beacon.slot:
|
||||
store.optimistic_header = update.attested_header
|
||||
didProgress = true
|
||||
|
||||
@ -243,13 +254,13 @@ proc process_light_client_update*(
|
||||
when update is SomeLightClientUpdateWithFinality:
|
||||
if num_active_participants * 3 >= static(sync_committee_bits.len * 2):
|
||||
var improvesFinality =
|
||||
update.finalized_header.slot > store.finalized_header.slot
|
||||
update.finalized_header.beacon.slot > store.finalized_header.beacon.slot
|
||||
when update is SomeLightClientUpdateWithSyncCommittee:
|
||||
if not improvesFinality and not store.is_next_sync_committee_known:
|
||||
improvesFinality =
|
||||
update.is_sync_committee_update and update.is_finality_update and
|
||||
update.finalized_header.slot.sync_committee_period ==
|
||||
update.attested_header.slot.sync_committee_period
|
||||
update.finalized_header.beacon.slot.sync_committee_period ==
|
||||
update.attested_header.beacon.slot.sync_committee_period
|
||||
if improvesFinality:
|
||||
# Normal update through 2/3 threshold
|
||||
if apply_light_client_update(store, update):
|
||||
|
@ -54,8 +54,8 @@ proc dump*(dir: string, v: ForkyLightClientBootstrap) =
|
||||
logErrors:
|
||||
let
|
||||
prefix = "bootstrap"
|
||||
slot = v.header.slot
|
||||
blck = shortLog(v.header.hash_tree_root())
|
||||
slot = v.header.beacon.slot
|
||||
blck = shortLog(v.header.beacon.hash_tree_root())
|
||||
root = shortLog(v.hash_tree_root())
|
||||
SSZ.saveFile(
|
||||
dir / &"{prefix}-{slot}-{blck}-{root}.ssz", v)
|
||||
@ -70,8 +70,8 @@ proc dump*(dir: string, v: SomeLightClientUpdate) =
|
||||
"finality-update"
|
||||
elif v is ForkyLightClientOptimisticUpdate:
|
||||
"optimistic-update"
|
||||
attestedSlot = v.attested_header.slot
|
||||
attestedBlck = shortLog(v.attested_header.hash_tree_root())
|
||||
attestedSlot = v.attested_header.beacon.slot
|
||||
attestedBlck = shortLog(v.attested_header.beacon.hash_tree_root())
|
||||
syncCommitteeSuffix =
|
||||
when v is SomeForkyLightClientUpdateWithSyncCommittee:
|
||||
if v.is_sync_committee_update:
|
||||
|
@ -148,7 +148,8 @@ proc doRequest(
|
||||
withForkyUpdate(update):
|
||||
when lcDataFork >= LightClientDataFork.Altair:
|
||||
let
|
||||
attPeriod = forkyUpdate.attested_header.slot.sync_committee_period
|
||||
attPeriod =
|
||||
forkyUpdate.attested_header.beacon.slot.sync_committee_period
|
||||
sigPeriod = forkyUpdate.signature_slot.sync_committee_period
|
||||
if attPeriod != sigPeriod:
|
||||
raise newException(
|
||||
|
@ -191,7 +191,7 @@ proc handleLightClientUpdates*(node: BeaconNode, slot: Slot) {.async.} =
|
||||
if num_active_participants < MIN_SYNC_COMMITTEE_PARTICIPANTS:
|
||||
return
|
||||
|
||||
let finalized_slot = forkyFinalityUpdate.finalized_header.slot
|
||||
let finalized_slot = forkyFinalityUpdate.finalized_header.beacon.slot
|
||||
if finalized_slot > node.lightClientPool[].latestForwardedFinalitySlot:
|
||||
template msg(): auto = forkyFinalityUpdate
|
||||
let sendResult =
|
||||
@ -207,7 +207,7 @@ proc handleLightClientUpdates*(node: BeaconNode, slot: Slot) {.async.} =
|
||||
warn "LC finality update failed to send",
|
||||
error = sendResult.error()
|
||||
|
||||
let attested_slot = forkyFinalityUpdate.attested_header.slot
|
||||
let attested_slot = forkyFinalityUpdate.attested_header.beacon.slot
|
||||
if attested_slot > node.lightClientPool[].latestForwardedOptimisticSlot:
|
||||
let msg = forkyFinalityUpdate.toOptimistic
|
||||
let sendResult =
|
||||
|
@ -153,21 +153,21 @@ INF 2022-11-21 18:01:24.734+01:00 Exchanged engine configuration top
|
||||
INF 2022-11-21 18:02:48.001+01:00 Slot start slot=1109714 epoch=34678 sync=bootstrapping(c092a1d110a1c8d630ac2c3fa2565813d43087f42c986855a2cd985b995a328c) peers=6 head=fb9b64fe:0 finalized=fb9b64fe:0 delay=1ms161us
|
||||
WRN 2022-11-21 18:02:53.603+01:00 Peer count low, no new peers discovered topics="networking" discovered_nodes=1 new_peers=@[] current_peers=6 wanted_peers=160
|
||||
INF 2022-11-21 18:03:00.001+01:00 Slot start slot=1109715 epoch=34678 sync=bootstrapping(c092a1d110a1c8d630ac2c3fa2565813d43087f42c986855a2cd985b995a328c) peers=5 head=fb9b64fe:0 finalized=fb9b64fe:0 delay=1ms154us
|
||||
INF 2022-11-21 18:03:09.989+01:00 New LC optimistic header optimistic_header="(slot: 1109216, proposer_index: 1813, parent_root: \"0871af30\", state_root: \"5c0afc98\")"
|
||||
INF 2022-11-21 18:03:09.989+01:00 New LC finalized header finalized_header="(slot: 1109216, proposer_index: 1813, parent_root: \"0871af30\", state_root: \"5c0afc98\")"
|
||||
INF 2022-11-21 18:03:09.989+01:00 New LC optimistic header optimistic_header="(beacon: (slot: 1109216, proposer_index: 1813, parent_root: \"0871af30\", state_root: \"5c0afc98\"))"
|
||||
INF 2022-11-21 18:03:09.989+01:00 New LC finalized header finalized_header="(beacon: (slot: 1109216, proposer_index: 1813, parent_root: \"0871af30\", state_root: \"5c0afc98\"))"
|
||||
INF 2022-11-21 18:03:12.001+01:00 Slot start slot=1109716 epoch=34678 sync=syncing peers=6 head=c092a1d1:1109216 finalized=c092a1d1:1109216 delay=1ms159us
|
||||
INF 2022-11-21 18:03:16.047+01:00 New LC optimistic header optimistic_header="(slot: 1109715, proposer_index: 262, parent_root: \"676f4fe4\", state_root: \"2d13aa42\")"
|
||||
INF 2022-11-21 18:03:16.047+01:00 New LC optimistic header optimistic_header="(beacon: (slot: 1109715, proposer_index: 262, parent_root: \"676f4fe4\", state_root: \"2d13aa42\"))"
|
||||
INF 2022-11-21 18:03:24.001+01:00 Slot start slot=1109717 epoch=34678 sync=synced peers=7 head=58cae92a:1109715 finalized=c092a1d1:1109216 delay=1ms120us
|
||||
INF 2022-11-21 18:03:27.984+01:00 New LC optimistic header optimistic_header="(slot: 1109716, proposer_index: 1281, parent_root: \"58cae92a\", state_root: \"de464f71\")"
|
||||
INF 2022-11-21 18:03:27.984+01:00 New LC optimistic header optimistic_header="(beacon: (slot: 1109716, proposer_index: 1281, parent_root: \"58cae92a\", state_root: \"de464f71\"))"
|
||||
WRN 2022-11-21 18:03:31.419+01:00 Peer count low, no new peers discovered topics="networking" discovered_nodes=0 new_peers=@[] current_peers=7 wanted_peers=160
|
||||
INF 2022-11-21 18:03:36.001+01:00 Slot start slot=1109718 epoch=34678 sync=synced peers=7 head=c5464508:1109716 finalized=c092a1d1:1109216 delay=1ms98us
|
||||
INF 2022-11-21 18:03:40.012+01:00 New LC optimistic header optimistic_header="(slot: 1109717, proposer_index: 835, parent_root: \"c5464508\", state_root: \"13f823f8\")"
|
||||
INF 2022-11-21 18:03:40.012+01:00 New LC optimistic header optimistic_header="(beacon: (slot: 1109717, proposer_index: 835, parent_root: \"c5464508\", state_root: \"13f823f8\"))"
|
||||
NOT 2022-11-21 18:03:40.012+01:00 New LC optimistic block opt=99ab28aa:1109717 wallSlot=1109718
|
||||
WRN 2022-11-21 18:03:40.422+01:00 Peer count low, no new peers discovered topics="networking" discovered_nodes=1 new_peers=@[] current_peers=7 wanted_peers=160
|
||||
INF 2022-11-21 18:03:48.001+01:00 Slot start slot=1109719 epoch=34678 sync=synced peers=7 head=99ab28aa:1109717 finalized=c092a1d1:1109216 delay=1ms53us
|
||||
WRN 2022-11-21 18:03:50.205+01:00 Peer count low, no new peers discovered topics="networking" discovered_nodes=0 new_peers=@[] current_peers=7 wanted_peers=160
|
||||
INF 2022-11-21 18:04:00.001+01:00 Slot start slot=1109720 epoch=34678 sync=synced peers=7 head=99ab28aa:1109717 finalized=c092a1d1:1109216 delay=1ms145us
|
||||
INF 2022-11-21 18:04:03.982+01:00 New LC optimistic header optimistic_header="(slot: 1109718, proposer_index: 1202, parent_root: \"99ab28aa\", state_root: \"7f7f88d2\")"
|
||||
INF 2022-11-21 18:04:03.982+01:00 New LC optimistic header optimistic_header="(beacon: (slot: 1109718, proposer_index: 1202, parent_root: \"99ab28aa\", state_root: \"7f7f88d2\"))"
|
||||
NOT 2022-11-21 18:04:03.982+01:00 New LC optimistic block opt=ab007266:1109718 wallSlot=1109720
|
||||
```
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
# beacon_chain
|
||||
# Copyright (c) 2021-2022 Status Research & Development GmbH
|
||||
# Copyright (c) 2021-2023 Status Research & Development GmbH
|
||||
# Licensed and distributed under either of
|
||||
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
||||
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
||||
@ -140,11 +140,11 @@ let full_sync_committee_bits = block:
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.2/tests/core/pyspec/eth2spec/test/helpers/light_client.py#L20-L29
|
||||
func initialize_light_client_store(state: auto): LightClientStore =
|
||||
LightClientStore(
|
||||
finalized_header: BeaconBlockHeader(),
|
||||
finalized_header: altair.LightClientHeader(),
|
||||
current_sync_committee: state.current_sync_committee,
|
||||
next_sync_committee: state.next_sync_committee,
|
||||
best_valid_update: Opt.none(altair.LightClientUpdate),
|
||||
optimistic_header: BeaconBlockHeader(),
|
||||
optimistic_header: altair.LightClientHeader(),
|
||||
previous_max_active_participants: 0,
|
||||
current_max_active_participants: 0,
|
||||
)
|
||||
@ -162,13 +162,14 @@ suite "EF - Altair - Unittests - Light client - Sync protocol" & preset():
|
||||
let forked = assignClone(genesisState[])
|
||||
template state(): auto = forked[].altairData.data
|
||||
var store = initialize_light_client_store(state)
|
||||
const lcDataFork = typeof(store).kind
|
||||
|
||||
# Block at slot 1 doesn't increase sync committee period,
|
||||
# so it won't update snapshot
|
||||
var cache: StateCache
|
||||
let
|
||||
attested_block = block_for_next_slot(cfg, forked[], cache).altairData
|
||||
attested_header = attested_block.toBeaconBlockHeader
|
||||
attested_header = attested_block.toLightClientHeader(lcDataFork)
|
||||
|
||||
# Sync committee signing the attested_header
|
||||
(sync_aggregate, signature_slot) = get_sync_aggregate(cfg, forked[])
|
||||
@ -179,7 +180,7 @@ suite "EF - Altair - Unittests - Light client - Sync protocol" & preset():
|
||||
check state.finalized_checkpoint.epoch == 0
|
||||
# Finality is unchanged
|
||||
let
|
||||
finality_header = BeaconBlockHeader()
|
||||
finality_header = altair.LightClientHeader()
|
||||
finality_branch = default(altair.FinalityBranch)
|
||||
|
||||
update = altair.LightClientUpdate(
|
||||
@ -208,6 +209,7 @@ suite "EF - Altair - Unittests - Light client - Sync protocol" & preset():
|
||||
var forked = assignClone(genesisState[])
|
||||
template state(): auto = forked[].altairData.data
|
||||
var store = initialize_light_client_store(state)
|
||||
const lcDataFork = typeof(store).kind
|
||||
|
||||
# Forward to slot before next sync committee period so that next block is
|
||||
# final one in period
|
||||
@ -218,13 +220,13 @@ suite "EF - Altair - Unittests - Light client - Sync protocol" & preset():
|
||||
cfg, forked[], Slot(UPDATE_TIMEOUT - 2), cache, info, flags = {}
|
||||
).expect("no failure")
|
||||
let
|
||||
store_period = sync_committee_period(store.optimistic_header.slot)
|
||||
store_period = sync_committee_period(store.optimistic_header.beacon.slot)
|
||||
update_period = sync_committee_period(state.slot)
|
||||
check: store_period == update_period
|
||||
|
||||
let
|
||||
attested_block = block_for_next_slot(cfg, forked[], cache).altairData
|
||||
attested_header = attested_block.toBeaconBlockHeader
|
||||
attested_header = attested_block.toLightClientHeader(lcDataFork)
|
||||
|
||||
# Sync committee signing the attested_header
|
||||
(sync_aggregate, signature_slot) = get_sync_aggregate(cfg, forked[])
|
||||
@ -232,7 +234,7 @@ suite "EF - Altair - Unittests - Light client - Sync protocol" & preset():
|
||||
next_sync_committee_branch = default(altair.NextSyncCommitteeBranch)
|
||||
|
||||
# Finality is unchanged
|
||||
finality_header = BeaconBlockHeader()
|
||||
finality_header = altair.LightClientHeader()
|
||||
finality_branch = default(altair.FinalityBranch)
|
||||
|
||||
update = altair.LightClientUpdate(
|
||||
@ -261,6 +263,7 @@ suite "EF - Altair - Unittests - Light client - Sync protocol" & preset():
|
||||
let forked = assignClone(genesisState[])
|
||||
template state(): auto = forked[].altairData.data
|
||||
var store = initialize_light_client_store(state)
|
||||
const lcDataFork = typeof(store).kind
|
||||
|
||||
# Forward to next sync committee period
|
||||
var
|
||||
@ -270,13 +273,13 @@ suite "EF - Altair - Unittests - Light client - Sync protocol" & preset():
|
||||
cfg, forked[], Slot(UPDATE_TIMEOUT), cache, info, flags = {}
|
||||
).expect("no failure")
|
||||
let
|
||||
store_period = sync_committee_period(store.optimistic_header.slot)
|
||||
store_period = sync_committee_period(store.optimistic_header.beacon.slot)
|
||||
update_period = sync_committee_period(state.slot)
|
||||
check: store_period + 1 == update_period
|
||||
|
||||
let
|
||||
attested_block = block_for_next_slot(cfg, forked[], cache).altairData
|
||||
attested_header = attested_block.toBeaconBlockHeader
|
||||
attested_header = attested_block.toLightClientHeader(lcDataFork)
|
||||
|
||||
# Sync committee signing the attested_header
|
||||
(sync_aggregate, signature_slot) = get_sync_aggregate(cfg, forked[])
|
||||
@ -288,7 +291,7 @@ suite "EF - Altair - Unittests - Light client - Sync protocol" & preset():
|
||||
state.build_proof(altair.NEXT_SYNC_COMMITTEE_INDEX).get
|
||||
|
||||
# Finality is unchanged
|
||||
finality_header = BeaconBlockHeader()
|
||||
finality_header = altair.LightClientHeader()
|
||||
finality_branch = default(altair.FinalityBranch)
|
||||
|
||||
update = altair.LightClientUpdate(
|
||||
@ -317,6 +320,7 @@ suite "EF - Altair - Unittests - Light client - Sync protocol" & preset():
|
||||
let forked = assignClone(genesisState[])
|
||||
template state(): auto = forked[].altairData.data
|
||||
var store = initialize_light_client_store(state)
|
||||
const lcDataFork = typeof(store).kind
|
||||
|
||||
# Change finality
|
||||
var
|
||||
@ -332,13 +336,13 @@ suite "EF - Altair - Unittests - Light client - Sync protocol" & preset():
|
||||
check: state.finalized_checkpoint.epoch == 3
|
||||
# Ensure that it's same period
|
||||
let
|
||||
store_period = sync_committee_period(store.optimistic_header.slot)
|
||||
store_period = sync_committee_period(store.optimistic_header.beacon.slot)
|
||||
update_period = sync_committee_period(state.slot)
|
||||
check: store_period == update_period
|
||||
|
||||
let
|
||||
attested_block = blocks[^1].altairData
|
||||
attested_header = attested_block.toBeaconBlockHeader
|
||||
attested_header = attested_block.toLightClientHeader(lcDataFork)
|
||||
|
||||
# Sync committee signing the attested_header
|
||||
(sync_aggregate, signature_slot) = get_sync_aggregate(cfg, forked[])
|
||||
@ -347,10 +351,12 @@ suite "EF - Altair - Unittests - Light client - Sync protocol" & preset():
|
||||
next_sync_committee = SyncCommittee()
|
||||
next_sync_committee_branch = default(altair.NextSyncCommitteeBranch)
|
||||
finalized_block = blocks[SLOTS_PER_EPOCH - 1].altairData
|
||||
finalized_header = finalized_block.toBeaconBlockHeader
|
||||
finalized_header = finalized_block.toLightClientHeader(lcDataFork)
|
||||
check:
|
||||
finalized_header.slot == start_slot(state.finalized_checkpoint.epoch)
|
||||
finalized_header.hash_tree_root() == state.finalized_checkpoint.root
|
||||
finalized_header.beacon.slot ==
|
||||
start_slot(state.finalized_checkpoint.epoch)
|
||||
finalized_header.beacon.hash_tree_root() ==
|
||||
state.finalized_checkpoint.root
|
||||
let
|
||||
finality_branch = state.build_proof(altair.FINALIZED_ROOT_INDEX).get
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
# beacon_chain
|
||||
# Copyright (c) 2022 Status Research & Development GmbH
|
||||
# Copyright (c) 2022-2023 Status Research & Development GmbH
|
||||
# Licensed and distributed under either of
|
||||
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
||||
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
||||
@ -110,11 +110,14 @@ proc runTest(path: string) =
|
||||
store, step.update, step.current_slot,
|
||||
cfg, genesis_validators_root)
|
||||
check res.isOk
|
||||
let
|
||||
finalized_root = hash_tree_root(store.finalized_header.beacon)
|
||||
optimistic_root = hash_tree_root(store.optimistic_header.beacon)
|
||||
check:
|
||||
store.finalized_header.slot == step.checks.finalized_slot
|
||||
hash_tree_root(store.finalized_header) == step.checks.finalized_root
|
||||
store.optimistic_header.slot == step.checks.optimistic_slot
|
||||
hash_tree_root(store.optimistic_header) == step.checks.optimistic_root
|
||||
store.finalized_header.beacon.slot == step.checks.finalized_slot
|
||||
finalized_root == step.checks.finalized_root
|
||||
store.optimistic_header.beacon.slot == step.checks.optimistic_slot
|
||||
optimistic_root == step.checks.optimistic_root
|
||||
|
||||
suite "EF - Light client - Sync" & preset():
|
||||
const presetPath = SszTestsDir/const_preset
|
||||
|
@ -158,22 +158,25 @@ suite "Light client" & preset():
|
||||
|
||||
# Sync to latest sync committee period
|
||||
var numIterations = 0
|
||||
while store.finalized_header.slot.sync_committee_period + 1 < headPeriod:
|
||||
template storePeriod: SyncCommitteePeriod =
|
||||
store.finalized_header.beacon.slot.sync_committee_period
|
||||
while storePeriod + 1 < headPeriod:
|
||||
let
|
||||
period =
|
||||
if store.is_next_sync_committee_known:
|
||||
store.finalized_header.slot.sync_committee_period + 1
|
||||
storePeriod + 1
|
||||
else:
|
||||
store.finalized_header.slot.sync_committee_period
|
||||
storePeriod
|
||||
update = dag.getLightClientUpdateForPeriod(period)
|
||||
check update.kind == storeDataFork
|
||||
template forkyUpdate: untyped = update.forky(storeDataFork)
|
||||
let res = process_light_client_update(
|
||||
store, forkyUpdate, currentSlot, cfg, genesis_validators_root)
|
||||
check:
|
||||
forkyUpdate.finalized_header.slot.sync_committee_period == period
|
||||
forkyUpdate.finalized_header.beacon.slot.sync_committee_period == period
|
||||
res.isOk
|
||||
if forkyUpdate.finalized_header.slot > forkyBootstrap.header.slot:
|
||||
if forkyUpdate.finalized_header.beacon.slot >
|
||||
forkyBootstrap.header.beacon.slot:
|
||||
store.finalized_header == forkyUpdate.finalized_header
|
||||
else:
|
||||
store.finalized_header == forkyBootstrap.header
|
||||
@ -187,7 +190,7 @@ suite "Light client" & preset():
|
||||
let res = process_light_client_update(
|
||||
store, forkyFinalityUpdate, currentSlot, cfg, genesis_validators_root)
|
||||
check:
|
||||
forkyFinalityUpdate.attested_header.slot == dag.head.parent.slot
|
||||
forkyFinalityUpdate.attested_header.beacon.slot == dag.head.parent.slot
|
||||
res.isOk
|
||||
store.finalized_header == forkyFinalityUpdate.finalized_header
|
||||
store.optimistic_header == forkyFinalityUpdate.attested_header
|
||||
|
@ -113,7 +113,7 @@ suite "Light client processor" & preset():
|
||||
bootstrap.kind <= storeDataFork
|
||||
let upgradedBootstrap = bootstrap.migratingToDataFork(storeDataFork)
|
||||
template forkyBootstrap: untyped = upgradedBootstrap.forky(storeDataFork)
|
||||
setTimeToSlot(forkyBootstrap.header.slot)
|
||||
setTimeToSlot(forkyBootstrap.header.beacon.slot)
|
||||
res = processor[].storeObject(
|
||||
MsgSource.gossip, getBeaconTime(), bootstrap)
|
||||
check:
|
||||
@ -135,7 +135,8 @@ suite "Light client processor" & preset():
|
||||
check:
|
||||
res.isOk
|
||||
store[].isSome
|
||||
if forkyUpdate.finalized_header.slot > forkyBootstrap.header.slot:
|
||||
if forkyUpdate.finalized_header.beacon.slot >
|
||||
forkyBootstrap.header.beacon.slot:
|
||||
store[].get.finalized_header == forkyUpdate.finalized_header
|
||||
else:
|
||||
store[].get.finalized_header == forkyBootstrap.header
|
||||
@ -274,10 +275,10 @@ suite "Light client processor" & preset():
|
||||
bootstrap.kind <= storeDataFork
|
||||
withForkyBootstrap(bootstrap):
|
||||
when lcDataFork >= LightClientDataFork.Altair:
|
||||
forkyBootstrap.header.slot.inc()
|
||||
forkyBootstrap.header.beacon.slot.inc()
|
||||
let upgradedBootstrap = bootstrap.migratingToDataFork(storeDataFork)
|
||||
template forkyBootstrap: untyped = upgradedBootstrap.forky(storeDataFork)
|
||||
setTimeToSlot(forkyBootstrap.header.slot)
|
||||
setTimeToSlot(forkyBootstrap.header.beacon.slot)
|
||||
res = processor[].storeObject(
|
||||
MsgSource.gossip, getBeaconTime(), bootstrap)
|
||||
check:
|
||||
@ -292,7 +293,7 @@ suite "Light client processor" & preset():
|
||||
bootstrap.kind <= storeDataFork
|
||||
let upgradedBootstrap = bootstrap.migratingToDataFork(storeDataFork)
|
||||
template forkyBootstrap: untyped = upgradedBootstrap.forky(storeDataFork)
|
||||
setTimeToSlot(forkyBootstrap.header.slot)
|
||||
setTimeToSlot(forkyBootstrap.header.beacon.slot)
|
||||
res = processor[].storeObject(
|
||||
MsgSource.gossip, getBeaconTime(), bootstrap)
|
||||
check:
|
||||
|
Loading…
x
Reference in New Issue
Block a user