Handle the case when a shard may not have a committee at slot.

Block is invalid if contains ShardBlobHeader lacking committee
Reject Gossip ShardBlobHeader and ShardBlob messages which lacks committee
This commit is contained in:
Anton Nashatyrev 2021-05-27 15:13:13 +03:00
parent 671ed36212
commit 414ef614cb
2 changed files with 19 additions and 3 deletions

View File

@ -455,8 +455,15 @@ def compute_shard_from_committee_index(state: BeaconState, slot: Slot, index: Co
```python ```python
def compute_committee_index_from_shard(state: BeaconState, slot: Slot, shard: Shard) -> CommitteeIndex: def compute_committee_index_from_shard(state: BeaconState, slot: Slot, shard: Shard) -> CommitteeIndex:
"""
Returns either committee index for ``shard`` at ``slot`` or ``None`` if no committee
"""
active_shards = get_active_shard_count(state, compute_epoch_at_slot(slot)) active_shards = get_active_shard_count(state, compute_epoch_at_slot(slot))
return CommitteeIndex((active_shards + shard - get_start_shard(state, slot)) % active_shards) index = (active_shards + shard - get_start_shard(state, slot)) % active_shards
if index >= get_committee_count_per_slot(state, compute_epoch_at_slot(slot)):
return None
else:
return CommitteeIndex(index)
``` ```
@ -559,6 +566,7 @@ def update_pending_votes(state: BeaconState, attestation: Attestation) -> None:
def process_shard_header(state: BeaconState, def process_shard_header(state: BeaconState,
signed_header: SignedShardBlobHeader) -> None: signed_header: SignedShardBlobHeader) -> None:
header = signed_header.message header = signed_header.message
committee_index = compute_committee_index_from_shard(state, header.slot, header.shard)
# Verify the header is not 0, and not from the future. # Verify the header is not 0, and not from the future.
assert Slot(0) < header.slot <= state.slot assert Slot(0) < header.slot <= state.slot
header_epoch = compute_epoch_at_slot(header.slot) header_epoch = compute_epoch_at_slot(header.slot)
@ -566,6 +574,8 @@ def process_shard_header(state: BeaconState,
assert header_epoch in [get_previous_epoch(state), get_current_epoch(state)] assert header_epoch in [get_previous_epoch(state), get_current_epoch(state)]
# Verify that the shard is active # Verify that the shard is active
assert header.shard < get_active_shard_count(state, header_epoch) assert header.shard < get_active_shard_count(state, header_epoch)
# Verify that shard has a committee at slot
assert committee_index is not None
# Verify that the block root matches, # Verify that the block root matches,
# to ensure the header will only be included in this specific Beacon Chain sub-tree. # to ensure the header will only be included in this specific Beacon Chain sub-tree.
assert header.body_summary.beacon_block_root == get_block_root_at_slot(state, header.slot - 1) assert header.body_summary.beacon_block_root == get_block_root_at_slot(state, header.slot - 1)
@ -595,8 +605,7 @@ def process_shard_header(state: BeaconState,
assert header_root not in [pending_header.root for pending_header in pending_headers] assert header_root not in [pending_header.root for pending_header in pending_headers]
# Include it in the pending list # Include it in the pending list
index = compute_committee_index_from_shard(state, header.slot, header.shard) committee_length = len(get_beacon_committee(state, header.slot, committee_index))
committee_length = len(get_beacon_committee(state, header.slot, index))
pending_headers.append(PendingShardHeader( pending_headers.append(PendingShardHeader(
slot=header.slot, slot=header.slot,
shard=header.shard, shard=header.shard,
@ -693,6 +702,9 @@ def process_pending_headers(state: BeaconState) -> None:
# The entire committee (and its balance) # The entire committee (and its balance)
index = compute_committee_index_from_shard(state, slot, shard) index = compute_committee_index_from_shard(state, slot, shard)
if index is None:
# the shard had no committee on this slot
continue
full_committee = get_beacon_committee(state, slot, index) full_committee = get_beacon_committee(state, slot, index)
# The set of voters who voted for each header (and their total balances) # The set of voters who voted for each header (and their total balances)
voting_sets = [ voting_sets = [

View File

@ -117,6 +117,8 @@ The following validations MUST pass before forwarding the `signed_blob` (with in
(a client MAY queue future blobs for processing at the appropriate slot). (a client MAY queue future blobs for processing at the appropriate slot).
- _[IGNORE]_ The `blob` is new enough to be still be processed -- - _[IGNORE]_ The `blob` is new enough to be still be processed --
i.e. validate that `compute_epoch_at_slot(blob.slot) >= get_previous_epoch(state)` i.e. validate that `compute_epoch_at_slot(blob.slot) >= get_previous_epoch(state)`
- _[REJECT]_ The shard should have a committee at slot --
i.e. validate that `compute_committee_index_from_shard(state, blob.slot, blob.shard) is not None`
- _[REJECT]_ The shard blob is for the correct subnet -- - _[REJECT]_ The shard blob is for the correct subnet --
i.e. `compute_subnet_for_shard_blob(state, blob.slot, blob.shard) == subnet_id` i.e. `compute_subnet_for_shard_blob(state, blob.slot, blob.shard) == subnet_id`
- _[IGNORE]_ The blob is the first blob with valid signature received for the `(blob.proposer_index, blob.slot, blob.shard)` combination. - _[IGNORE]_ The blob is the first blob with valid signature received for the `(blob.proposer_index, blob.slot, blob.shard)` combination.
@ -141,6 +143,8 @@ The following validations MUST pass before forwarding the `signed_shard_header`
- _[IGNORE]_ The `header` is new enough to be still be processed -- - _[IGNORE]_ The `header` is new enough to be still be processed --
i.e. validate that `compute_epoch_at_slot(header.slot) >= get_previous_epoch(state)` i.e. validate that `compute_epoch_at_slot(header.slot) >= get_previous_epoch(state)`
- _[IGNORE]_ The header is the first header with valid signature received for the `(header.proposer_index, header.slot, header.shard)` combination. - _[IGNORE]_ The header is the first header with valid signature received for the `(header.proposer_index, header.slot, header.shard)` combination.
- _[REJECT]_ The shard should have a committee at slot --
i.e. validate that `compute_committee_index_from_shard(state, header.slot, header.shard) is not None`
- _[REJECT]_ The proposer signature, `signed_shard_header.signature`, is valid with respect to the `proposer_index` pubkey. - _[REJECT]_ The proposer signature, `signed_shard_header.signature`, is valid with respect to the `proposer_index` pubkey.
- _[REJECT]_ The header is proposed by the expected `proposer_index` for the block's slot - _[REJECT]_ The header is proposed by the expected `proposer_index` for the block's slot
in the context of the current shuffling (defined by `header.body_summary.beacon_block_root`/`slot`). in the context of the current shuffling (defined by `header.body_summary.beacon_block_root`/`slot`).