Merge pull request #3149 from etan-status/lc-toheader

Add `block_to_light_client_header` helper
This commit is contained in:
Hsiao-Wei Wang 2023-01-05 12:12:36 +08:00 committed by GitHub
commit 0777a52f55
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 187 additions and 230 deletions

View File

@ -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.

View File

@ -10,8 +10,8 @@ from eth2spec.test.context import (
@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,

View File

@ -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

View File

@ -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)

View File

@ -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