diff --git a/specs/phase1/beacon-chain.md b/specs/phase1/beacon-chain.md index f9b123d3b..5a5200c9e 100644 --- a/specs/phase1/beacon-chain.md +++ b/specs/phase1/beacon-chain.md @@ -772,6 +772,8 @@ def validate_attestation(state: BeaconState, attestation: Attestation) -> None: # Correct shard number shard = compute_shard_from_committee_index(state, attestation.data.index, attestation.data.slot) assert attestation.data.shard == shard + # On-time attestations should have a non-empty shard transition root + assert attestation.data.shard_transition_root != hash_tree_root(ShardTransition()) # Type 2: no shard transition else: # Ensure delayed attestation @@ -886,11 +888,6 @@ def process_crosslink_for_shard(state: BeaconState, for attestation in transition_attestations: participants = get_attesting_indices(state, attestation.data, attestation.aggregation_bits) transition_participants = transition_participants.union(participants) - if len(shard_transition.shard_states) > 0: - # Is the `shard_transition` candidate - last_offset_index = len(shard_transition.shard_states) - 1 - shard_head_root = shard_transition.shard_states[last_offset_index].latest_block_root - assert attestation.data.shard_head_root == shard_head_root enough_online_stake = ( get_total_balance(state, online_indices.intersection(transition_participants)) * 3 >= @@ -903,6 +900,12 @@ def process_crosslink_for_shard(state: BeaconState, # Attestation <-> shard transition consistency assert shard_transition_root == hash_tree_root(shard_transition) + # Check `shard_head_root` of the winning root + last_offset_index = len(shard_transition.shard_states) - 1 + shard_head_root = shard_transition.shard_states[last_offset_index].latest_block_root + for attestation in transition_attestations: + assert attestation.data.shard_head_root == shard_head_root + # Apply transition apply_shard_transition(state, shard, shard_transition) # Apply proposer reward and cost