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:
parent
f810b6714b
commit
f5f3031c5e
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue