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.
This commit is contained in:
Etan Kissling 2022-12-06 17:44:41 +01:00
parent 2a7083d3cd
commit 8bf801ecc6
No known key found for this signature in database
GPG Key ID: B21DA824C5A3D03D
4 changed files with 181 additions and 224 deletions

View File

@ -11,6 +11,7 @@
- [Introduction](#introduction) - [Introduction](#introduction)
- [Helper functions](#helper-functions) - [Helper functions](#helper-functions)
- [`compute_merkle_proof_for_state`](#compute_merkle_proof_for_state) - [`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) - [Deriving light client data](#deriving-light-client-data)
- [`create_light_client_bootstrap`](#create_light_client_bootstrap) - [`create_light_client_bootstrap`](#create_light_client_bootstrap)
- [`create_light_client_update`](#create_light_client_update) - [`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 ## Deriving light client data
Full nodes are expected to derive light client data from historic blocks and states and provide it to other clients. 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) assert hash_tree_root(header) == hash_tree_root(block.message)
return LightClientBootstrap( return LightClientBootstrap(
header=BeaconBlockHeader( header=block_to_light_client_header(block),
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,
),
current_sync_committee=state.current_sync_committee, current_sync_committee=state.current_sync_committee,
current_sync_committee_branch=compute_merkle_proof_for_state(state, CURRENT_SYNC_COMMITTEE_INDEX), 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 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_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 # `next_sync_committee` is only useful if the message is signed by the current sync committee
if update_attested_period == update_signature_period: if update_attested_period == update_signature_period:
next_sync_committee = attested_state.next_sync_committee update.next_sync_committee = attested_state.next_sync_committee
next_sync_committee_branch = compute_merkle_proof_for_state(attested_state, NEXT_SYNC_COMMITTEE_INDEX) update.next_sync_committee_branch = \
else: compute_merkle_proof_for_state(attested_state, NEXT_SYNC_COMMITTEE_INDEX)
next_sync_committee = SyncCommittee()
next_sync_committee_branch = [Bytes32() for _ in range(floorlog2(NEXT_SYNC_COMMITTEE_INDEX))]
# Indicate finality whenever possible # Indicate finality whenever possible
if finalized_block is not None: if finalized_block is not None:
if finalized_block.message.slot != GENESIS_SLOT: if finalized_block.message.slot != GENESIS_SLOT:
finalized_header = BeaconBlockHeader( update.finalized_header = block_to_light_client_header(finalized_block)
slot=finalized_block.message.slot, assert hash_tree_root(update.finalized_header) == attested_state.finalized_checkpoint.root
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
else: else:
assert attested_state.finalized_checkpoint.root == Bytes32() assert attested_state.finalized_checkpoint.root == Bytes32()
finalized_header = BeaconBlockHeader() update.finality_branch = \
finality_branch = compute_merkle_proof_for_state(attested_state, FINALIZED_ROOT_INDEX) 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( update.sync_aggregate = block.message.body.sync_aggregate
attested_header=attested_header, update.signature_slot = block.message.slot
next_sync_committee=next_sync_committee,
next_sync_committee_branch=next_sync_committee_branch, return update
finalized_header=finalized_header,
finality_branch=finality_branch,
sync_aggregate=block.message.body.sync_aggregate,
signature_slot=block.message.slot,
)
``` ```
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. 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.

View File

@ -9,45 +9,23 @@ from eth2spec.test.helpers.attestations import (
) )
from eth2spec.test.helpers.constants import MINIMAL from eth2spec.test.helpers.constants import MINIMAL
from eth2spec.test.helpers.light_client import ( from eth2spec.test.helpers.light_client import (
get_sync_aggregate, create_update,
signed_block_to_header,
) )
from eth2spec.test.helpers.state import ( from eth2spec.test.helpers.state import (
next_slots, 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 attested_state, attested_block, finalized_block = test
num_participants = floor(spec.SYNC_COMMITTEE_SIZE * participation_rate) return create_update(
spec,
attested_header = signed_block_to_header(spec, attested_block) attested_state,
attested_block,
if with_next: finalized_block,
next_sync_committee = attested_state.next_sync_committee with_next,
next_sync_committee_branch = spec.compute_merkle_proof_for_state(attested_state, spec.NEXT_SYNC_COMMITTEE_INDEX) with_finality,
else: participation_rate,
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,
) )
@ -84,76 +62,76 @@ def test_update_ranking(spec, state):
# Create updates (in descending order of quality) # Create updates (in descending order of quality)
updates = [ updates = [
# Updates with sync committee finality # Updates with sync committee finality
create_update(spec, fin, with_next=1, with_finality=1, participation_rate=1.0), create_test_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_test_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_test_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, lat, with_next=1, with_finality=1, participation_rate=0.8),
# Updates without sync committee finality # Updates without sync committee finality
create_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=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=0.8),
# Updates without indication of any finality # Updates without indication of any finality
create_update(spec, att, with_next=1, with_finality=0, participation_rate=1.0), create_test_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_test_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_test_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_test_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_test_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, lat, with_next=1, with_finality=0, participation_rate=0.8),
# Updates with sync committee finality but no `next_sync_committee` # 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_test_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_test_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_test_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_test_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_test_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, lat, with_next=0, with_finality=1, participation_rate=0.8),
# Updates without sync committee finality and also no `next_sync_committee` # 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_test_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=0.8),
# Updates without indication of any finality nor `next_sync_committee` # 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_test_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_test_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_test_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_test_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_test_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_test_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_test_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, lat, with_next=0, with_finality=0, participation_rate=0.8),
# Updates with low sync committee participation # Updates with low sync committee participation
create_update(spec, fin, with_next=1, with_finality=1, participation_rate=0.4), create_test_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_test_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_test_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_test_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_test_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_test_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_test_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_test_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_test_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_test_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_test_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_test_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_test_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, lat, with_next=0, with_finality=0, participation_rate=0.4),
# Updates with very low sync committee participation # Updates with very low sync committee participation
create_update(spec, fin, with_next=1, with_finality=1, participation_rate=0.2), create_test_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_test_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_test_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_test_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_test_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_test_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_test_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_test_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_test_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_test_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_test_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_test_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_test_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, lat, with_next=0, with_finality=0, participation_rate=0.2),
] ]
yield "updates", updates yield "updates", updates

View File

@ -11,43 +11,44 @@ from eth2spec.test.helpers.attestations import (
) )
from eth2spec.test.helpers.constants import MINIMAL from eth2spec.test.helpers.constants import MINIMAL
from eth2spec.test.helpers.light_client import ( from eth2spec.test.helpers.light_client import (
get_sync_aggregate, create_update,
initialize_light_client_store,
signed_block_to_header,
) )
from eth2spec.test.helpers.state import ( from eth2spec.test.helpers.state import (
next_slots, 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 @with_altair_and_later
@spec_state_test_with_matching_config @spec_state_test_with_matching_config
def test_process_light_client_update_not_timeout(spec, state): 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 # 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_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))]
# Ensure that finality checkpoint is genesis # Ensure that finality checkpoint is genesis
assert state.finalized_checkpoint.epoch == 0 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( update = create_update(
attested_header=attested_header, spec,
next_sync_committee=next_sync_committee, attested_state=state,
next_sync_committee_branch=next_sync_committee_branch, attested_block=attested_block,
finalized_header=finalized_header, finalized_block=genesis_block,
finality_branch=finality_branch, with_next=False,
sync_aggregate=sync_aggregate, with_finality=False,
signature_slot=signature_slot, participation_rate=1.0,
) )
pre_store = deepcopy(store) pre_store = deepcopy(store)
@ -64,7 +65,7 @@ def test_process_light_client_update_not_timeout(spec, state):
@spec_state_test_with_matching_config @spec_state_test_with_matching_config
@with_presets([MINIMAL], reason="too slow") @with_presets([MINIMAL], reason="too slow")
def test_process_light_client_update_at_period_boundary(spec, state): 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 # 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) 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 assert store_period == update_period
attested_block = state_transition_with_full_block(spec, state, False, False) 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 update = create_update(
sync_aggregate, signature_slot = get_sync_aggregate(spec, state) spec,
next_sync_committee = spec.SyncCommittee() attested_state=state,
next_sync_committee_branch = [spec.Bytes32() for _ in range(spec.floorlog2(spec.NEXT_SYNC_COMMITTEE_INDEX))] attested_block=attested_block,
finalized_block=genesis_block,
# Finality is unchanged with_next=False,
finalized_header = spec.BeaconBlockHeader() with_finality=False,
finality_branch = [spec.Bytes32() for _ in range(spec.floorlog2(spec.FINALIZED_ROOT_INDEX))] participation_rate=1.0,
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,
) )
pre_store = deepcopy(store) 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 @spec_state_test_with_matching_config
@with_presets([MINIMAL], reason="too slow") @with_presets([MINIMAL], reason="too slow")
def test_process_light_client_update_timeout(spec, state): 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 # Forward to next sync committee period
next_slots(spec, state, spec.UPDATE_TIMEOUT) 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 assert store_period + 1 == update_period
attested_block = state_transition_with_full_block(spec, state, False, False) 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 update = create_update(
sync_aggregate, signature_slot = get_sync_aggregate(spec, state) spec,
attested_state=state,
# Sync committee is updated attested_block=attested_block,
next_sync_committee = state.next_sync_committee finalized_block=genesis_block,
next_sync_committee_branch = spec.compute_merkle_proof_for_state(state, spec.NEXT_SYNC_COMMITTEE_INDEX) with_next=True,
# Finality is unchanged with_finality=False,
finalized_header = spec.BeaconBlockHeader() participation_rate=1.0,
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,
) )
pre_store = deepcopy(store) pre_store = deepcopy(store)
@ -153,7 +135,7 @@ def test_process_light_client_update_timeout(spec, state):
@spec_state_test_with_matching_config @spec_state_test_with_matching_config
@with_presets([MINIMAL], reason="too slow") @with_presets([MINIMAL], reason="too slow")
def test_process_light_client_update_finality_updated(spec, state): def test_process_light_client_update_finality_updated(spec, state):
store = initialize_light_client_store(spec, state) _, store = setup_test(spec, state)
# Change finality # Change finality
blocks = [] blocks = []
@ -169,28 +151,21 @@ def test_process_light_client_update_finality_updated(spec, state):
assert store_period == update_period assert store_period == update_period
attested_block = blocks[-1] attested_block = blocks[-1]
attested_header = signed_block_to_header(spec, attested_block) signature_slot = state.slot + 1
# Sync committee signing the attested_header # Updated finality
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))]
finalized_block = blocks[spec.SLOTS_PER_EPOCH - 1] finalized_block = blocks[spec.SLOTS_PER_EPOCH - 1]
finalized_header = signed_block_to_header(spec, finalized_block) assert finalized_block.message.slot == spec.compute_start_slot_at_epoch(state.finalized_checkpoint.epoch)
assert finalized_header.slot == spec.compute_start_slot_at_epoch(state.finalized_checkpoint.epoch) assert finalized_block.message.hash_tree_root() == state.finalized_checkpoint.root
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( update = create_update(
attested_header=attested_header, spec,
next_sync_committee=next_sync_committee, attested_state=state,
next_sync_committee_branch=next_sync_committee_branch, attested_block=attested_block,
finalized_header=finalized_header, finalized_block=finalized_block,
finality_branch=finality_branch, with_next=False,
sync_aggregate=sync_aggregate, with_finality=True,
signature_slot=signature_slot, participation_rate=1.0,
) )
spec.process_light_client_update(store, update, signature_slot, state.genesis_validators_root) spec.process_light_client_update(store, update, signature_slot, state.genesis_validators_root)

View File

@ -5,28 +5,7 @@ from eth2spec.test.helpers.sync_committee import (
compute_aggregate_sync_committee_signature, compute_aggregate_sync_committee_signature,
compute_committee_indices, compute_committee_indices,
) )
from math import floor
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,
)
def get_sync_aggregate(spec, state, num_participants=None, signature_slot=None): 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, sync_committee_signature=sync_committee_signature,
) )
return sync_aggregate, signature_slot 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