def test_aggregator_selection(validator_count, privkeys, genesis_state, config): state = genesis_state epoch = compute_epoch_at_slot(state.slot, config.SLOTS_PER_EPOCH) sum_aggregator_count = 0 for committee, committee_index, slot in iterate_committees_at_epoch( state, epoch, config): assert config.TARGET_COMMITTEE_SIZE == len(committee) aggregator_count = 0 for index in range(validator_count): if index in committee: signature = get_slot_signature(genesis_state, slot, privkeys[index], config) attester_is_aggregator = is_aggregator(state, slot, committee_index, signature, config) if attester_is_aggregator: aggregator_count += 1 assert aggregator_count > 0 sum_aggregator_count += aggregator_count # The average aggregator count per slot should be around # `TARGET_AGGREGATORS_PER_COMMITTEE`. average_aggregator_count = sum_aggregator_count / config.SLOTS_PER_EPOCH assert (TARGET_AGGREGATORS_PER_COMMITTEE - 3 < average_aggregator_count < TARGET_AGGREGATORS_PER_COMMITTEE + 3)
async def aggregate(self, slot: Slot) -> Tuple[AggregateAndProof, ...]: """ Aggregate the attestations at ``slot`` and broadcast them. """ # Check the aggregators selection aggregate_and_proofs: Tuple[AggregateAndProof, ...] = () state_machine = self.chain.get_state_machine() state = self.chain.get_head_state() config = state_machine.config attesting_committee_assignments_at_slot = self._get_attesting_assignments_at_slot( slot) # 1. For each committee_assignment at the given slot for committee_assignment in attesting_committee_assignments_at_slot: committee_index = committee_assignment.committee_index local_attesters = 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 local_attesters } selected_proofs: Dict[ValidatorIndex, BLSSignature] = {} # 2. For each attester for validator_index, privkey in attesting_validator_privkeys.items( ): # Check if the vallidator is one of the aggregators signature = get_slot_signature(state, slot, privkey, CommitteeConfig(config)) is_aggregator_result = is_aggregator(state, slot, committee_index, signature, CommitteeConfig(config)) if is_aggregator_result: self.logger.debug( f"validator ({validator_index}) is aggregator of" f" committee_index={committee_index} at slot={slot}") selected_proofs[validator_index] = signature else: continue aggregates = self._get_aggregates(slot, committee_index, config) # 3. For each aggregate # (it's possible with same CommitteeIndex and different AttesatationData) for aggregate in aggregates: aggregate_and_proof = AggregateAndProof.create( aggregator_index=validator_index, aggregate=aggregate, selection_proof=selected_proofs[validator_index], ) self.import_attestation(aggregate_and_proof.aggregate, True) await self.p2p_node.broadcast_beacon_aggregate_and_proof( aggregate_and_proof) aggregate_and_proofs += (aggregate_and_proof, ) return aggregate_and_proofs