async def handle_first_tick(self, slot: Slot) -> None: head = self.chain.get_canonical_head() state_machine = self.chain.get_state_machine() state = self.chain.get_head_state() self.logger.debug( bold_green( "status at slot %s in epoch %s: state_root %s, finalized_checkpoint %s" ), state.slot, state.current_epoch(self.slots_per_epoch), humanize_hash(head.message.state_root), state.finalized_checkpoint, ) self.logger.debug( ("status at slot %s in epoch %s:" " previous_justified_checkpoint %s, current_justified_checkpoint %s" ), state.slot, state.current_epoch(self.slots_per_epoch), state.previous_justified_checkpoint, state.current_justified_checkpoint, ) self.logger.debug( ("status at slot %s in epoch %s:" " previous_epoch_attestations %s, current_epoch_attestations %s"), state.slot, state.current_epoch(self.slots_per_epoch), state.previous_epoch_attestations, state.current_epoch_attestations, ) # To see if a validator is assigned to propose during the slot, the beacon state must # be in the epoch in question. At the epoch boundaries, the validator must run an # epoch transition into the epoch to successfully check the proposal assignment of the # first slot. temp_state = state_machine.state_transition.apply_state_transition( state, future_slot=slot, ) proposer_index = get_beacon_proposer_index( temp_state, CommitteeConfig(state_machine.config), ) # `latest_proposed_epoch` is used to prevent validator from erraneously proposing twice # in the same epoch due to service crashing. epoch = compute_epoch_at_slot(slot, self.slots_per_epoch) if proposer_index in self.validator_privkeys: has_proposed = epoch <= self.latest_proposed_epoch[proposer_index] if not has_proposed: await self.propose_block( proposer_index=proposer_index, slot=slot, state=state, state_machine=state_machine, head_block=head, ) self.latest_proposed_epoch[proposer_index] = epoch
async def test_validator_include_ready_attestations(event_loop, event_bus, monkeypatch): # Alice controls all validators alice_indices = list(range(NUM_VALIDATORS)) alice = await get_validator( event_loop=event_loop, event_bus=event_bus, monkeypatch=monkeypatch, indices=alice_indices, ) state_machine = alice.chain.get_state_machine() state = alice.chain.get_head_state() attesting_slot = state.slot + 1 attestations = await alice.attest(attesting_slot) assert len(attestations) > 0 # Mock `get_ready_attestations_fn` so it returns the attestation alice # attested to. def get_ready_attestations_fn(slot, is_aggregated): return attestations monkeypatch.setattr(alice, "get_ready_attestations", get_ready_attestations_fn) proposing_slot = (attesting_slot + MINIMAL_SERENITY_CONFIG.MIN_ATTESTATION_INCLUSION_DELAY) proposer_index = get_beacon_proposer_index( state.set("slot", proposing_slot), CommitteeConfig(state_machine.config)) head = alice.chain.get_canonical_head() block = await alice.propose_block( proposer_index=proposer_index, slot=proposing_slot, state=state, state_machine=state_machine, head_block=head, ) # Check that attestation is included in the proposed block. assert attestations[0] in block.body.attestations