From c10daf1709b973ce2bbc3948d82db0b165d51574 Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Mon, 9 May 2022 14:37:54 +0200 Subject: [PATCH 1/3] Allow `LightClientUpdate` with genesis finality When `state.finalized_checkpoint` references the genesis slot, it points to an empty `root`, instead of the actual genesis block hash. This patch updates the `LightClientUpdate` logic to allow including finality proofs for genesis `finalized_checkpoint.root`, better supporting non-mainnet. When including such a finality proof, the proof is for the empty `root`, but `finalized_header` is kept zeroed out to signify this edge case. --- specs/altair/sync-protocol.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/specs/altair/sync-protocol.md b/specs/altair/sync-protocol.md index a3b10efa2..c03db304f 100644 --- a/specs/altair/sync-protocol.md +++ b/specs/altair/sync-protocol.md @@ -100,7 +100,7 @@ class LightClientStore(object): ```python def is_finality_update(update: LightClientUpdate) -> bool: - return update.finalized_header != BeaconBlockHeader() + return update.finality_branch != [Bytes32() for _ in range(floorlog2(FINALIZED_ROOT_INDEX))] ``` ### `get_subtree_index` @@ -173,10 +173,15 @@ def validate_light_client_update(store: LightClientStore, # Verify that the `finalized_header`, if present, actually is the finalized header saved in the # state of the `attested_header` if not is_finality_update(update): - assert update.finality_branch == [Bytes32() for _ in range(floorlog2(FINALIZED_ROOT_INDEX))] + assert update.finalized_header == BeaconBlockHeader() else: + if update.finalized_header.slot != GENESIS_SLOT: + finalized_root = hash_tree_root(update.finalized_header) + else: + finalized_root = Bytes32() + assert update.finalized_header == BeaconBlockHeader() assert is_valid_merkle_branch( - leaf=hash_tree_root(update.finalized_header), + leaf=finalized_root, branch=update.finality_branch, depth=floorlog2(FINALIZED_ROOT_INDEX), index=get_subtree_index(FINALIZED_ROOT_INDEX), From 99e30328a8a51de55789ca4421da42d4705230d1 Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Mon, 27 Jun 2022 22:26:35 +0200 Subject: [PATCH 2/3] Switch condition order for readability Co-authored-by: Hsiao-Wei Wang --- specs/altair/sync-protocol.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/specs/altair/sync-protocol.md b/specs/altair/sync-protocol.md index c03db304f..23ef1ce66 100644 --- a/specs/altair/sync-protocol.md +++ b/specs/altair/sync-protocol.md @@ -175,11 +175,11 @@ def validate_light_client_update(store: LightClientStore, if not is_finality_update(update): assert update.finalized_header == BeaconBlockHeader() else: - if update.finalized_header.slot != GENESIS_SLOT: - finalized_root = hash_tree_root(update.finalized_header) - else: + if update.finalized_header.slot == GENESIS_SLOT: finalized_root = Bytes32() assert update.finalized_header == BeaconBlockHeader() + else: + finalized_root = hash_tree_root(update.finalized_header) assert is_valid_merkle_branch( leaf=finalized_root, branch=update.finality_branch, From 65cfedef22cd90607ac4a8b63d83545f7820015c Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Mon, 27 Jun 2022 22:36:55 +0200 Subject: [PATCH 3/3] Update finality update documentation --- specs/altair/sync-protocol.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/specs/altair/sync-protocol.md b/specs/altair/sync-protocol.md index 23ef1ce66..5340a2015 100644 --- a/specs/altair/sync-protocol.md +++ b/specs/altair/sync-protocol.md @@ -170,8 +170,9 @@ def validate_light_client_update(store: LightClientStore, signature_period = compute_sync_committee_period(compute_epoch_at_slot(update.signature_slot)) assert signature_period in (finalized_period, finalized_period + 1) - # Verify that the `finalized_header`, if present, actually is the finalized header saved in the - # state of the `attested_header` + # Verify that the `finality_branch`, if present, confirms `finalized_header` + # to match the finalized checkpoint root saved in the state of `attested_header`. + # Note that the genesis finalized checkpoint root is represented as a zero hash. if not is_finality_update(update): assert update.finalized_header == BeaconBlockHeader() else: