def test_sync_committee_with_participating_withdrawable_member(spec, state): # move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH # move forward via some blocks for _ in range(3): next_epoch_via_block(spec, state) committee_indices = compute_committee_indices(spec, state) rng = random.Random(1010) exited_index = _exit_validator_from_committee_and_transition_state( spec, state, committee_indices, rng, lambda v: v.withdrawable_epoch + 1, ) current_epoch = spec.get_current_epoch(state) assert current_epoch > state.validators[exited_index].withdrawable_epoch block = build_empty_block_for_next_slot(spec, state) block.body.sync_aggregate = spec.SyncAggregate( sync_committee_bits=[True] * len(committee_indices), sync_committee_signature=compute_aggregate_sync_committee_signature( spec, state, block.slot - 1, committee_indices, # full committee signs block_root=block.parent_root, ) ) yield from run_sync_committee_processing(spec, state, block)
def test_finality_rule_2(spec, state): # get past first two epochs that finality does not run on next_epoch_via_block(spec, state) next_epoch_via_block(spec, state) yield 'pre', state blocks = [] for epoch in range(3): if epoch == 0: prev_state, new_blocks, state = next_epoch_with_attestations( spec, state, True, False) check_finality(spec, state, prev_state, True, False, False) elif epoch == 1: prev_state, new_blocks, state = next_epoch_with_attestations( spec, state, False, False) check_finality(spec, state, prev_state, False, True, False) elif epoch == 2: prev_state, new_blocks, state = next_epoch_with_attestations( spec, state, False, True) # finalized by rule 2 check_finality(spec, state, prev_state, True, False, True) assert state.finalized_checkpoint == prev_state.previous_justified_checkpoint blocks += new_blocks yield 'blocks', blocks yield 'post', state
def test_validator_withdrawal_reenable_after_custody_reveal(spec, state): transition_to_valid_shard_slot(spec, state) transition_to(spec, state, state.slot + 1) # Make len(offset_slots) == 1 spec.initiate_validator_exit(state, 0) assert state.validators[0].withdrawable_epoch < spec.FAR_FUTURE_EPOCH next_epoch_via_block(spec, state) assert state.validators[0].withdrawable_epoch == spec.FAR_FUTURE_EPOCH while spec.get_current_epoch(state) < state.validators[0].exit_epoch: next_epoch_via_block(spec, state) while (state.validators[0].next_custody_secret_to_reveal <= spec.get_custody_period_for_validator( 0, state.validators[0].exit_epoch - 1)): custody_key_reveal = get_valid_custody_key_reveal(spec, state, validator_index=0) _, _, _ = run_custody_key_reveal_processing(spec, state, custody_key_reveal) yield from run_process_custody_final_updates(spec, state) assert state.validators[0].withdrawable_epoch < spec.FAR_FUTURE_EPOCH
def test_current_filled(spec, state): next_epoch_via_block(spec, state) state.previous_epoch_participation = [0] * len(state.validators) state.current_epoch_participation = [get_full_flags(spec)] * len( state.validators) yield from run_process_participation_flag_updates(spec, state)
def test_reveal_from_past_epoch(spec, state): next_epoch_via_block(spec, state) randao_key_reveal = get_valid_early_derived_secret_reveal( spec, state, spec.get_current_epoch(state) - 1) yield from run_early_derived_secret_reveal_processing( spec, state, randao_key_reveal, False)
def test_success_previous_epoch(spec, state): attestation = get_valid_attestation(spec, state, signed=True, on_time=False) next_epoch_via_block(spec, state) yield from run_attestation_processing(spec, state, attestation)
def test_mismatched_target_and_slot(spec, state): next_epoch_via_block(spec, state) next_epoch_via_block(spec, state) attestation = get_valid_attestation(spec, state, on_time=False) attestation.data.slot = attestation.data.slot - spec.SLOTS_PER_EPOCH sign_attestation(spec, state, attestation) yield from run_attestation_processing(spec, state, attestation, False)
def test_validator_withdrawal_suspend_after_chunk_challenge(spec, state): transition_to_valid_shard_slot(spec, state) transition_to(spec, state, state.slot + 1) # Make len(offset_slots) == 1 shard = 0 offset_slots = spec.get_offset_slots(state, shard) shard_transition = get_sample_shard_transition( spec, state.slot, [2**15 // 3] * len(offset_slots)) attestation = get_valid_on_time_attestation( spec, state, index=shard, signed=True, shard_transition=shard_transition) transition_to(spec, state, state.slot + spec.MIN_ATTESTATION_INCLUSION_DELAY) _, _, _ = run_attestation_processing(spec, state, attestation) validator_index = spec.get_beacon_committee(state, attestation.data.slot, attestation.data.index)[0] spec.initiate_validator_exit(state, validator_index) assert state.validators[ validator_index].withdrawable_epoch < spec.FAR_FUTURE_EPOCH transition_to(spec, state, state.slot + spec.SLOTS_PER_EPOCH) assert state.validators[ validator_index].withdrawable_epoch == spec.FAR_FUTURE_EPOCH while spec.get_current_epoch( state) < state.validators[validator_index].exit_epoch: next_epoch_via_block(spec, state) while (state.validators[validator_index].next_custody_secret_to_reveal <= spec.get_custody_period_for_validator( validator_index, state.validators[validator_index].exit_epoch - 1)): custody_key_reveal = get_valid_custody_key_reveal( spec, state, validator_index=validator_index) _, _, _ = run_custody_key_reveal_processing(spec, state, custody_key_reveal) next_epoch_via_block(spec, state) challenge = get_valid_chunk_challenge(spec, state, attestation, shard_transition) _, _, _ = run_chunk_challenge_processing(spec, state, challenge) yield from run_process_custody_final_updates(spec, state) assert state.validators[ validator_index].withdrawable_epoch == spec.FAR_FUTURE_EPOCH
def test_success_attestation_from_future(spec, state): # Transition state to future to enable generation of a "future" attestation future_state = state.copy() next_epoch_via_block(spec, future_state) # Generate slashing using the future state attester_slashing = get_valid_attester_slashing( spec, future_state, slot=state.slot + 5, # Slot is in the future wrt `state` signed_1=True, signed_2=True) yield from run_attester_slashing_processing(spec, state, attester_slashing)
def test_success_proposer_index_slashed(spec, state): # Transition past genesis slot because generally doesn't have a proposer next_epoch_via_block(spec, state) proposer_index = spec.get_beacon_proposer_index(state) attester_slashing = get_valid_attester_slashing_by_indices( spec, state, [proposer_index], signed_1=True, signed_2=True, ) yield from run_attester_slashing_processing(spec, state, attester_slashing)
def test_finality_rule_3(spec, state): """ Test scenario described here https://github.com/ethereum/eth2.0-specs/issues/611#issuecomment-463612892 """ # get past first two epochs that finality does not run on next_epoch_via_block(spec, state) next_epoch_via_block(spec, state) yield 'pre', state blocks = [] prev_state, new_blocks, state = next_epoch_with_attestations( spec, state, True, False) blocks += new_blocks check_finality(spec, state, prev_state, True, False, False) # In epoch N, JE is set to N, prev JE is set to N-1 prev_state, new_blocks, state = next_epoch_with_attestations( spec, state, True, False) blocks += new_blocks check_finality(spec, state, prev_state, True, True, True) # In epoch N+1, JE is N, prev JE is N-1, and not enough messages get in to do anything prev_state, new_blocks, state = next_epoch_with_attestations( spec, state, False, False) blocks += new_blocks check_finality(spec, state, prev_state, False, True, False) # In epoch N+2, JE is N, prev JE is N, and enough messages from the previous epoch get in to justify N+1. # N+1 now becomes the JE. Not enough messages from epoch N+2 itself get in to justify N+2 prev_state, new_blocks, state = next_epoch_with_attestations( spec, state, False, True) blocks += new_blocks # rule 2 check_finality(spec, state, prev_state, True, False, True) # In epoch N+3, LJE is N+1, prev LJE is N, and enough messages get in to justify epochs N+2 and N+3. prev_state, new_blocks, state = next_epoch_with_attestations( spec, state, True, True) blocks += new_blocks # rule 3 check_finality(spec, state, prev_state, True, True, True) assert state.finalized_checkpoint == prev_state.current_justified_checkpoint yield 'blocks', blocks yield 'post', state
def test_success_surround(spec, state): next_epoch_via_block(spec, state) state.current_justified_checkpoint.epoch += 1 attester_slashing = get_valid_attester_slashing(spec, state, signed_1=False, signed_2=True) att_1_data = get_attestation_1_data(spec, attester_slashing) att_2_data = get_attestation_2_data(spec, attester_slashing) # set attestion1 to surround attestation 2 att_1_data.source.epoch = att_2_data.source.epoch - 1 att_1_data.target.epoch = att_2_data.target.epoch + 1 sign_indexed_attestation(spec, state, attester_slashing.attestation_1) yield from run_attester_slashing_processing(spec, state, attester_slashing)
def test_inactivity_scores(spec, state): for _ in range(spec.MIN_EPOCHS_TO_INACTIVITY_PENALTY + 2): next_epoch_via_block(spec, state) assert spec.is_in_inactivity_leak(state) previous_inactivity_scores = state.inactivity_scores.copy() yield 'pre', state # Block transition to next epoch block = build_empty_block(spec, state, slot=state.slot + spec.SLOTS_PER_EPOCH) signed_block = state_transition_and_sign_block(spec, state, block) yield 'blocks', [signed_block] yield 'post', state for pre, post in zip(previous_inactivity_scores, state.inactivity_scores): assert post == pre + spec.INACTIVITY_SCORE_BIAS
def test_proposer_after_inactive_index(spec, state): # disable some low validator index to check after for inactive_index = 10 state.validators[inactive_index].exit_epoch = spec.get_current_epoch(state) # skip forward, get brand new proposers next_epoch_via_block(spec, state) next_epoch_via_block(spec, state) while True: proposer_index = spec.get_beacon_proposer_index(state) if proposer_index > inactive_index: # found a proposer that has a higher index than a disabled validator yield 'pre', state # test if the proposer can be recognized correctly after the inactive validator signed_block = state_transition_and_sign_block(spec, state, build_empty_block_for_next_slot(spec, state)) yield 'blocks', [signed_block] yield 'post', state break next_slot(spec, state)
def test_finality_rule_4(spec, state): # get past first two epochs that finality does not run on next_epoch_via_block(spec, state) next_epoch_via_block(spec, state) yield 'pre', state blocks = [] for epoch in range(2): prev_state, new_blocks, state = next_epoch_with_attestations( spec, state, True, False) blocks += new_blocks if epoch == 0: check_finality(spec, state, prev_state, True, False, False) elif epoch == 1: # rule 4 of finality check_finality(spec, state, prev_state, True, True, True) assert state.finalized_checkpoint == prev_state.current_justified_checkpoint yield 'blocks', blocks yield 'post', state
def test_sync_committee_with_nonparticipating_exited_member(spec, state): # move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH # move forward via some blocks for _ in range(3): next_epoch_via_block(spec, state) committee_indices = compute_committee_indices(spec, state) rng = random.Random(1010) exited_index = _exit_validator_from_committee_and_transition_state( spec, state, committee_indices, rng, lambda v: v.exit_epoch, ) exited_pubkey = state.validators[exited_index].pubkey current_epoch = spec.get_current_epoch(state) assert current_epoch < state.validators[exited_index].withdrawable_epoch exited_committee_index = state.current_sync_committee.pubkeys.index(exited_pubkey) block = build_empty_block_for_next_slot(spec, state) committee_bits = [i != exited_committee_index for i in committee_indices] committee_indices = [index for index in committee_indices if index != exited_committee_index] block.body.sync_aggregate = spec.SyncAggregate( sync_committee_bits=committee_bits, sync_committee_signature=compute_aggregate_sync_committee_signature( spec, state, block.slot - 1, committee_indices, # with exited validator removed block_root=block.parent_root, ) ) yield from run_sync_committee_processing(spec, state, block)
def test_transition_with_no_attestations_until_after_fork( state, fork_epoch, spec, post_spec, pre_tag, post_tag): """ Transition from the initial ``state`` to the ``fork_epoch`` with no attestations, then transition forward with enough attestations to finalize the fork epoch. """ yield "pre", state assert spec.get_current_epoch(state) < fork_epoch # regular state transition until fork: to_slot = fork_epoch * spec.SLOTS_PER_EPOCH - 1 blocks = [] blocks.extend([ pre_tag(block) for block in _state_transition_across_slots(spec, state, to_slot) ]) # irregular state transition to handle fork: state, block = _do_altair_fork(state, spec, post_spec, fork_epoch) blocks.append(post_tag(block)) # continue regular state transition but add attestations # for enough epochs to finalize the ``fork_epoch`` block = next_epoch_via_block(post_spec, state) blocks.append(post_tag(sign_block(post_spec, state, block))) for _ in range(4): _, blocks_in_epoch, state = next_slots_with_attestations( post_spec, state, post_spec.SLOTS_PER_EPOCH, False, True, ) blocks.extend([post_tag(block) for block in blocks_in_epoch]) assert state.slot % post_spec.SLOTS_PER_EPOCH == 0 assert post_spec.get_current_epoch(state) == fork_epoch + 5 assert state.current_justified_checkpoint.epoch == fork_epoch + 3 assert state.finalized_checkpoint.epoch == fork_epoch + 1 yield "blocks", blocks yield "post", state
def test_random_inactivity_scores_full_participation(spec, state): next_epoch_via_block(spec, state) set_full_participation(spec, state) randomize_inactivity_scores(spec, state, rng=Random(33333)) yield from run_process_inactivity_updates(spec, state)
def test_previous_epoch_zeroed(spec, state): next_epoch_via_block(spec, state) random_flags(spec, state, 13, previous=False) state.previous_epoch_participation = [0] * len(state.validators) yield from run_process_participation_flag_updates(spec, state)
def _run_transition_test_with_attestations(state, fork_epoch, spec, post_spec, pre_tag, post_tag, participation_fn=None, expect_finality=True): yield "pre", state current_epoch = spec.get_current_epoch(state) assert current_epoch < fork_epoch assert current_epoch == spec.GENESIS_EPOCH # skip genesis epoch to avoid dealing with some edge cases... block = next_epoch_via_block(spec, state) # regular state transition until fork: fill_cur_epoch = False fill_prev_epoch = True blocks = [pre_tag(sign_block(spec, state, block))] current_epoch = spec.get_current_epoch(state) for _ in range(current_epoch, fork_epoch - 1): _, blocks_in_epoch, state = next_slots_with_attestations( spec, state, spec.SLOTS_PER_EPOCH, fill_cur_epoch, fill_prev_epoch, participation_fn=participation_fn, ) blocks.extend([pre_tag(block) for block in blocks_in_epoch]) _, blocks_in_epoch, state = next_slots_with_attestations( spec, state, spec.SLOTS_PER_EPOCH - 1, fill_cur_epoch, fill_prev_epoch, participation_fn=participation_fn, ) blocks.extend([pre_tag(block) for block in blocks_in_epoch]) assert spec.get_current_epoch(state) == fork_epoch - 1 assert (state.slot + 1) % spec.SLOTS_PER_EPOCH == 0 # irregular state transition to handle fork: state, block = _do_altair_fork(state, spec, post_spec, fork_epoch) blocks.append(post_tag(block)) # continue regular state transition with new spec into next epoch for _ in range(4): _, blocks_in_epoch, state = next_slots_with_attestations( post_spec, state, post_spec.SLOTS_PER_EPOCH, fill_cur_epoch, fill_prev_epoch, participation_fn=participation_fn, ) blocks.extend([post_tag(block) for block in blocks_in_epoch]) assert state.slot % post_spec.SLOTS_PER_EPOCH == 0 assert post_spec.get_current_epoch(state) == fork_epoch + 4 if expect_finality: assert state.current_justified_checkpoint.epoch == fork_epoch + 2 assert state.finalized_checkpoint.epoch == fork_epoch else: assert state.current_justified_checkpoint.epoch == spec.GENESIS_EPOCH assert state.finalized_checkpoint.epoch == spec.GENESIS_EPOCH assert len(blocks) == (fork_epoch + 3) * post_spec.SLOTS_PER_EPOCH + 1 assert len(blocks) == len(set(blocks)) blocks_without_attestations = [ block for block in blocks if len(block.message.body.attestations) == 0 ] assert len(blocks_without_attestations) == 2 slots_without_attestations = [ b.message.slot for b in blocks_without_attestations ] assert set(slots_without_attestations) == set( [spec.SLOTS_PER_EPOCH, fork_epoch * spec.SLOTS_PER_EPOCH]) yield "blocks", blocks yield "post", state
def test_balance_threshold_with_exited_validators(spec, state): """ This test exercises a very specific failure mode where exited validators are incorrectly included in the total active balance when weighing justification. """ rng = Random(133333) # move past genesis conditions for _ in range(3): next_epoch_via_block(spec, state) # mock attestation helper requires last slot of epoch for _ in range(spec.SLOTS_PER_EPOCH - 1): next_slot(spec, state) # Step 1: Exit ~1/2 vals in current epoch epoch = spec.get_current_epoch(state) for index in spec.get_active_validator_indices(state, epoch): if rng.choice([True, False]): continue validator = state.validators[index] validator.exit_epoch = epoch validator.withdrawable_epoch = epoch + 1 validator.withdrawable_epoch = validator.exit_epoch + spec.config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY exited_validators = get_unslashed_exited_validators(spec, state) assert len(exited_validators) != 0 source = state.current_justified_checkpoint target = spec.Checkpoint(epoch=epoch, root=spec.get_block_root(state, epoch)) add_mock_attestations( spec, state, epoch, source, target, sufficient_support=False, ) if not is_post_altair(spec): current_attestations = spec.get_matching_target_attestations( state, epoch) total_active_balance = spec.get_total_active_balance(state) current_target_balance = spec.get_attesting_balance( state, current_attestations) # Check we will not justify the current checkpoint does_justify = current_target_balance * 3 >= total_active_balance * 2 assert not does_justify # Ensure we would have justified the current checkpoint w/ the exited validators current_exited_balance = spec.get_total_balance( state, exited_validators) does_justify = (current_target_balance + current_exited_balance) * 3 >= total_active_balance * 2 assert does_justify else: current_indices = spec.get_unslashed_participating_indices( state, spec.TIMELY_TARGET_FLAG_INDEX, epoch) total_active_balance = spec.get_total_active_balance(state) current_target_balance = spec.get_total_balance(state, current_indices) # Check we will not justify the current checkpoint does_justify = current_target_balance * 3 >= total_active_balance * 2 assert not does_justify # Ensure we would have justified the current checkpoint w/ the exited validators current_exited_balance = spec.get_total_balance( state, exited_validators) does_justify = (current_target_balance + current_exited_balance) * 3 >= total_active_balance * 2 assert does_justify yield from run_process_just_and_fin(spec, state) assert state.current_justified_checkpoint.epoch != epoch
def test_slightly_larger_random(spec, state): next_epoch_via_block(spec, state) random_flags(spec, state, 14) yield from run_process_participation_flag_updates(spec, state)
def test_random_0(spec, state): next_epoch_via_block(spec, state) random_flags(spec, state, 100) yield from run_process_participation_flag_updates(spec, state)
def test_all_zero_inactivity_scores_random_participation(spec, state): next_epoch_via_block(spec, state) state.inactivity_scores = [0] * len(state.validators) randomize_attestation_participation(spec, state, rng=Random(5555)) yield from run_process_inactivity_updates(spec, state)
def test_fork_next_epoch_with_block(spec, phases, state): next_epoch_via_block(spec, state) yield from run_fork_test(phases[ALTAIR], state)
def test_all_zero_inactivity_scores_full_participation(spec, state): next_epoch_via_block(spec, state) set_full_participation(spec, state) state.inactivity_scores = [0] * len(state.validators) yield from run_process_inactivity_updates(spec, state)