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:
parent
671ed36212
commit
414ef614cb
|
@ -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 = [
|
||||||
|
|
|
@ -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`).
|
||||||
|
|
Loading…
Reference in New Issue