diff --git a/specs/altair/light-client/full-node.md b/specs/altair/light-client/full-node.md index 53ba4dc82..2dd2ded6c 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))] + update.finality_branch = \ + compute_merkle_proof_for_state(attested_state, 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.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 23ad79584..bde70a940 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.attestations import ( ) 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 bf09cc30e..a72f1980b 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.attestations import ( ) 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) + signature_slot = state.slot + 1 - # 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, + 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) + signature_slot = state.slot + 1 - # 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, + 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) + signature_slot = state.slot + 1 - # Sync committee signing the attested_header - sync_aggregate, signature_slot = get_sync_aggregate(spec, state) - - # 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) + 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 = 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=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 8d632b3a1..39175a352 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 @@ from eth2spec.test.helpers.sync_committee import ( 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