From 8bf801ecc64aaa3e1b5ba24b80855bb5e7fa1112 Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Tue, 6 Dec 2022 17:44:41 +0100 Subject: [PATCH 1/2] Add `block_to_light_client_header` helper Introduce `block_to_light_client_header` helper function to enable future forks to override it with additional info (e.g., execution), without having to change the general light client logic. Likewise, update existing light client data creation flow to use `block_to_light_client_header` and default-initialize empty fields. Furthermore, generalize `create_update` helper to streamline test code using `block_to_light_client_header`. Note: In Altair spec, LC header is the same as `BeaconBlockHeader`. however; future forks will extend it with more information. --- specs/altair/light-client/full-node.md | 66 ++++---- .../light_client/test_update_ranking.py | 154 ++++++++---------- .../light_client/test_sync_protocol.py | 143 +++++++--------- .../eth2spec/test/helpers/light_client.py | 52 +++--- 4 files changed, 186 insertions(+), 229 deletions(-) diff --git a/specs/altair/light-client/full-node.md b/specs/altair/light-client/full-node.md index 53ba4dc82c..2dd2ded6cf 100644 --- a/specs/altair/light-client/full-node.md +++ b/specs/altair/light-client/full-node.md @@ -11,6 +11,7 @@ - [Introduction](#introduction) - [Helper functions](#helper-functions) - [`compute_merkle_proof_for_state`](#compute_merkle_proof_for_state) + - [`block_to_light_client_header`](#block_to_light_client_header) - [Deriving light client data](#deriving-light-client-data) - [`create_light_client_bootstrap`](#create_light_client_bootstrap) - [`create_light_client_update`](#create_light_client_update) @@ -34,6 +35,19 @@ def compute_merkle_proof_for_state(state: BeaconState, ... ``` +### `block_to_light_client_header` + +```python +def block_to_light_client_header(block: SignedBeaconBlock) -> BeaconBlockHeader: + return BeaconBlockHeader( + slot=block.message.slot, + proposer_index=block.message.proposer_index, + parent_root=block.message.parent_root, + state_root=block.message.state_root, + body_root=hash_tree_root(block.message.body), + ) +``` + ## Deriving light client data Full nodes are expected to derive light client data from historic blocks and states and provide it to other clients. @@ -55,13 +69,7 @@ def create_light_client_bootstrap(state: BeaconState, assert hash_tree_root(header) == hash_tree_root(block.message) return LightClientBootstrap( - header=BeaconBlockHeader( - slot=state.latest_block_header.slot, - proposer_index=state.latest_block_header.proposer_index, - parent_root=state.latest_block_header.parent_root, - state_root=hash_tree_root(state), - body_root=state.latest_block_header.body_root, - ), + header=block_to_light_client_header(block), current_sync_committee=state.current_sync_committee, current_sync_committee_branch=compute_merkle_proof_for_state(state, CURRENT_SYNC_COMMITTEE_INDEX), ) @@ -103,42 +111,30 @@ def create_light_client_update(state: BeaconState, assert hash_tree_root(attested_header) == hash_tree_root(attested_block.message) == block.message.parent_root update_attested_period = compute_sync_committee_period_at_slot(attested_block.message.slot) + update = LightClientUpdate() + + update.attested_header = block_to_light_client_header(attested_block) + # `next_sync_committee` is only useful if the message is signed by the current sync committee if update_attested_period == update_signature_period: - next_sync_committee = attested_state.next_sync_committee - next_sync_committee_branch = compute_merkle_proof_for_state(attested_state, NEXT_SYNC_COMMITTEE_INDEX) - else: - next_sync_committee = SyncCommittee() - next_sync_committee_branch = [Bytes32() for _ in range(floorlog2(NEXT_SYNC_COMMITTEE_INDEX))] + update.next_sync_committee = attested_state.next_sync_committee + update.next_sync_committee_branch = \ + compute_merkle_proof_for_state(attested_state, NEXT_SYNC_COMMITTEE_INDEX) # Indicate finality whenever possible if finalized_block is not None: if finalized_block.message.slot != GENESIS_SLOT: - finalized_header = BeaconBlockHeader( - slot=finalized_block.message.slot, - proposer_index=finalized_block.message.proposer_index, - parent_root=finalized_block.message.parent_root, - state_root=finalized_block.message.state_root, - body_root=hash_tree_root(finalized_block.message.body), - ) - assert hash_tree_root(finalized_header) == attested_state.finalized_checkpoint.root + update.finalized_header = block_to_light_client_header(finalized_block) + assert hash_tree_root(update.finalized_header) == attested_state.finalized_checkpoint.root else: assert attested_state.finalized_checkpoint.root == Bytes32() - finalized_header = BeaconBlockHeader() - finality_branch = compute_merkle_proof_for_state(attested_state, FINALIZED_ROOT_INDEX) - else: - finalized_header = BeaconBlockHeader() - finality_branch = [Bytes32() for _ in range(floorlog2(FINALIZED_ROOT_INDEX))] - - return LightClientUpdate( - attested_header=attested_header, - next_sync_committee=next_sync_committee, - next_sync_committee_branch=next_sync_committee_branch, - finalized_header=finalized_header, - finality_branch=finality_branch, - sync_aggregate=block.message.body.sync_aggregate, - signature_slot=block.message.slot, - ) + update.finality_branch = \ + compute_merkle_proof_for_state(attested_state, FINALIZED_ROOT_INDEX) + + update.sync_aggregate = block.message.body.sync_aggregate + update.signature_slot = block.message.slot + + return update ``` Full nodes SHOULD provide the best derivable `LightClientUpdate` (according to `is_better_update`) for each sync committee period covering any epochs in range `[max(ALTAIR_FORK_EPOCH, current_epoch - MIN_EPOCHS_FOR_BLOCK_REQUESTS), current_epoch]` where `current_epoch` is defined by the current wall-clock time. Full nodes MAY also provide `LightClientUpdate` for other sync committee periods. diff --git a/tests/core/pyspec/eth2spec/test/altair/light_client/test_update_ranking.py b/tests/core/pyspec/eth2spec/test/altair/light_client/test_update_ranking.py index 23ad795847..bde70a940c 100644 --- a/tests/core/pyspec/eth2spec/test/altair/light_client/test_update_ranking.py +++ b/tests/core/pyspec/eth2spec/test/altair/light_client/test_update_ranking.py @@ -9,45 +9,23 @@ ) from eth2spec.test.helpers.constants import MINIMAL from eth2spec.test.helpers.light_client import ( - get_sync_aggregate, - signed_block_to_header, + create_update, ) from eth2spec.test.helpers.state import ( next_slots, ) -from math import floor -def create_update(spec, test, with_next, with_finality, participation_rate): +def create_test_update(spec, test, with_next, with_finality, participation_rate): attested_state, attested_block, finalized_block = test - num_participants = floor(spec.SYNC_COMMITTEE_SIZE * participation_rate) - - attested_header = signed_block_to_header(spec, attested_block) - - if with_next: - next_sync_committee = attested_state.next_sync_committee - next_sync_committee_branch = spec.compute_merkle_proof_for_state(attested_state, spec.NEXT_SYNC_COMMITTEE_INDEX) - else: - next_sync_committee = spec.SyncCommittee() - next_sync_committee_branch = [spec.Bytes32() for _ in range(spec.floorlog2(spec.NEXT_SYNC_COMMITTEE_INDEX))] - - if with_finality: - finalized_header = signed_block_to_header(spec, finalized_block) - finality_branch = spec.compute_merkle_proof_for_state(attested_state, spec.FINALIZED_ROOT_INDEX) - else: - finalized_header = spec.BeaconBlockHeader() - finality_branch = [spec.Bytes32() for _ in range(spec.floorlog2(spec.FINALIZED_ROOT_INDEX))] - - sync_aggregate, signature_slot = get_sync_aggregate(spec, attested_state, num_participants) - - return spec.LightClientUpdate( - attested_header=attested_header, - next_sync_committee=next_sync_committee, - next_sync_committee_branch=next_sync_committee_branch, - finalized_header=finalized_header, - finality_branch=finality_branch, - sync_aggregate=sync_aggregate, - signature_slot=signature_slot, + return create_update( + spec, + attested_state, + attested_block, + finalized_block, + with_next, + with_finality, + participation_rate, ) @@ -84,76 +62,76 @@ def test_update_ranking(spec, state): # Create updates (in descending order of quality) updates = [ # Updates with sync committee finality - create_update(spec, fin, with_next=1, with_finality=1, participation_rate=1.0), - create_update(spec, lat, with_next=1, with_finality=1, participation_rate=1.0), - create_update(spec, fin, with_next=1, with_finality=1, participation_rate=0.8), - create_update(spec, lat, with_next=1, with_finality=1, participation_rate=0.8), + create_test_update(spec, fin, with_next=1, with_finality=1, participation_rate=1.0), + create_test_update(spec, lat, with_next=1, with_finality=1, participation_rate=1.0), + create_test_update(spec, fin, with_next=1, with_finality=1, participation_rate=0.8), + create_test_update(spec, lat, with_next=1, with_finality=1, participation_rate=0.8), # Updates without sync committee finality - create_update(spec, att, with_next=1, with_finality=1, participation_rate=1.0), - create_update(spec, att, with_next=1, with_finality=1, participation_rate=0.8), + create_test_update(spec, att, with_next=1, with_finality=1, participation_rate=1.0), + create_test_update(spec, att, with_next=1, with_finality=1, participation_rate=0.8), # Updates without indication of any finality - create_update(spec, att, with_next=1, with_finality=0, participation_rate=1.0), - create_update(spec, fin, with_next=1, with_finality=0, participation_rate=1.0), - create_update(spec, lat, with_next=1, with_finality=0, participation_rate=1.0), - create_update(spec, att, with_next=1, with_finality=0, participation_rate=0.8), - create_update(spec, fin, with_next=1, with_finality=0, participation_rate=0.8), - create_update(spec, lat, with_next=1, with_finality=0, participation_rate=0.8), + create_test_update(spec, att, with_next=1, with_finality=0, participation_rate=1.0), + create_test_update(spec, fin, with_next=1, with_finality=0, participation_rate=1.0), + create_test_update(spec, lat, with_next=1, with_finality=0, participation_rate=1.0), + create_test_update(spec, att, with_next=1, with_finality=0, participation_rate=0.8), + create_test_update(spec, fin, with_next=1, with_finality=0, participation_rate=0.8), + create_test_update(spec, lat, with_next=1, with_finality=0, participation_rate=0.8), # Updates with sync committee finality but no `next_sync_committee` - create_update(spec, sig, with_next=0, with_finality=1, participation_rate=1.0), - create_update(spec, fin, with_next=0, with_finality=1, participation_rate=1.0), - create_update(spec, lat, with_next=0, with_finality=1, participation_rate=1.0), - create_update(spec, sig, with_next=0, with_finality=1, participation_rate=0.8), - create_update(spec, fin, with_next=0, with_finality=1, participation_rate=0.8), - create_update(spec, lat, with_next=0, with_finality=1, participation_rate=0.8), + create_test_update(spec, sig, with_next=0, with_finality=1, participation_rate=1.0), + create_test_update(spec, fin, with_next=0, with_finality=1, participation_rate=1.0), + create_test_update(spec, lat, with_next=0, with_finality=1, participation_rate=1.0), + create_test_update(spec, sig, with_next=0, with_finality=1, participation_rate=0.8), + create_test_update(spec, fin, with_next=0, with_finality=1, participation_rate=0.8), + create_test_update(spec, lat, with_next=0, with_finality=1, participation_rate=0.8), # Updates without sync committee finality and also no `next_sync_committee` - create_update(spec, att, with_next=0, with_finality=1, participation_rate=1.0), - create_update(spec, att, with_next=0, with_finality=1, participation_rate=0.8), + create_test_update(spec, att, with_next=0, with_finality=1, participation_rate=1.0), + create_test_update(spec, att, with_next=0, with_finality=1, participation_rate=0.8), # Updates without indication of any finality nor `next_sync_committee` - create_update(spec, sig, with_next=0, with_finality=0, participation_rate=1.0), - create_update(spec, att, with_next=0, with_finality=0, participation_rate=1.0), - create_update(spec, fin, with_next=0, with_finality=0, participation_rate=1.0), - create_update(spec, lat, with_next=0, with_finality=0, participation_rate=1.0), - create_update(spec, sig, with_next=0, with_finality=0, participation_rate=0.8), - create_update(spec, att, with_next=0, with_finality=0, participation_rate=0.8), - create_update(spec, fin, with_next=0, with_finality=0, participation_rate=0.8), - create_update(spec, lat, with_next=0, with_finality=0, participation_rate=0.8), + create_test_update(spec, sig, with_next=0, with_finality=0, participation_rate=1.0), + create_test_update(spec, att, with_next=0, with_finality=0, participation_rate=1.0), + create_test_update(spec, fin, with_next=0, with_finality=0, participation_rate=1.0), + create_test_update(spec, lat, with_next=0, with_finality=0, participation_rate=1.0), + create_test_update(spec, sig, with_next=0, with_finality=0, participation_rate=0.8), + create_test_update(spec, att, with_next=0, with_finality=0, participation_rate=0.8), + create_test_update(spec, fin, with_next=0, with_finality=0, participation_rate=0.8), + create_test_update(spec, lat, with_next=0, with_finality=0, participation_rate=0.8), # Updates with low sync committee participation - create_update(spec, fin, with_next=1, with_finality=1, participation_rate=0.4), - create_update(spec, lat, with_next=1, with_finality=1, participation_rate=0.4), - create_update(spec, att, with_next=1, with_finality=1, participation_rate=0.4), - create_update(spec, att, with_next=1, with_finality=0, participation_rate=0.4), - create_update(spec, fin, with_next=1, with_finality=0, participation_rate=0.4), - create_update(spec, lat, with_next=1, with_finality=0, participation_rate=0.4), - create_update(spec, sig, with_next=0, with_finality=1, participation_rate=0.4), - create_update(spec, fin, with_next=0, with_finality=1, participation_rate=0.4), - create_update(spec, lat, with_next=0, with_finality=1, participation_rate=0.4), - create_update(spec, att, with_next=0, with_finality=1, participation_rate=0.4), - create_update(spec, sig, with_next=0, with_finality=0, participation_rate=0.4), - create_update(spec, att, with_next=0, with_finality=0, participation_rate=0.4), - create_update(spec, fin, with_next=0, with_finality=0, participation_rate=0.4), - create_update(spec, lat, with_next=0, with_finality=0, participation_rate=0.4), + create_test_update(spec, fin, with_next=1, with_finality=1, participation_rate=0.4), + create_test_update(spec, lat, with_next=1, with_finality=1, participation_rate=0.4), + create_test_update(spec, att, with_next=1, with_finality=1, participation_rate=0.4), + create_test_update(spec, att, with_next=1, with_finality=0, participation_rate=0.4), + create_test_update(spec, fin, with_next=1, with_finality=0, participation_rate=0.4), + create_test_update(spec, lat, with_next=1, with_finality=0, participation_rate=0.4), + create_test_update(spec, sig, with_next=0, with_finality=1, participation_rate=0.4), + create_test_update(spec, fin, with_next=0, with_finality=1, participation_rate=0.4), + create_test_update(spec, lat, with_next=0, with_finality=1, participation_rate=0.4), + create_test_update(spec, att, with_next=0, with_finality=1, participation_rate=0.4), + create_test_update(spec, sig, with_next=0, with_finality=0, participation_rate=0.4), + create_test_update(spec, att, with_next=0, with_finality=0, participation_rate=0.4), + create_test_update(spec, fin, with_next=0, with_finality=0, participation_rate=0.4), + create_test_update(spec, lat, with_next=0, with_finality=0, participation_rate=0.4), # Updates with very low sync committee participation - create_update(spec, fin, with_next=1, with_finality=1, participation_rate=0.2), - create_update(spec, lat, with_next=1, with_finality=1, participation_rate=0.2), - create_update(spec, att, with_next=1, with_finality=1, participation_rate=0.2), - create_update(spec, att, with_next=1, with_finality=0, participation_rate=0.2), - create_update(spec, fin, with_next=1, with_finality=0, participation_rate=0.2), - create_update(spec, lat, with_next=1, with_finality=0, participation_rate=0.2), - create_update(spec, sig, with_next=0, with_finality=1, participation_rate=0.2), - create_update(spec, fin, with_next=0, with_finality=1, participation_rate=0.2), - create_update(spec, lat, with_next=0, with_finality=1, participation_rate=0.2), - create_update(spec, att, with_next=0, with_finality=1, participation_rate=0.2), - create_update(spec, sig, with_next=0, with_finality=0, participation_rate=0.2), - create_update(spec, att, with_next=0, with_finality=0, participation_rate=0.2), - create_update(spec, fin, with_next=0, with_finality=0, participation_rate=0.2), - create_update(spec, lat, with_next=0, with_finality=0, participation_rate=0.2), + create_test_update(spec, fin, with_next=1, with_finality=1, participation_rate=0.2), + create_test_update(spec, lat, with_next=1, with_finality=1, participation_rate=0.2), + create_test_update(spec, att, with_next=1, with_finality=1, participation_rate=0.2), + create_test_update(spec, att, with_next=1, with_finality=0, participation_rate=0.2), + create_test_update(spec, fin, with_next=1, with_finality=0, participation_rate=0.2), + create_test_update(spec, lat, with_next=1, with_finality=0, participation_rate=0.2), + create_test_update(spec, sig, with_next=0, with_finality=1, participation_rate=0.2), + create_test_update(spec, fin, with_next=0, with_finality=1, participation_rate=0.2), + create_test_update(spec, lat, with_next=0, with_finality=1, participation_rate=0.2), + create_test_update(spec, att, with_next=0, with_finality=1, participation_rate=0.2), + create_test_update(spec, sig, with_next=0, with_finality=0, participation_rate=0.2), + create_test_update(spec, att, with_next=0, with_finality=0, participation_rate=0.2), + create_test_update(spec, fin, with_next=0, with_finality=0, participation_rate=0.2), + create_test_update(spec, lat, with_next=0, with_finality=0, participation_rate=0.2), ] yield "updates", updates diff --git a/tests/core/pyspec/eth2spec/test/altair/unittests/light_client/test_sync_protocol.py b/tests/core/pyspec/eth2spec/test/altair/unittests/light_client/test_sync_protocol.py index bf09cc30ec..a72f1980b1 100644 --- a/tests/core/pyspec/eth2spec/test/altair/unittests/light_client/test_sync_protocol.py +++ b/tests/core/pyspec/eth2spec/test/altair/unittests/light_client/test_sync_protocol.py @@ -11,43 +11,44 @@ ) from eth2spec.test.helpers.constants import MINIMAL from eth2spec.test.helpers.light_client import ( - get_sync_aggregate, - initialize_light_client_store, - signed_block_to_header, + create_update, ) from eth2spec.test.helpers.state import ( next_slots, ) +def setup_test(spec, state): + trusted_block = spec.SignedBeaconBlock() + trusted_block.message.state_root = state.hash_tree_root() + trusted_block_root = trusted_block.message.hash_tree_root() + bootstrap = spec.create_light_client_bootstrap(state, trusted_block) + store = spec.initialize_light_client_store(trusted_block_root, bootstrap) + store.next_sync_committee = state.next_sync_committee + + return (trusted_block, store) + + @with_altair_and_later @spec_state_test_with_matching_config def test_process_light_client_update_not_timeout(spec, state): - store = initialize_light_client_store(spec, state) + genesis_block, store = setup_test(spec, state) # Block at slot 1 doesn't increase sync committee period, so it won't force update store.finalized_header attested_block = state_transition_with_full_block(spec, state, False, False) - attested_header = signed_block_to_header(spec, attested_block) - - # Sync committee signing the attested_header - sync_aggregate, signature_slot = get_sync_aggregate(spec, state) - next_sync_committee = spec.SyncCommittee() - next_sync_committee_branch = [spec.Bytes32() for _ in range(spec.floorlog2(spec.NEXT_SYNC_COMMITTEE_INDEX))] + signature_slot = state.slot + 1 # Ensure that finality checkpoint is genesis assert state.finalized_checkpoint.epoch == 0 - # Finality is unchanged - finalized_header = spec.BeaconBlockHeader() - finality_branch = [spec.Bytes32() for _ in range(spec.floorlog2(spec.FINALIZED_ROOT_INDEX))] - - update = spec.LightClientUpdate( - attested_header=attested_header, - next_sync_committee=next_sync_committee, - next_sync_committee_branch=next_sync_committee_branch, - finalized_header=finalized_header, - finality_branch=finality_branch, - sync_aggregate=sync_aggregate, - signature_slot=signature_slot, + + update = create_update( + spec, + attested_state=state, + attested_block=attested_block, + finalized_block=genesis_block, + with_next=False, + with_finality=False, + participation_rate=1.0, ) pre_store = deepcopy(store) @@ -64,7 +65,7 @@ def test_process_light_client_update_not_timeout(spec, state): @spec_state_test_with_matching_config @with_presets([MINIMAL], reason="too slow") def test_process_light_client_update_at_period_boundary(spec, state): - store = initialize_light_client_store(spec, state) + genesis_block, store = setup_test(spec, state) # Forward to slot before next sync committee period so that next block is final one in period next_slots(spec, state, spec.UPDATE_TIMEOUT - 2) @@ -73,25 +74,16 @@ def test_process_light_client_update_at_period_boundary(spec, state): assert store_period == update_period attested_block = state_transition_with_full_block(spec, state, False, False) - attested_header = signed_block_to_header(spec, attested_block) - - # Sync committee signing the attested_header - sync_aggregate, signature_slot = get_sync_aggregate(spec, state) - next_sync_committee = spec.SyncCommittee() - next_sync_committee_branch = [spec.Bytes32() for _ in range(spec.floorlog2(spec.NEXT_SYNC_COMMITTEE_INDEX))] - - # Finality is unchanged - finalized_header = spec.BeaconBlockHeader() - finality_branch = [spec.Bytes32() for _ in range(spec.floorlog2(spec.FINALIZED_ROOT_INDEX))] - - update = spec.LightClientUpdate( - attested_header=attested_header, - next_sync_committee=next_sync_committee, - next_sync_committee_branch=next_sync_committee_branch, - finalized_header=finalized_header, - finality_branch=finality_branch, - sync_aggregate=sync_aggregate, - signature_slot=signature_slot, + signature_slot = state.slot + 1 + + update = create_update( + spec, + attested_state=state, + attested_block=attested_block, + finalized_block=genesis_block, + with_next=False, + with_finality=False, + participation_rate=1.0, ) pre_store = deepcopy(store) @@ -108,7 +100,7 @@ def test_process_light_client_update_at_period_boundary(spec, state): @spec_state_test_with_matching_config @with_presets([MINIMAL], reason="too slow") def test_process_light_client_update_timeout(spec, state): - store = initialize_light_client_store(spec, state) + genesis_block, store = setup_test(spec, state) # Forward to next sync committee period next_slots(spec, state, spec.UPDATE_TIMEOUT) @@ -117,26 +109,16 @@ def test_process_light_client_update_timeout(spec, state): assert store_period + 1 == update_period attested_block = state_transition_with_full_block(spec, state, False, False) - attested_header = signed_block_to_header(spec, attested_block) - - # Sync committee signing the attested_header - sync_aggregate, signature_slot = get_sync_aggregate(spec, state) - - # Sync committee is updated - next_sync_committee = state.next_sync_committee - next_sync_committee_branch = spec.compute_merkle_proof_for_state(state, spec.NEXT_SYNC_COMMITTEE_INDEX) - # Finality is unchanged - finalized_header = spec.BeaconBlockHeader() - finality_branch = [spec.Bytes32() for _ in range(spec.floorlog2(spec.FINALIZED_ROOT_INDEX))] - - update = spec.LightClientUpdate( - attested_header=attested_header, - next_sync_committee=next_sync_committee, - next_sync_committee_branch=next_sync_committee_branch, - finalized_header=finalized_header, - finality_branch=finality_branch, - sync_aggregate=sync_aggregate, - signature_slot=signature_slot, + signature_slot = state.slot + 1 + + update = create_update( + spec, + attested_state=state, + attested_block=attested_block, + finalized_block=genesis_block, + with_next=True, + with_finality=False, + participation_rate=1.0, ) pre_store = deepcopy(store) @@ -153,7 +135,7 @@ def test_process_light_client_update_timeout(spec, state): @spec_state_test_with_matching_config @with_presets([MINIMAL], reason="too slow") def test_process_light_client_update_finality_updated(spec, state): - store = initialize_light_client_store(spec, state) + _, store = setup_test(spec, state) # Change finality blocks = [] @@ -169,28 +151,21 @@ def test_process_light_client_update_finality_updated(spec, state): assert store_period == update_period attested_block = blocks[-1] - attested_header = signed_block_to_header(spec, attested_block) - - # Sync committee signing the attested_header - sync_aggregate, signature_slot = get_sync_aggregate(spec, state) + signature_slot = state.slot + 1 - # Updated sync_committee and finality - next_sync_committee = spec.SyncCommittee() - next_sync_committee_branch = [spec.Bytes32() for _ in range(spec.floorlog2(spec.NEXT_SYNC_COMMITTEE_INDEX))] + # Updated finality finalized_block = blocks[spec.SLOTS_PER_EPOCH - 1] - finalized_header = signed_block_to_header(spec, finalized_block) - assert finalized_header.slot == spec.compute_start_slot_at_epoch(state.finalized_checkpoint.epoch) - assert finalized_header.hash_tree_root() == state.finalized_checkpoint.root - finality_branch = spec.compute_merkle_proof_for_state(state, spec.FINALIZED_ROOT_INDEX) - - update = spec.LightClientUpdate( - attested_header=attested_header, - next_sync_committee=next_sync_committee, - next_sync_committee_branch=next_sync_committee_branch, - finalized_header=finalized_header, - finality_branch=finality_branch, - sync_aggregate=sync_aggregate, - signature_slot=signature_slot, + assert finalized_block.message.slot == spec.compute_start_slot_at_epoch(state.finalized_checkpoint.epoch) + assert finalized_block.message.hash_tree_root() == state.finalized_checkpoint.root + + update = create_update( + spec, + attested_state=state, + attested_block=attested_block, + finalized_block=finalized_block, + with_next=False, + with_finality=True, + participation_rate=1.0, ) spec.process_light_client_update(store, update, signature_slot, state.genesis_validators_root) diff --git a/tests/core/pyspec/eth2spec/test/helpers/light_client.py b/tests/core/pyspec/eth2spec/test/helpers/light_client.py index 8d632b3a1f..39175a352e 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/light_client.py +++ b/tests/core/pyspec/eth2spec/test/helpers/light_client.py @@ -5,28 +5,7 @@ compute_aggregate_sync_committee_signature, compute_committee_indices, ) - - -def signed_block_to_header(spec, block): - return spec.BeaconBlockHeader( - slot=block.message.slot, - proposer_index=block.message.proposer_index, - parent_root=block.message.parent_root, - state_root=block.message.state_root, - body_root=block.message.body.hash_tree_root(), - ) - - -def initialize_light_client_store(spec, state): - return spec.LightClientStore( - finalized_header=spec.BeaconBlockHeader(), - current_sync_committee=state.current_sync_committee, - next_sync_committee=state.next_sync_committee, - best_valid_update=None, - optimistic_header=spec.BeaconBlockHeader(), - previous_max_active_participants=0, - current_max_active_participants=0, - ) +from math import floor def get_sync_aggregate(spec, state, num_participants=None, signature_slot=None): @@ -60,3 +39,32 @@ def get_sync_aggregate(spec, state, num_participants=None, signature_slot=None): sync_committee_signature=sync_committee_signature, ) return sync_aggregate, signature_slot + + +def create_update(spec, + attested_state, + attested_block, + finalized_block, + with_next, + with_finality, + participation_rate): + num_participants = floor(spec.SYNC_COMMITTEE_SIZE * participation_rate) + + update = spec.LightClientUpdate() + + update.attested_header = spec.block_to_light_client_header(attested_block) + + if with_next: + update.next_sync_committee = attested_state.next_sync_committee + update.next_sync_committee_branch = \ + spec.compute_merkle_proof_for_state(attested_state, spec.NEXT_SYNC_COMMITTEE_INDEX) + + if with_finality: + update.finalized_header = spec.block_to_light_client_header(finalized_block) + update.finality_branch = \ + spec.compute_merkle_proof_for_state(attested_state, spec.FINALIZED_ROOT_INDEX) + + update.sync_aggregate, update.signature_slot = \ + get_sync_aggregate(spec, attested_state, num_participants) + + return update From ef2a8b319d963bbe00976a366ac7ded2ea3fcb12 Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Tue, 13 Dec 2022 12:30:14 +0100 Subject: [PATCH 2/2] Avoid line continuation syntax --- specs/altair/light-client/full-node.md | 8 ++++---- .../altair/light_client/test_single_merkle_proof.py | 12 ++++++------ .../pyspec/eth2spec/test/helpers/light_client.py | 12 ++++++------ 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/specs/altair/light-client/full-node.md b/specs/altair/light-client/full-node.md index 2dd2ded6cf..7f0b7bc39c 100644 --- a/specs/altair/light-client/full-node.md +++ b/specs/altair/light-client/full-node.md @@ -118,8 +118,8 @@ def create_light_client_update(state: BeaconState, # `next_sync_committee` is only useful if the message is signed by the current sync committee if update_attested_period == update_signature_period: update.next_sync_committee = attested_state.next_sync_committee - update.next_sync_committee_branch = \ - compute_merkle_proof_for_state(attested_state, NEXT_SYNC_COMMITTEE_INDEX) + update.next_sync_committee_branch = compute_merkle_proof_for_state( + attested_state, NEXT_SYNC_COMMITTEE_INDEX) # Indicate finality whenever possible if finalized_block is not None: @@ -128,8 +128,8 @@ def create_light_client_update(state: BeaconState, assert hash_tree_root(update.finalized_header) == attested_state.finalized_checkpoint.root else: assert attested_state.finalized_checkpoint.root == Bytes32() - update.finality_branch = \ - compute_merkle_proof_for_state(attested_state, FINALIZED_ROOT_INDEX) + update.finality_branch = compute_merkle_proof_for_state( + attested_state, FINALIZED_ROOT_INDEX) update.sync_aggregate = block.message.body.sync_aggregate update.signature_slot = block.message.slot diff --git a/tests/core/pyspec/eth2spec/test/altair/light_client/test_single_merkle_proof.py b/tests/core/pyspec/eth2spec/test/altair/light_client/test_single_merkle_proof.py index 465fa629f2..5d802bbb3e 100644 --- a/tests/core/pyspec/eth2spec/test/altair/light_client/test_single_merkle_proof.py +++ b/tests/core/pyspec/eth2spec/test/altair/light_client/test_single_merkle_proof.py @@ -10,8 +10,8 @@ @spec_state_test def test_current_sync_committee_merkle_proof(spec, state): yield "object", state - current_sync_committee_branch = \ - spec.compute_merkle_proof_for_state(state, spec.CURRENT_SYNC_COMMITTEE_INDEX) + current_sync_committee_branch = spec.compute_merkle_proof_for_state( + state, spec.CURRENT_SYNC_COMMITTEE_INDEX) yield "proof", { "leaf": "0x" + state.current_sync_committee.hash_tree_root().hex(), "leaf_index": spec.CURRENT_SYNC_COMMITTEE_INDEX, @@ -31,8 +31,8 @@ def test_current_sync_committee_merkle_proof(spec, state): @spec_state_test def test_next_sync_committee_merkle_proof(spec, state): yield "object", state - next_sync_committee_branch = \ - spec.compute_merkle_proof_for_state(state, spec.NEXT_SYNC_COMMITTEE_INDEX) + next_sync_committee_branch = spec.compute_merkle_proof_for_state( + state, spec.NEXT_SYNC_COMMITTEE_INDEX) yield "proof", { "leaf": "0x" + state.next_sync_committee.hash_tree_root().hex(), "leaf_index": spec.NEXT_SYNC_COMMITTEE_INDEX, @@ -52,8 +52,8 @@ def test_next_sync_committee_merkle_proof(spec, state): @spec_state_test def test_finality_root_merkle_proof(spec, state): yield "object", state - finality_branch = \ - spec.compute_merkle_proof_for_state(state, spec.FINALIZED_ROOT_INDEX) + finality_branch = spec.compute_merkle_proof_for_state( + state, spec.FINALIZED_ROOT_INDEX) yield "proof", { "leaf": "0x" + state.finalized_checkpoint.root.hex(), "leaf_index": spec.FINALIZED_ROOT_INDEX, diff --git a/tests/core/pyspec/eth2spec/test/helpers/light_client.py b/tests/core/pyspec/eth2spec/test/helpers/light_client.py index 39175a352e..215d174fc8 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/light_client.py +++ b/tests/core/pyspec/eth2spec/test/helpers/light_client.py @@ -56,15 +56,15 @@ def create_update(spec, if with_next: update.next_sync_committee = attested_state.next_sync_committee - update.next_sync_committee_branch = \ - spec.compute_merkle_proof_for_state(attested_state, spec.NEXT_SYNC_COMMITTEE_INDEX) + update.next_sync_committee_branch = spec.compute_merkle_proof_for_state( + attested_state, spec.NEXT_SYNC_COMMITTEE_INDEX) if with_finality: update.finalized_header = spec.block_to_light_client_header(finalized_block) - update.finality_branch = \ - spec.compute_merkle_proof_for_state(attested_state, spec.FINALIZED_ROOT_INDEX) + update.finality_branch = spec.compute_merkle_proof_for_state( + attested_state, spec.FINALIZED_ROOT_INDEX) - update.sync_aggregate, update.signature_slot = \ - get_sync_aggregate(spec, attested_state, num_participants) + update.sync_aggregate, update.signature_slot = get_sync_aggregate( + spec, attested_state, num_participants) return update