diff --git a/specs/sharding/beacon-chain.md b/specs/sharding/beacon-chain.md index 5522e044d..2a0695c49 100644 --- a/specs/sharding/beacon-chain.md +++ b/specs/sharding/beacon-chain.md @@ -455,8 +455,15 @@ def compute_shard_from_committee_index(state: BeaconState, slot: Slot, index: Co ```python 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)) - 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, signed_header: SignedShardBlobHeader) -> None: 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. assert Slot(0) < header.slot <= state.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)] # Verify that the shard is active 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, # 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) @@ -595,8 +605,7 @@ def process_shard_header(state: BeaconState, assert header_root not in [pending_header.root for pending_header in pending_headers] # 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, index)) + committee_length = len(get_beacon_committee(state, header.slot, committee_index)) pending_headers.append(PendingShardHeader( slot=header.slot, shard=header.shard, @@ -693,6 +702,9 @@ def process_pending_headers(state: BeaconState) -> None: # The entire committee (and its balance) 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) # The set of voters who voted for each header (and their total balances) voting_sets = [ diff --git a/specs/sharding/p2p-interface.md b/specs/sharding/p2p-interface.md index 47ed52970..458c9985b 100644 --- a/specs/sharding/p2p-interface.md +++ b/specs/sharding/p2p-interface.md @@ -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). - _[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)` +- _[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 -- 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. @@ -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 -- 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. +- _[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 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`).