diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 6a81dadcf..70b5bac9b 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1917,6 +1917,13 @@ def get_crosslink_deltas(state: BeaconState) -> Tuple[List[Gwei], List[Gwei]]: for slot in range(previous_epoch_start_slot, current_epoch_start_slot): for crosslink_committee, shard in get_crosslink_committees_at_slot(state, slot): winning_root, previous_crosslink_root, participants = get_winning_root_and_participants(state, slot, shard) + + # do not count as success if winning_root did not or cannot form a chain + attempted_crosslink = Crosslink(epoch=slot_to_epoch(slot), crosslink_data_root=winning_root, previous_crosslink_root=previous_crosslink_root) + current_crosslink_root = hash_tree_root(state.current_crosslinks[shard]) + if not current_crosslink_root in {previous_crosslink_root, hash_tree_root(attempted_crosslink) }: + participants = [] + participating_balance = get_total_balance(state, participants) total_balance = get_total_balance(state, crosslink_committee) for index in crosslink_committee: diff --git a/tests/phase0/epoch_processing/test_process_crosslinks.py b/tests/phase0/epoch_processing/test_process_crosslinks.py index f2be142c6..06dc07d85 100644 --- a/tests/phase0/epoch_processing/test_process_crosslinks.py +++ b/tests/phase0/epoch_processing/test_process_crosslinks.py @@ -7,12 +7,9 @@ from build.phase0.state_transition import ( state_transition, ) from build.phase0.spec import ( - ZERO_HASH, cache_state, - get_crosslink_committee_for_attestation, - get_current_epoch, + get_crosslink_deltas, process_crosslinks, - slot_to_epoch, ) from tests.phase0.helpers import ( add_attestation_to_state, @@ -20,6 +17,7 @@ from tests.phase0.helpers import ( fill_aggregate_attestation, get_valid_attestation, next_epoch, + next_slot, set_bitfield_bit, ) @@ -102,8 +100,11 @@ def test_double_late_crosslink(state): next_epoch(state) add_attestation_to_state(state, attestation_1, state.slot + 1) - state.slot = attestation_1.data.slot + spec.SLOTS_PER_EPOCH - attestation_2 = get_valid_attestation(state) + for slot in range(spec.SLOTS_PER_EPOCH): + attestation_2 = get_valid_attestation(state) + if attestation_2.data.shard == attestation_1.data.shard: + break + next_slot(state) fill_aggregate_attestation(state, attestation_2) # add attestation_2 in the next epoch after attestation_1 has @@ -115,13 +116,15 @@ def test_double_late_crosslink(state): assert len(state.current_epoch_attestations) == 0 pre_state, post_state = run_process_crosslinks(state) + crosslink_deltas = get_crosslink_deltas(state) - shard_1 = attestation_1.data.shard - shard_2 = attestation_2.data.shard - assert shard_1 == shard_2 - shard = shard_1 + shard = attestation_2.data.shard + slot = attestation_2.data.slot # ensure that the current crosslinks were not updated by the second attestation assert post_state.previous_crosslinks[shard] == post_state.current_crosslinks[shard] + # ensure no reward, only penalties for the failed crosslink + assert crosslink_deltas[0][slot % spec.SLOTS_PER_EPOCH] == 0 + assert crosslink_deltas[1][slot % spec.SLOTS_PER_EPOCH] > 0 return pre_state, post_state diff --git a/tests/phase0/helpers.py b/tests/phase0/helpers.py index cd731e49c..219e77c47 100644 --- a/tests/phase0/helpers.py +++ b/tests/phase0/helpers.py @@ -274,7 +274,7 @@ def get_valid_attester_slashing(state): def get_valid_attestation(state, slot=None): if slot is None: slot = state.slot - shard = state.latest_start_shard + slot % spec.SLOTS_PER_EPOCH + shard = (state.latest_start_shard + slot) % spec.SLOTS_PER_EPOCH attestation_data = build_attestation_data(state, slot, shard) crosslink_committee = get_crosslink_committee_for_attestation(state, attestation_data) @@ -341,6 +341,11 @@ def add_attestation_to_state(state, attestation, slot): state_transition(state, block) +def next_slot(state): + block = build_empty_block_for_next_slot(state) + state_transition(state, block) + + def next_epoch(state): block = build_empty_block_for_next_slot(state) block.slot += spec.SLOTS_PER_EPOCH - (state.slot % spec.SLOTS_PER_EPOCH)