async def attest(self, slot: Slot) -> Tuple[Attestation, ...]: attestations: Tuple[Attestation, ...] = () head = self.chain.get_canonical_head() state_machine = self.chain.get_state_machine() state = self.chain.get_head_state() epoch = compute_epoch_of_slot(slot, self.slots_per_epoch) validator_assignments = { validator_index: self._get_this_epoch_assignment( validator_index, epoch, ) for validator_index in self.validator_privkeys } attesting_validators = self._get_attesting_validator_and_shard( validator_assignments, slot, epoch, ) if len(attesting_validators) == 0: return () # Sort the attesting validators by shard sorted_attesting_validators = sorted( attesting_validators, key=itemgetter(1), ) # Group the attesting validators by shard attesting_validators_groups = groupby( sorted_attesting_validators, key=itemgetter(1), ) for shard, group in attesting_validators_groups: # Get the validator_index -> privkey map of the attesting validators attesting_validator_privkeys = { attesting_data[0]: self.validator_privkeys[attesting_data[0]] for attesting_data in group } attesting_validators_indices = tuple( attesting_validator_privkeys.keys()) # Get one of the attesting validator's assignment in order to get the committee info assignment = self._get_this_epoch_assignment( attesting_validators_indices[0], epoch, ) attestation = create_signed_attestation_at_slot( state, state_machine.config, state_machine, slot, head.signing_root, attesting_validator_privkeys, assignment.committee, shard, ) self.logger.debug( bold_green("Validators=%s attest to block=%s attestation=%s"), attesting_validators_indices, head, attestation, ) for validator_index in attesting_validators_indices: self.latest_attested_epoch[validator_index] = epoch attestations = attestations + (attestation, ) self.logger.debug("Brodcasting attestations %s", attestations) await self.p2p_node.broadcast_attestations(attestations) return attestations
async def attest(self, slot: Slot) -> Tuple[Attestation, ...]: """ Attest the block at the given ``slot`` and broadcast them. """ attestations: Tuple[Attestation, ...] = () head = self.chain.get_canonical_head() state_machine = self.chain.get_state_machine() state = self.chain.get_head_state() epoch = compute_epoch_at_slot(slot, self.slots_per_epoch) attesting_committee_assignments_at_slot = self._get_attesting_assignments_at_slot(slot) for committee_assignment in attesting_committee_assignments_at_slot: committee_index = committee_assignment.committee_index committee = committee_assignment.committee attesting_validators_indices = tuple( filter( lambda attester: self.latest_attested_epoch[attester] < epoch, self._get_local_attesters_at_assignment(committee_assignment), ) ) # Get the validator_index -> privkey map of the attesting validators attesting_validator_privkeys = { index: self.validator_privkeys[index] for index in attesting_validators_indices } attestation = create_signed_attestation_at_slot( state, state_machine.config, state_machine, slot, head.signing_root, attesting_validator_privkeys, committee, committee_index, tuple( CommitteeValidatorIndex(committee.index(index)) for index in attesting_validators_indices ), ) self.logger.debug( bold_green("validators %s attesting to block %s with attestation %s"), attesting_validators_indices, head, attestation, ) # await self.p2p_node.broadcast_attestation(attestation) subnet_id = SubnetId(committee_index % ATTESTATION_SUBNET_COUNT) # Import attestation to pool and then broadcast it self.import_attestation(attestation, False) await self.p2p_node.broadcast_attestation_to_subnet(attestation, subnet_id) # Log the last epoch that the validator attested for index in attesting_validators_indices: self.latest_attested_epoch[index] = epoch attestations = attestations + (attestation,) # TODO: Aggregate attestations return attestations