Allow passing redundant `next_sync_committee`

The producer of `LightClientUpdate` structures usually does not know how
far the `LightClientStore` on the client side has advanced. Updates are
currently rejected when including a redundant `next_sync_committee` not
advancing the `LightClientStore`. Behaviour is changed to allow this.
This commit is contained in:
Etan Kissling 2022-04-27 16:07:49 +02:00
parent f810b6714b
commit f5f3031c5e
No known key found for this signature in database
GPG Key ID: B21DA824C5A3D03D
2 changed files with 23 additions and 7 deletions

View File

@ -16,6 +16,7 @@
- [`LightClientUpdate`](#lightclientupdate)
- [`LightClientStore`](#lightclientstore)
- [Helper functions](#helper-functions)
- [`is_sync_committee_update`](#is_sync_committee_update)
- [`is_finality_update`](#is_finality_update)
- [`get_subtree_index`](#get_subtree_index)
- [`get_active_header`](#get_active_header)
@ -96,6 +97,13 @@ class LightClientStore(object):
## Helper functions
### `is_sync_committee_update`
```python
def is_sync_committee_update(update: LightClientUpdate) -> bool:
return update.next_sync_committee_branch != [Bytes32() for _ in range(floorlog2(NEXT_SYNC_COMMITTEE_INDEX))]
```
### `is_finality_update`
```python
@ -189,10 +197,14 @@ def validate_light_client_update(store: LightClientStore,
root=update.attested_header.state_root,
)
# Verify update next sync committee if the update period incremented
if update_period == finalized_period:
assert update.next_sync_committee_branch == [Bytes32() for _ in range(floorlog2(NEXT_SYNC_COMMITTEE_INDEX))]
# Verify that the `next_sync_committee`, if present, actually is the next sync committee saved in the
# state of the `active_header`
if not is_sync_committee_update(update):
assert update_period == finalized_period
assert update.next_sync_committee == SyncCommittee()
else:
if update_period == finalized_period:
assert update.next_sync_committee == store.next_sync_committee
assert is_valid_merkle_branch(
leaf=hash_tree_root(update.next_sync_committee),
branch=update.next_sync_committee_branch,

View File

@ -42,6 +42,7 @@ def test_process_light_client_update_not_timeout(spec, state):
# Sync committee signing the block_header
sync_aggregate, signature_slot = get_sync_aggregate(spec, state, block_header)
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
@ -52,7 +53,7 @@ def test_process_light_client_update_not_timeout(spec, state):
update = spec.LightClientUpdate(
attested_header=block_header,
next_sync_committee=state.next_sync_committee,
next_sync_committee=next_sync_committee,
next_sync_committee_branch=next_sync_committee_branch,
finalized_header=finality_header,
finality_branch=finality_branch,
@ -94,6 +95,7 @@ def test_process_light_client_update_at_period_boundary(spec, state):
# Sync committee signing the block_header
sync_aggregate, signature_slot = get_sync_aggregate(spec, state, block_header)
next_sync_committee = spec.SyncCommittee()
next_sync_committee_branch = [spec.Bytes32() for _ in range(spec.floorlog2(spec.NEXT_SYNC_COMMITTEE_INDEX))]
# Finality is unchanged
@ -102,7 +104,7 @@ def test_process_light_client_update_at_period_boundary(spec, state):
update = spec.LightClientUpdate(
attested_header=block_header,
next_sync_committee=state.next_sync_committee,
next_sync_committee=next_sync_committee,
next_sync_committee_branch=next_sync_committee_branch,
finalized_header=finality_header,
finality_branch=finality_branch,
@ -146,6 +148,7 @@ def test_process_light_client_update_timeout(spec, state):
sync_aggregate, signature_slot = get_sync_aggregate(spec, state, block_header)
# Sync committee is updated
next_sync_committee = state.next_sync_committee
next_sync_committee_branch = build_proof(state.get_backing(), spec.NEXT_SYNC_COMMITTEE_INDEX)
# Finality is unchanged
finality_header = spec.BeaconBlockHeader()
@ -153,7 +156,7 @@ def test_process_light_client_update_timeout(spec, state):
update = spec.LightClientUpdate(
attested_header=block_header,
next_sync_committee=state.next_sync_committee,
next_sync_committee=next_sync_committee,
next_sync_committee_branch=next_sync_committee_branch,
finalized_header=finality_header,
finality_branch=finality_branch,
@ -191,6 +194,7 @@ def test_process_light_client_update_finality_updated(spec, state):
assert snapshot_period == update_period
# 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_header = blocks[spec.SLOTS_PER_EPOCH - 1].message
assert finalized_block_header.slot == spec.compute_start_slot_at_epoch(state.finalized_checkpoint.epoch)
@ -212,7 +216,7 @@ def test_process_light_client_update_finality_updated(spec, state):
update = spec.LightClientUpdate(
attested_header=block_header,
next_sync_committee=state.next_sync_committee,
next_sync_committee=next_sync_committee,
next_sync_committee_branch=next_sync_committee_branch,
finalized_header=finalized_block_header,
finality_branch=finality_branch,