def test_single_crosslink_update_from_previous_epoch(spec, state): next_epoch(spec, state) attestation = get_valid_attestation(spec, state, signed=True) fill_aggregate_attestation(spec, state, attestation) add_attestation_to_state(spec, state, attestation, state.slot + spec.SLOTS_PER_EPOCH) assert len(state.previous_epoch_attestations) == 1 shard = attestation.data.crosslink.shard pre_crosslink = deepcopy(state.current_crosslinks[shard]) crosslink_deltas = spec.get_crosslink_deltas(state) yield from run_process_crosslinks(spec, state) assert state.previous_crosslinks[shard] != state.current_crosslinks[shard] assert pre_crosslink != state.current_crosslinks[shard] # ensure rewarded for index in spec.get_crosslink_committee( state, attestation.data.target_epoch, attestation.data.crosslink.shard): assert crosslink_deltas[0][index] > 0 assert crosslink_deltas[1][index] == 0
def test_get_eth1_vote_consensus_vote(spec, state): min_new_period_epochs = get_min_new_period_epochs(spec) for _ in range(min_new_period_epochs + 2): next_epoch(spec, state) period_start = spec.voting_period_start_time(state) votes_length = spec.get_current_epoch(state) % spec.EPOCHS_PER_ETH1_VOTING_PERIOD assert votes_length >= 3 # We need to have the majority vote state.eth1_data_votes = () block_1 = spec.Eth1Block( timestamp=period_start - spec.SECONDS_PER_ETH1_BLOCK * spec.ETH1_FOLLOW_DISTANCE - 1, deposit_count=state.eth1_data.deposit_count, deposit_root=b'\x04' * 32, ) block_2 = spec.Eth1Block( timestamp=period_start - spec.SECONDS_PER_ETH1_BLOCK * spec.ETH1_FOLLOW_DISTANCE, deposit_count=state.eth1_data.deposit_count + 1, deposit_root=b'\x05' * 32, ) eth1_chain = [block_1, block_2] eth1_data_votes = [] # Only the first vote is for block_1 eth1_data_votes.append(spec.get_eth1_data(block_1)) # Other votes are for block_2 for _ in range(votes_length - 1): eth1_data_votes.append(spec.get_eth1_data(block_2)) state.eth1_data_votes = eth1_data_votes eth1_data = spec.get_eth1_vote(state, eth1_chain) assert eth1_data.block_hash == block_2.hash_tree_root()
def test_get_eth1_vote_tie(spec, state): min_new_period_epochs = get_min_new_period_epochs(spec) for _ in range(min_new_period_epochs + 1): next_epoch(spec, state) period_start = spec.voting_period_start_time(state) votes_length = spec.get_current_epoch(state) % spec.EPOCHS_PER_ETH1_VOTING_PERIOD assert votes_length > 0 and votes_length % 2 == 0 state.eth1_data_votes = () block_1 = spec.Eth1Block( timestamp=period_start - spec.SECONDS_PER_ETH1_BLOCK * spec.ETH1_FOLLOW_DISTANCE - 1, deposit_count=state.eth1_data.deposit_count, deposit_root=b'\x04' * 32, ) block_2 = spec.Eth1Block( timestamp=period_start - spec.SECONDS_PER_ETH1_BLOCK * spec.ETH1_FOLLOW_DISTANCE, deposit_count=state.eth1_data.deposit_count + 1, deposit_root=b'\x05' * 32, ) eth1_chain = [block_1, block_2] eth1_data_votes = [] # Half votes are for block_1, another half votes are for block_2 for i in range(votes_length): if i % 2 == 0: block = block_1 else: block = block_2 eth1_data_votes.append(spec.get_eth1_data(block)) state.eth1_data_votes = eth1_data_votes eth1_data = spec.get_eth1_vote(state, eth1_chain) # Tiebreak by smallest distance -> eth1_chain[0] assert eth1_data.block_hash == eth1_chain[0].hash_tree_root()
def transition_state_to_leak(spec, state, epochs=None): if epochs is None: epochs = spec.MIN_EPOCHS_TO_INACTIVITY_PENALTY assert epochs >= spec.MIN_EPOCHS_TO_INACTIVITY_PENALTY for _ in range(epochs): next_epoch(spec, state)
def test_on_attestation_inconsistent_target_and_head(spec, state): store = get_genesis_forkchoice_store(spec, state) spec.on_tick(store, store.time + 2 * spec.config.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH) # Create chain 1 as empty chain between genesis and start of 1st epoch target_state_1 = state.copy() next_epoch(spec, target_state_1) # Create chain 2 with different block in chain from chain 1 from chain 1 from chain 1 from chain 1 target_state_2 = state.copy() diff_block = build_empty_block_for_next_slot(spec, target_state_2) signed_diff_block = state_transition_and_sign_block(spec, target_state_2, diff_block) spec.on_block(store, signed_diff_block) next_epoch(spec, target_state_2) next_slot(spec, target_state_2) # Create and store block new head block on target state 1 head_block = build_empty_block_for_next_slot(spec, target_state_1) signed_head_block = state_transition_and_sign_block(spec, target_state_1, head_block) spec.on_block(store, signed_head_block) # Attest to head of chain 1 attestation = get_valid_attestation(spec, target_state_1, slot=head_block.slot, signed=False) epoch = spec.compute_epoch_at_slot(attestation.data.slot) # Set attestation target to be from chain 2 attestation.data.target = spec.Checkpoint(epoch=epoch, root=spec.get_block_root(target_state_2, epoch)) sign_attestation(spec, state, attestation) assert attestation.data.target.epoch == spec.GENESIS_EPOCH + 1 assert spec.compute_epoch_at_slot(attestation.data.slot) == spec.GENESIS_EPOCH + 1 assert spec.get_block_root(target_state_1, epoch) != attestation.data.target.root run_on_attestation(spec, state, store, attestation, False)
def test_update_justified_single_on_store_finalized_chain(spec, state): store = get_genesis_forkchoice_store(spec, state) # [Mock store.best_justified_checkpoint] # Create a block at epoch 1 next_epoch(spec, state) block = build_empty_block_for_next_slot(spec, state) state_transition_and_sign_block(spec, state, block) store.blocks[block.hash_tree_root()] = block.copy() store.block_states[block.hash_tree_root()] = state.copy() parent_block = block.copy() # To make compute_slots_since_epoch_start(current_slot) == 0, transition to the end of the epoch slot = state.slot + spec.SLOTS_PER_EPOCH - state.slot % spec.SLOTS_PER_EPOCH - 1 transition_to(spec, state, slot) # Create a block at the start of epoch 2 block = build_empty_block_for_next_slot(spec, state) # Mock state state.current_justified_checkpoint = spec.Checkpoint( epoch=spec.compute_epoch_at_slot(parent_block.slot), root=parent_block.hash_tree_root(), ) state_transition_and_sign_block(spec, state, block) store.blocks[block.hash_tree_root()] = block store.block_states[block.hash_tree_root()] = state # Mock store.best_justified_checkpoint store.best_justified_checkpoint = state.current_justified_checkpoint.copy() run_on_tick(spec, store, store.genesis_time + state.slot * spec.config.SECONDS_PER_SLOT, new_justified_checkpoint=True)
def test_on_block_update_justified_checkpoint_within_safe_slots(spec, state): # Initialization store = spec.get_genesis_store(state) time = 100 spec.on_tick(store, time) next_epoch(spec, state) spec.on_tick(store, store.time + state.slot * spec.SECONDS_PER_SLOT) state, store, last_block = apply_next_epoch_with_attestations( spec, state, store) next_epoch(spec, state) spec.on_tick(store, store.time + state.slot * spec.SECONDS_PER_SLOT) last_block_root = signing_root(last_block) # Mock the justified checkpoint just_state = store.block_states[last_block_root] new_justified = spec.Checkpoint( epoch=just_state.current_justified_checkpoint.epoch + 1, root=b'\x77' * 32, ) just_state.current_justified_checkpoint = new_justified block = build_empty_block_for_next_slot(spec, just_state) state_transition_and_sign_block(spec, deepcopy(just_state), block) assert spec.get_current_slot( store) % spec.SLOTS_PER_EPOCH < spec.SAFE_SLOTS_TO_UPDATE_JUSTIFIED run_on_block(spec, store, block) assert store.justified_checkpoint == new_justified
def test_activation_queue_to_activated_if_finalized(spec, state): # move past first two irregular epochs wrt finality next_epoch(spec, state) next_epoch(spec, state) index = 0 mock_deposit(spec, state, index) # mock validator as having been in queue since latest finalized state.finalized_checkpoint.epoch = spec.get_current_epoch(state) - 1 state.validators[ index].activation_eligibility_epoch = state.finalized_checkpoint.epoch assert not spec.is_active_validator(state.validators[index], spec.get_current_epoch(state)) yield from run_process_registry_updates(spec, state) # validator activated for future epoch assert state.validators[ index].activation_eligibility_epoch != spec.FAR_FUTURE_EPOCH assert state.validators[index].activation_epoch != spec.FAR_FUTURE_EPOCH assert not spec.is_active_validator(state.validators[index], spec.get_current_epoch(state)) assert spec.is_active_validator( state.validators[index], spec.compute_activation_exit_epoch(spec.get_current_epoch(state)))
def test_finality_rule_1(spec, state): # get past first two epochs that finality does not run on next_epoch(spec, state) apply_empty_block(spec, state) next_epoch(spec, state) apply_empty_block(spec, state) yield 'pre', state blocks = [] for epoch in range(3): prev_state, new_blocks, state = next_epoch_with_attestations(spec, state, False, True) blocks += new_blocks if epoch == 0: check_finality(spec, state, prev_state, True, False, False) elif epoch == 1: check_finality(spec, state, prev_state, True, True, False) elif epoch == 2: # finalized by rule 1 check_finality(spec, state, prev_state, True, True, True) assert state.finalized_checkpoint == prev_state.previous_justified_checkpoint yield 'blocks', blocks yield 'post', state
def test_success_previous_epoch(spec, state): attestation = get_valid_attestation(spec, state, signed=True) state.slot = spec.SLOTS_PER_EPOCH - 1 next_epoch(spec, state) apply_empty_block(spec, state) yield from run_attestation_processing(spec, state, attestation)
def test_full_random_without_leak_and_current_exit_0(spec, state): """ This test specifically ensures a validator exits in the current epoch to ensure rewards are handled properly in this case. """ rng = Random(1011) randomize_state(spec, state, rng) assert spec.is_in_inactivity_leak(state) patch_state_to_non_leaking(spec, state) assert not spec.is_in_inactivity_leak(state) target_validators = get_unslashed_exited_validators(spec, state) assert len(target_validators) != 0 # move forward some epochs to process attestations added # by ``randomize_state`` before we exit validators in # what will be the current epoch for _ in range(2): next_epoch(spec, state) current_epoch = spec.get_current_epoch(state) for index in target_validators: # patch exited validators to exit in the current epoch validator = state.validators[index] validator.exit_epoch = current_epoch validator.withdrawable_epoch = current_epoch + spec.config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY # re-randomize attestation participation for the current epoch randomize_attestation_participation(spec, state, rng) assert has_active_balance_differential(spec, state) yield from rewards_helpers.run_deltas(spec, state)
def transition_state_to_leak(spec, state, epochs=None): if epochs is None: # +1 to trigger inactivity_score transitions epochs = spec.MIN_EPOCHS_TO_INACTIVITY_PENALTY + 1 assert epochs >= spec.MIN_EPOCHS_TO_INACTIVITY_PENALTY for _ in range(epochs): next_epoch(spec, state)
def test_scaled_penalties(spec, state): # skip to next epoch next_epoch(spec, state) # Also mock some previous slashings, so that we test to have the delta in the penalties computation. base = spec.config.EJECTION_BALANCE incr = spec.EFFECTIVE_BALANCE_INCREMENT # Just add some random slashings. non-zero slashings are at least the minimal effective balance. state.slashings[0] = base + (incr * 12) state.slashings[4] = base + (incr * 3) state.slashings[5] = base + (incr * 6) state.slashings[spec.EPOCHS_PER_SLASHINGS_VECTOR - 1] = base + (incr * 7) slashed_count = len( state.validators) // (get_slashing_multiplier(spec) + 1) assert slashed_count > 10 # make the balances non-uniform. # Otherwise it would just be a simple balance slashing. Test the per-validator scaled penalties. diff = spec.MAX_EFFECTIVE_BALANCE - base increments = diff // incr for i in range(10): state.validators[i].effective_balance = base + (incr * (i % increments)) assert state.validators[ i].effective_balance <= spec.MAX_EFFECTIVE_BALANCE # add/remove some, see if balances different than the effective balances are picked up state.balances[i] = state.validators[i].effective_balance + i - 5 total_balance = spec.get_total_active_balance(state) out_epoch = spec.get_current_epoch(state) + ( spec.EPOCHS_PER_SLASHINGS_VECTOR // 2) slashed_indices = list(range(slashed_count)) # Process up to the sub-transition, then Hi-jack and get the balances. # We just want to test the slashings. # But we are not interested in the other balance changes during the same epoch transition. run_epoch_processing_to(spec, state, 'process_slashings') pre_slash_balances = list(state.balances) slash_validators(spec, state, slashed_indices, [out_epoch] * slashed_count) yield 'pre', state spec.process_slashings(state) yield 'post', state total_penalties = sum(state.slashings) for i in slashed_indices: v = state.validators[i] expected_penalty = ( v.effective_balance // spec.EFFECTIVE_BALANCE_INCREMENT * (get_slashing_multiplier(spec) * total_penalties) // (total_balance) * spec.EFFECTIVE_BALANCE_INCREMENT) assert state.balances[i] == pre_slash_balances[i] - expected_penalty
def test_get_eth1_vote_default_vote(spec, state): min_new_period_epochs = get_min_new_period_epochs(spec) for _ in range(min_new_period_epochs): next_epoch(spec, state) state.eth1_data_votes = () eth1_chain = [] eth1_data = spec.get_eth1_vote(state, eth1_chain) assert eth1_data == state.eth1_data
def test_reveal_from_past_epoch(spec, state): next_epoch(spec, state) apply_empty_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_get_start_shard_far_past_epoch(spec, state): initial_epoch = spec.get_current_epoch(state) initial_start_slot = spec.compute_start_slot_at_epoch(initial_epoch) initial_start_shard = state.current_epoch_start_shard for _ in range(spec.MAX_SHARDS + 2): next_epoch(spec, state) assert spec.get_start_shard(state, initial_start_slot) == initial_start_shard
def transition_state_to_leak(spec, state, epochs=None): if epochs is None: # +2 because finality delay is based on previous_epoch and must be more than `MIN_EPOCHS_TO_INACTIVITY_PENALTY` epochs = spec.MIN_EPOCHS_TO_INACTIVITY_PENALTY + 2 assert epochs > spec.MIN_EPOCHS_TO_INACTIVITY_PENALTY for _ in range(epochs): next_epoch(spec, state) assert spec.is_in_inactivity_leak(state)
def test_no_attestations_all_penalties(spec, state): next_epoch(spec, state) pre_state = deepcopy(state) assert spec.compute_epoch_at_slot(state.slot) == spec.GENESIS_EPOCH + 1 yield from run_process_rewards_and_penalties(spec, state) for index in range(len(pre_state.validators)): assert state.balances[index] < pre_state.balances[index]
def test_mismatched_target_and_slot(spec, state): next_epoch(spec, state) next_epoch(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_no_attestations_all_penalties(spec, state): # Move to next epoch to ensure rewards/penalties are processed next_epoch(spec, state) pre_state = state.copy() assert spec.compute_epoch_at_slot(state.slot) == spec.GENESIS_EPOCH + 1 yield from run_process_rewards_and_penalties(spec, state) validate_resulting_balances(spec, pre_state, state, [])
def test_on_block_outside_safe_slots_and_multiple_better_justified( spec, state): # Initialization store = spec.get_genesis_store(state) time = 100 spec.on_tick(store, time) next_epoch(spec, state) spec.on_tick(store, store.time + state.slot * spec.SECONDS_PER_SLOT) state, store, last_signed_block = apply_next_epoch_with_attestations( spec, state, store) next_epoch(spec, state) spec.on_tick(store, store.time + state.slot * spec.SECONDS_PER_SLOT) last_block_root = hash_tree_root(last_signed_block.message) # Mock justified block in store just_block = build_empty_block_for_next_slot(spec, state) # Slot is same as justified checkpoint so does not trigger an override in the store just_block.slot = spec.compute_start_slot_at_epoch( store.justified_checkpoint.epoch) store.blocks[just_block.hash_tree_root()] = just_block # Step time past safe slots spec.on_tick( store, store.time + spec.SAFE_SLOTS_TO_UPDATE_JUSTIFIED * spec.SECONDS_PER_SLOT) assert spec.get_current_slot( store) % spec.SLOTS_PER_EPOCH >= spec.SAFE_SLOTS_TO_UPDATE_JUSTIFIED previously_justified = store.justified_checkpoint # Add a series of new blocks with "better" justifications best_justified_checkpoint = spec.Checkpoint(epoch=0) for i in range(3, 0, -1): just_state = store.block_states[last_block_root] new_justified = spec.Checkpoint( epoch=previously_justified.epoch + i, root=just_block.hash_tree_root(), ) if new_justified.epoch > best_justified_checkpoint.epoch: best_justified_checkpoint = new_justified just_state.current_justified_checkpoint = new_justified block = build_empty_block_for_next_slot(spec, just_state) signed_block = state_transition_and_sign_block(spec, deepcopy(just_state), block) run_on_block(spec, store, signed_block) assert store.justified_checkpoint == previously_justified # ensure the best from the series was stored assert store.best_justified_checkpoint == best_justified_checkpoint
def test_attestation(spec, state): next_epoch(spec, state) yield 'pre', state attestation_block = build_empty_block( spec, state, state.slot + spec.MIN_ATTESTATION_INCLUSION_DELAY) index = 0 # if spec.fork == SHARDING: # TODO add shard data to block to vote on attestation = get_valid_attestation(spec, state, index=index, signed=True, on_time=True) if not is_post_altair(spec): pre_current_attestations_len = len(state.current_epoch_attestations) # Add to state via block transition attestation_block.body.attestations.append(attestation) signed_attestation_block = state_transition_and_sign_block( spec, state, attestation_block) if not is_post_altair(spec): assert len(state.current_epoch_attestations ) == pre_current_attestations_len + 1 # Epoch transition should move to previous_epoch_attestations pre_current_attestations_root = spec.hash_tree_root( state.current_epoch_attestations) else: pre_current_epoch_participation_root = spec.hash_tree_root( state.current_epoch_participation) epoch_block = build_empty_block(spec, state, state.slot + spec.SLOTS_PER_EPOCH) signed_epoch_block = state_transition_and_sign_block( spec, state, epoch_block) yield 'blocks', [signed_attestation_block, signed_epoch_block] yield 'post', state if not is_post_altair(spec): assert len(state.current_epoch_attestations) == 0 assert spec.hash_tree_root( state.previous_epoch_attestations) == pre_current_attestations_root else: for index in range(len(state.validators)): assert state.current_epoch_participation[ index] == spec.ParticipationFlags(0b0000_0000) assert spec.hash_tree_root(state.previous_epoch_participation ) == pre_current_epoch_participation_root
def test_proposer_is_withdrawn(spec, state): proposer_slashing = get_valid_proposer_slashing(spec, state, signed_1=True, signed_2=True) # move 1 epoch into future, to allow for past withdrawable epoch next_epoch(spec, state) # set proposer withdrawable_epoch in past current_epoch = spec.get_current_epoch(state) proposer_index = proposer_slashing.signed_header_1.message.proposer_index state.validators[proposer_index].withdrawable_epoch = current_epoch - 1 yield from run_proposer_slashing_processing(spec, state, proposer_slashing, False)
def test_success_withdrawable(spec, state): next_epoch(spec, state) apply_empty_block(spec, state) transfer = get_valid_transfer(spec, state, signed=True) # withdrawable_epoch in past so can transfer state.validators[ transfer.sender].withdrawable_epoch = spec.get_current_epoch(state) - 1 yield from run_transfer_processing(spec, state, transfer)
def test_activation(spec, state): index = 0 mock_deposit(spec, state, index) for _ in range(spec.MAX_SEED_LOOKAHEAD + 1): next_epoch(spec, state) yield from run_process_registry_updates(spec, state) assert state.validators[index].activation_eligibility_epoch != spec.FAR_FUTURE_EPOCH assert state.validators[index].activation_epoch != spec.FAR_FUTURE_EPOCH assert spec.is_active_validator(state.validators[index], spec.get_current_epoch(state))
def prepare_state_with_attestations(spec, state, participation_fn=None): """ Prepare state with attestations according to the ``participation_fn``. If no ``participation_fn``, default to "full" -- max committee participation at each slot. participation_fn: (slot, committee_index, committee_indices_set) -> participants_indices_set """ # Go to start of next epoch to ensure can have full participation next_epoch(spec, state) start_slot = state.slot start_epoch = spec.get_current_epoch(state) next_epoch_start_slot = spec.compute_start_slot_at_epoch(start_epoch + 1) attestations = [] for _ in range(spec.SLOTS_PER_EPOCH + spec.MIN_ATTESTATION_INCLUSION_DELAY): # create an attestation for each index in each slot in epoch if state.slot < next_epoch_start_slot: for committee_index in range( spec.get_committee_count_per_slot( state, spec.get_current_epoch(state))): def temp_participants_filter(comm): if participation_fn is None: return comm else: return participation_fn(state.slot, committee_index, comm) attestation = get_valid_attestation( spec, state, index=committee_index, filter_participant_set=temp_participants_filter, signed=True) if any(attestation.aggregation_bits ): # Only if there is at least 1 participant. attestations.append(attestation) # fill each created slot in state after inclusion delay if state.slot >= start_slot + spec.MIN_ATTESTATION_INCLUSION_DELAY: inclusion_slot = state.slot - spec.MIN_ATTESTATION_INCLUSION_DELAY include_attestations = [ att for att in attestations if att.data.slot == inclusion_slot ] add_attestations_to_state(spec, state, include_attestations, state.slot) next_slot(spec, state) assert state.slot == next_epoch_start_slot + spec.MIN_ATTESTATION_INCLUSION_DELAY if not is_post_altair(spec): assert len(state.previous_epoch_attestations) == len(attestations) return attestations
def test_bad_crosslink_end_epoch(spec, state): next_epoch(spec, state) apply_empty_block(spec, state) attestation = get_valid_attestation(spec, state, signed=True) for _ in range(spec.MIN_ATTESTATION_INCLUSION_DELAY): next_slot(spec, state) apply_empty_block(spec, state) attestation.data.crosslink.end_epoch += 1 yield from run_attestation_processing(spec, state, attestation, False)
def test_get_start_shard_current_epoch_start(spec, state): assert state.current_epoch_start_shard == 0 next_epoch(spec, state) active_shard_count = spec.get_active_shard_count(state) assert state.current_epoch_start_shard == ( spec.get_committee_count_delta(state, 0, spec.SLOTS_PER_EPOCH) % active_shard_count ) current_epoch_start_slot = spec.compute_start_slot_at_epoch(spec.get_current_epoch(state)) slot = current_epoch_start_slot start_shard = spec.get_start_shard(state, slot) assert start_shard == state.current_epoch_start_shard
def test_bad_previous_crosslink(state): next_epoch(state) apply_empty_block(state) attestation = get_valid_attestation(state, signed=True) for _ in range(spec.MIN_ATTESTATION_INCLUSION_DELAY): next_slot(state) apply_empty_block(state) state.current_crosslinks[attestation.data.shard].epoch += 10 yield from run_attestation_processing(state, attestation, False)
def test_on_block_outside_safe_slots_but_finality(spec, state): # Initialization store = get_genesis_forkchoice_store(spec, state) time = 100 spec.on_tick(store, time) next_epoch(spec, state) spec.on_tick(store, store.time + state.slot * spec.SECONDS_PER_SLOT) state, store, last_signed_block = apply_next_epoch_with_attestations(spec, state, store) last_block_root = hash_tree_root(last_signed_block.message) # Mock fictitious justified checkpoint in store store.justified_checkpoint = spec.Checkpoint( epoch=spec.compute_epoch_at_slot(last_signed_block.message.slot), root=spec.Root("0x4a55535449464945440000000000000000000000000000000000000000000000") ) next_epoch(spec, state) spec.on_tick(store, store.time + state.slot * spec.SECONDS_PER_SLOT) # Create new higher justified checkpoint not in branch of store's justified checkpoint just_block = build_empty_block_for_next_slot(spec, state) store.blocks[just_block.hash_tree_root()] = just_block # Step time past safe slots spec.on_tick(store, store.time + spec.SAFE_SLOTS_TO_UPDATE_JUSTIFIED * spec.SECONDS_PER_SLOT) assert spec.get_current_slot(store) % spec.SLOTS_PER_EPOCH >= spec.SAFE_SLOTS_TO_UPDATE_JUSTIFIED # Mock justified and finalized update in state just_fin_state = store.block_states[last_block_root] new_justified = spec.Checkpoint( epoch=spec.compute_epoch_at_slot(just_block.slot) + 1, root=just_block.hash_tree_root(), ) assert new_justified.epoch > store.justified_checkpoint.epoch new_finalized = spec.Checkpoint( epoch=spec.compute_epoch_at_slot(just_block.slot), root=just_block.parent_root, ) assert new_finalized.epoch > store.finalized_checkpoint.epoch just_fin_state.current_justified_checkpoint = new_justified just_fin_state.finalized_checkpoint = new_finalized # Build and add block that includes the new justified/finalized info block = build_empty_block_for_next_slot(spec, just_fin_state) signed_block = state_transition_and_sign_block(spec, deepcopy(just_fin_state), block) run_on_block(spec, store, signed_block) assert store.finalized_checkpoint == new_finalized assert store.justified_checkpoint == new_justified