From 3ee0761d17206d5cd3f97ef72dea14beeb106eb7 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Tue, 16 Jun 2020 00:16:39 +0800 Subject: [PATCH 1/5] Add `shard: Shard` field to `AttestationData` --- specs/phase1/beacon-chain.md | 18 ++++++------------ specs/phase1/fork-choice.md | 3 ++- specs/phase1/shard-transition.md | 3 +-- .../test/fork_choice/test_on_attestation.py | 2 +- .../test/fork_choice/test_on_shard_head.py | 2 +- .../eth2spec/test/helpers/attestations.py | 10 ++++++---- 6 files changed, 17 insertions(+), 21 deletions(-) diff --git a/specs/phase1/beacon-chain.md b/specs/phase1/beacon-chain.md index 87de9d34e..582e2e669 100644 --- a/specs/phase1/beacon-chain.md +++ b/specs/phase1/beacon-chain.md @@ -55,7 +55,6 @@ - [`get_indexed_attestation`](#get_indexed_attestation) - [`get_committee_count_delta`](#get_committee_count_delta) - [`get_start_shard`](#get_start_shard) - - [`get_shard`](#get_shard) - [`get_latest_slot_for_shard`](#get_latest_slot_for_shard) - [`get_offset_slots`](#get_offset_slots) - [Predicates](#predicates) @@ -165,6 +164,8 @@ class AttestationData(Container): # FFG vote source: Checkpoint target: Checkpoint + # Shard vote + shard: Shard # Current-slot shard block root shard_head_root: Root # Shard transition root @@ -624,16 +625,6 @@ def get_start_shard(state: BeaconState, slot: Slot) -> Shard: ) ``` -#### `get_shard` - -```python -def get_shard(state: BeaconState, attestation: Attestation) -> Shard: - """ - Return the shard that the given ``attestation`` is attesting. - """ - return compute_shard_from_committee_index(state, attestation.data.index, attestation.data.slot) -``` - #### `get_latest_slot_for_shard` ```python @@ -833,12 +824,15 @@ def validate_attestation(state: BeaconState, attestation: Attestation) -> None: else: assert attestation.data.source == state.previous_justified_checkpoint + assert attestation.data.shard == compute_shard_from_committee_index( + state, attestation.data.index, attestation.data.slot) + # Type 1: on-time attestations, the custody bits should be non-empty. if attestation.custody_bits_blocks != []: # Ensure on-time attestation assert is_on_time_attestation(state, attestation) # Correct data root count - shard = get_shard(state, attestation) + shard = attestation.data.shard assert len(attestation.custody_bits_blocks) == len(get_offset_slots(state, shard)) # Correct parent block root assert data.beacon_block_root == get_block_root_at_slot(state, compute_previous_slot(state.slot)) diff --git a/specs/phase1/fork-choice.md b/specs/phase1/fork-choice.md index 3f9fbdbfb..b07f33496 100644 --- a/specs/phase1/fork-choice.md +++ b/specs/phase1/fork-choice.md @@ -47,7 +47,8 @@ class LatestMessage(object): def update_latest_messages(store: Store, attesting_indices: Sequence[ValidatorIndex], attestation: Attestation) -> None: target = attestation.data.target beacon_block_root = attestation.data.beacon_block_root - shard = get_shard(store.block_states[beacon_block_root], attestation) + # TODO: separate shard chain vote + shard = attestation.data.shard for i in attesting_indices: if i not in store.latest_messages or target.epoch > store.latest_messages[i].epoch: store.latest_messages[i] = LatestMessage( diff --git a/specs/phase1/shard-transition.md b/specs/phase1/shard-transition.md index c62b059ee..186b4cad0 100644 --- a/specs/phase1/shard-transition.md +++ b/specs/phase1/shard-transition.md @@ -148,8 +148,7 @@ def is_valid_fraud_proof(beacon_state: BeaconState, # 2. Check if the shard state transition result is wrong between # `transition.shard_states[offset_index - 1]` to `transition.shard_states[offset_index]`. if offset_index == 0: - shard = get_shard(beacon_state, attestation) - shard_states = beacon_parent_block.body.shard_transitions[shard].shard_states + shard_states = beacon_parent_block.body.shard_transitions[attestation.data.shard].shard_states shard_state = shard_states[len(shard_states) - 1] else: shard_state = transition.shard_states[offset_index - 1] # Not doing the actual state updates here. diff --git a/tests/core/pyspec/eth2spec/test/fork_choice/test_on_attestation.py b/tests/core/pyspec/eth2spec/test/fork_choice/test_on_attestation.py index a5334c5c7..1c177a919 100644 --- a/tests/core/pyspec/eth2spec/test/fork_choice/test_on_attestation.py +++ b/tests/core/pyspec/eth2spec/test/fork_choice/test_on_attestation.py @@ -31,7 +31,7 @@ def run_on_attestation(spec, state, store, attestation, valid=True): latest_message = spec.LatestMessage( epoch=attestation.data.target.epoch, root=attestation.data.beacon_block_root, - shard=spec.get_shard(state, attestation), + shard=attestation.data.shard, shard_root=attestation.data.shard_head_root, ) diff --git a/tests/core/pyspec/eth2spec/test/fork_choice/test_on_shard_head.py b/tests/core/pyspec/eth2spec/test/fork_choice/test_on_shard_head.py index 24eeaedbe..c84f073b2 100644 --- a/tests/core/pyspec/eth2spec/test/fork_choice/test_on_shard_head.py +++ b/tests/core/pyspec/eth2spec/test/fork_choice/test_on_shard_head.py @@ -82,7 +82,7 @@ def apply_shard_and_beacon(spec, state, store, shard_store, shard_blocks_buffer) shard_transition=shard_transition, signed=False, ) - assert spec.get_shard(state, attestation) == shard + assert attestation.data.shard == shard beacon_block.body.attestations = [attestation] beacon_block.body.shard_transitions = shard_transitions diff --git a/tests/core/pyspec/eth2spec/test/helpers/attestations.py b/tests/core/pyspec/eth2spec/test/helpers/attestations.py index 1e0560405..25d55f3a9 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/attestations.py +++ b/tests/core/pyspec/eth2spec/test/helpers/attestations.py @@ -45,7 +45,7 @@ def run_attestation_processing(spec, state, attestation, valid=True): yield 'post', state -def build_attestation_data(spec, state, slot, index, shard_transition=None, on_time=True): +def build_attestation_data(spec, state, slot, index, shard=None, shard_transition=None, on_time=True): assert state.slot >= slot if slot == state.slot: @@ -77,13 +77,15 @@ def build_attestation_data(spec, state, slot, index, shard_transition=None, on_t ) if spec.fork == PHASE1: + if shard is None: + shard = spec.compute_shard_from_committee_index(state, attestation_data.index, attestation_data.slot) + attestation_data.shard = shard + if shard_transition is not None: lastest_shard_data_root_index = len(shard_transition.shard_data_roots) - 1 attestation_data.shard_head_root = shard_transition.shard_data_roots[lastest_shard_data_root_index] attestation_data.shard_transition_root = shard_transition.hash_tree_root() else: - # No shard transition -> no shard block - shard = spec.get_shard(state, spec.Attestation(data=attestation_data)) if on_time: shard_transition = spec.get_shard_transition(state, shard, shard_blocks=[]) lastest_shard_data_root_index = len(shard_transition.shard_data_roots) - 1 @@ -96,7 +98,7 @@ def build_attestation_data(spec, state, slot, index, shard_transition=None, on_t def convert_to_valid_on_time_attestation(spec, state, attestation, signed=False): - shard = spec.get_shard(state, attestation) + shard = spec.compute_shard_from_committee_index(state, attestation.data.index, attestation.data.slot) offset_slots = spec.compute_offset_slots( spec.get_latest_slot_for_shard(state, shard), attestation.data.slot + spec.MIN_ATTESTATION_INCLUSION_DELAY, From c8ae7d99f9e4875581ab3f31d88f63ab63a11ab6 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Wed, 17 Jun 2020 09:05:44 +0800 Subject: [PATCH 2/5] Fix after auto-merge --- specs/phase1/beacon-chain.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/specs/phase1/beacon-chain.md b/specs/phase1/beacon-chain.md index 0b7db5516..ad543a941 100644 --- a/specs/phase1/beacon-chain.md +++ b/specs/phase1/beacon-chain.md @@ -760,6 +760,9 @@ def validate_attestation(state: BeaconState, attestation: Attestation) -> None: else: assert attestation.data.source == state.previous_justified_checkpoint + assert attestation.data.shard == compute_shard_from_committee_index( + state, attestation.data.index, attestation.data.slot) + # Type 1: on-time attestations if is_on_time_attestation(state, attestation): # Correct parent block root From 23cbbb1d081c07c915e8db56de796e1cb042bb98 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Wed, 17 Jun 2020 09:47:39 +0800 Subject: [PATCH 3/5] Fix shard number assertion and refactor it --- specs/phase1/beacon-chain.md | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/specs/phase1/beacon-chain.md b/specs/phase1/beacon-chain.md index ad543a941..f63654182 100644 --- a/specs/phase1/beacon-chain.md +++ b/specs/phase1/beacon-chain.md @@ -760,13 +760,14 @@ def validate_attestation(state: BeaconState, attestation: Attestation) -> None: else: assert attestation.data.source == state.previous_justified_checkpoint - assert attestation.data.shard == compute_shard_from_committee_index( - state, attestation.data.index, attestation.data.slot) - # Type 1: on-time attestations if is_on_time_attestation(state, attestation): # Correct parent block root assert data.beacon_block_root == get_block_root_at_slot(state, compute_previous_slot(state.slot)) + # Correct shard number + assert attestation.data.shard == compute_shard_from_committee_index( + state, attestation.data.index, attestation.data.slot + ) # Type 2: no shard transition else: # Ensure delayed attestation @@ -868,7 +869,6 @@ def process_crosslink_for_shard(state: BeaconState, on_time_attestation_slot = compute_previous_slot(state.slot) committee = get_beacon_committee(state, on_time_attestation_slot, committee_index) online_indices = get_online_validator_indices(state) - shard = compute_shard_from_committee_index(state, committee_index, on_time_attestation_slot) # Loop over all shard transition roots shard_transition_roots = set([a.data.shard_transition_root for a in attestations]) @@ -894,7 +894,7 @@ def process_crosslink_for_shard(state: BeaconState, assert shard_transition_root == hash_tree_root(shard_transition) # Apply transition - apply_shard_transition(state, shard, shard_transition) + apply_shard_transition(state, attestation.data.shard, shard_transition) # Apply proposer reward and cost beacon_proposer_index = get_beacon_proposer_index(state) estimated_attester_reward = sum([get_base_reward(state, attester) for attester in transition_participants]) @@ -902,11 +902,11 @@ def process_crosslink_for_shard(state: BeaconState, increase_balance(state, beacon_proposer_index, proposer_reward) states_slots_lengths = zip( shard_transition.shard_states, - get_offset_slots(state, shard), + get_offset_slots(state, attestation.data.shard), shard_transition.shard_block_lengths ) for shard_state, slot, length in states_slots_lengths: - proposer_index = get_shard_proposer_index(state, slot, shard) + proposer_index = get_shard_proposer_index(state, slot, attestation.data.shard) decrease_balance(state, proposer_index, shard_state.gasprice * length) # Return winning transition root @@ -931,13 +931,16 @@ def process_crosslinks(state: BeaconState, attestation for attestation in attestations if is_on_time_attestation(state, attestation) and attestation.data.index == committee_index ] - shard = compute_shard_from_committee_index(state, committee_index, on_time_attestation_slot) - winning_root = process_crosslink_for_shard(state, committee_index, shard_transitions[shard], shard_attestations) - if winning_root != Root(): - # Mark relevant pending attestations as creating a successful crosslink - for pending_attestation in state.current_epoch_attestations: - if is_winning_attestation(state, pending_attestation, committee_index, winning_root): - pending_attestation.crosslink_success = True + if len(shard_attestations) > 0: + shard = shard_attestations[0].data.shard + winning_root = process_crosslink_for_shard( + state, committee_index, shard_transitions[shard], shard_attestations + ) + if winning_root != Root(): + # Mark relevant pending attestations as creating a successful crosslink + for pending_attestation in state.current_epoch_attestations: + if is_winning_attestation(state, pending_attestation, committee_index, winning_root): + pending_attestation.crosslink_success = True ``` ###### `verify_empty_shard_transition` From 35bf3b5290bed6bbae03ca62d798766dbcd3791c Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Thu, 18 Jun 2020 23:20:24 +0800 Subject: [PATCH 4/5] Refactor `validate_attestation` Co-authored-by: Danny Ryan --- specs/phase1/beacon-chain.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/specs/phase1/beacon-chain.md b/specs/phase1/beacon-chain.md index f63654182..27f317bc1 100644 --- a/specs/phase1/beacon-chain.md +++ b/specs/phase1/beacon-chain.md @@ -765,9 +765,8 @@ def validate_attestation(state: BeaconState, attestation: Attestation) -> None: # Correct parent block root assert data.beacon_block_root == get_block_root_at_slot(state, compute_previous_slot(state.slot)) # Correct shard number - assert attestation.data.shard == compute_shard_from_committee_index( - state, attestation.data.index, attestation.data.slot - ) + shard = compute_shard_from_committee_index(state, attestation.data.index, attestation.data.slot) + assert attestation.data.shard == shard # Type 2: no shard transition else: # Ensure delayed attestation From fe47869d5f73ba5c4aea419186fad8e47b9ced63 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Thu, 18 Jun 2020 23:32:23 +0800 Subject: [PATCH 5/5] Revert `process_crosslinks` and add comment --- specs/phase1/beacon-chain.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/specs/phase1/beacon-chain.md b/specs/phase1/beacon-chain.md index 27f317bc1..485a52d06 100644 --- a/specs/phase1/beacon-chain.md +++ b/specs/phase1/beacon-chain.md @@ -926,20 +926,20 @@ def process_crosslinks(state: BeaconState, committee_count = get_committee_count_at_slot(state, on_time_attestation_slot) for committee_index in map(CommitteeIndex, range(committee_count)): # All attestations in the block for this committee/shard and current slot + shard = compute_shard_from_committee_index(state, committee_index, on_time_attestation_slot) + # Since the attestations are validated, all `shard_attestations` satisfy `attestation.data.shard == shard` shard_attestations = [ attestation for attestation in attestations if is_on_time_attestation(state, attestation) and attestation.data.index == committee_index ] - if len(shard_attestations) > 0: - shard = shard_attestations[0].data.shard - winning_root = process_crosslink_for_shard( - state, committee_index, shard_transitions[shard], shard_attestations - ) - if winning_root != Root(): - # Mark relevant pending attestations as creating a successful crosslink - for pending_attestation in state.current_epoch_attestations: - if is_winning_attestation(state, pending_attestation, committee_index, winning_root): - pending_attestation.crosslink_success = True + winning_root = process_crosslink_for_shard( + state, committee_index, shard_transitions[shard], shard_attestations + ) + if winning_root != Root(): + # Mark relevant pending attestations as creating a successful crosslink + for pending_attestation in state.current_epoch_attestations: + if is_winning_attestation(state, pending_attestation, committee_index, winning_root): + pending_attestation.crosslink_success = True ``` ###### `verify_empty_shard_transition`