def is_aggregator( state: BeaconState, slot: Slot, index: CommitteeIndex, signature: BLSSignature, config: Eth2Config, ) -> bool: """ Check if the validator is one of the aggregators of the given ``slot``. .. note:: - Probabilistically, with enought validators, the aggregator count should approach ``TARGET_AGGREGATORS_PER_COMMITTEE``. - With ``len(committee)`` is 128 and ``TARGET_AGGREGATORS_PER_COMMITTEE`` is 16, the expected length of selected validators is 16. - It's possible that this algorithm selects *no one* as the aggregator, but with the above parameters, the chance of having no aggregator has a probability of 3.78E-08. - Chart analysis: https://docs.google.com/spreadsheets/d/1C7pBqEWJgzk3_jesLkqJoDTnjZOODnGTOJUrxUMdxMA # noqa: E501 """ committee = get_beacon_committee(state, slot, index, config) modulo = max(1, len(committee) // TARGET_AGGREGATORS_PER_COMMITTEE) return int.from_bytes(hash_eth2(signature)[0:8], byteorder="little") % modulo == 0
def test_get_attesting_indices(genesis_state, config): state = genesis_state.set( "slot", compute_start_slot_at_epoch(3, config.SLOTS_PER_EPOCH)) target_epoch = state.current_epoch(config.SLOTS_PER_EPOCH) target_slot = compute_start_slot_at_epoch(target_epoch, config.SLOTS_PER_EPOCH) committee_index = 0 some_committee = get_beacon_committee(state, target_slot, committee_index, config) data = AttestationData.create( slot=target_slot, index=committee_index, target=Checkpoint.create(epoch=target_epoch), ) some_subset_count = random.randrange(1, len(some_committee) // 2) some_subset = random.sample(some_committee, some_subset_count) bitfield = get_empty_bitfield(len(some_committee)) for i, index in enumerate(some_committee): if index in some_subset: bitfield = set_voted(bitfield, i) indices = get_attesting_indices(state, data, bitfield, config) assert set(indices) == set(some_subset) assert len(indices) == len(some_subset)
def _validate_aggregation_bits(state: BeaconState, attestation: Attestation, config: Eth2Config) -> None: data = attestation.data committee = get_beacon_committee(state, data.slot, data.index, config) if not (len(attestation.aggregation_bits) == len(committee)): raise ValidationError( f"The attestation bit lengths not match:" f"\tlen(attestation.aggregation_bits)={len(attestation.aggregation_bits)}\n" f"\tlen(committee)={len(committee)}")
def get_attesting_indices( state: BeaconState, attestation_data: AttestationData, bitfield: Bitfield, config: CommitteeConfig, ) -> Set[ValidatorIndex]: """ Return the attesting indices corresponding to ``attestation_data`` and ``bitfield``. """ committee = get_beacon_committee(state, attestation_data.slot, attestation_data.index, config) return set(index for i, index in enumerate(committee) if has_voted(bitfield, i))
def test_get_beacon_committee(genesis_state, config): state = genesis_state indices = tuple() epoch_start_slot = state.slot for slot in range(epoch_start_slot, epoch_start_slot + config.SLOTS_PER_EPOCH): committees_at_slot = get_committee_count_at_slot( state, slot, config.MAX_COMMITTEES_PER_SLOT, config.SLOTS_PER_EPOCH, config.TARGET_COMMITTEE_SIZE, ) for committee_index in range(committees_at_slot): some_committee = get_beacon_committee(state, slot, committee_index, config) indices += tuple(some_committee) assert set(indices) == set(range(len(genesis_state.validators))) assert len(indices) == len(genesis_state.validators)
def test_get_unslashed_attesting_indices(genesis_state, config): state = genesis_state.set( "slot", compute_start_slot_at_epoch(3, config.SLOTS_PER_EPOCH) ) target_epoch = state.current_epoch(config.SLOTS_PER_EPOCH) target_slot = compute_start_slot_at_epoch(target_epoch, config.SLOTS_PER_EPOCH) committee_index = 0 some_committee = get_beacon_committee( state, target_slot, committee_index, CommitteeConfig(config) ) data = AttestationData.create( slot=state.slot, index=committee_index, target=Checkpoint.create(epoch=target_epoch), ) some_subset_count = random.randrange(1, len(some_committee) // 2) some_subset = random.sample(some_committee, some_subset_count) bitfield = get_empty_bitfield(len(some_committee)) for i, index in enumerate(some_committee): if index in some_subset: if random.choice([True, False]): state = state.transform(["validators", index, "slashed"], True) bitfield = set_voted(bitfield, i) some_subset = tuple( filter(lambda index: not state.validators[index].slashed, some_subset) ) indices = get_unslashed_attesting_indices( state, (PendingAttestation.create(data=data, aggregation_bits=bitfield),), CommitteeConfig(config), ) assert set(indices) == set(some_subset) assert len(indices) == len(some_subset)