def test_get_attestation_participants( monkeypatch, num_validators, slots_per_epoch, committee, aggregation_bitfield, expected, sample_state, genesis_epoch, target_committee_size, shard_count, committee_config, sample_attestation_data_params): shard = 1 from eth2.beacon import committee_helpers def mock_get_crosslink_committees_at_slot(state, slot, committee_config, registry_change=False): return ( (committee, shard,), ) monkeypatch.setattr( committee_helpers, 'get_crosslink_committees_at_slot', mock_get_crosslink_committees_at_slot ) attestation_data = AttestationData(**sample_attestation_data_params).copy( slot=0, shard=shard, ) if isinstance(expected, Exception): with pytest.raises(ValidationError): get_attestation_participants( state=sample_state, attestation_data=attestation_data, bitfield=aggregation_bitfield, committee_config=committee_config, ) else: result = get_attestation_participants( state=sample_state, attestation_data=attestation_data, bitfield=aggregation_bitfield, committee_config=committee_config, ) assert result == expected
def get_inclusion_infos( *, state: 'BeaconState', attestations: Sequence[PendingAttestationRecord], committee_config: CommitteeConfig ) -> Dict[ValidatorIndex, InclusionInfo]: # noqa: E501 """ Return two maps. One with ``ValidatorIndex`` -> ``inclusion_slot`` and the other with ``ValidatorIndex`` -> ``inclusion_distance``. ``attestation.inclusion_slot`` is the slot during which the pending attestation is included. ``inclusion_distance = attestation.inclusion_slot - attestation.data.slot`` """ inclusion_infos: Dict[ValidatorIndex, InclusionInfo] = {} for attestation in attestations: participant_indices = get_attestation_participants( state, attestation.data, attestation.aggregation_bitfield, committee_config, ) for index in participant_indices: should_update_inclusion_data = ( index not in inclusion_infos or attestation.slot_included < inclusion_infos[index].inclusion_slot) if should_update_inclusion_data: inclusion_infos[index] = InclusionInfo( attestation.slot_included, attestation.data.slot) return inclusion_infos
def get_attesting_validator_indices( *, state: 'BeaconState', attestations: Sequence[PendingAttestationRecord], shard: ShardNumber, shard_block_root: Hash32, genesis_epoch: EpochNumber, epoch_length: int, target_committee_size: int, shard_count: int) -> Iterable[ValidatorIndex]: """ Loop through ``attestations`` and check if ``shard``/``shard_block_root`` in the attestation matches the given ``shard``/``shard_block_root``. If the attestation matches, get the index of the participating validators. Finally, return the union of the indices. """ for a in attestations: if a.data.shard == shard and a.data.shard_block_root == shard_block_root: yield from get_attestation_participants( state, a.data, a.aggregation_bitfield, genesis_epoch, epoch_length, target_committee_size, shard_count, )
def get_epoch_boundary_attester_indices( state: 'BeaconState', attestations: Sequence[PendingAttestationRecord], epoch: Epoch, root: Hash32, committee_config: CommitteeConfig) -> Iterable[ValidatorIndex]: for a in attestations: if a.data.justified_epoch == epoch and a.data.epoch_boundary_root == root: yield from get_attestation_participants( state, a.data, a.aggregation_bitfield, committee_config, )
def validate_attestation_aggregate_signature(state: BeaconState, attestation: Attestation, genesis_epoch: EpochNumber, epoch_length: int, target_committee_size: int, shard_count: int) -> None: """ Validate ``aggregate_signature`` field of ``attestation``. Raise ``ValidationError`` if it's invalid. Note: This is the phase 0 version of `aggregate_signature`` validation. All proof of custody bits are assumed to be 0 within the signed data. This will change to reflect real proof of custody bits in the Phase 1. """ participant_indices = get_attestation_participants( state=state, attestation_data=attestation.data, bitfield=attestation.aggregation_bitfield, genesis_epoch=genesis_epoch, epoch_length=epoch_length, target_committee_size=target_committee_size, shard_count=shard_count, ) pubkeys = tuple( state.validator_registry[validator_index].pubkey for validator_index in participant_indices ) group_public_key = bls.aggregate_pubkeys(pubkeys) # TODO: change to tree hashing when we have SSZ message = AttestationDataAndCustodyBit.create_attestation_message(attestation.data) domain = get_domain( fork=state.fork, epoch=slot_to_epoch(attestation.data.slot, epoch_length), domain_type=SignatureDomain.DOMAIN_ATTESTATION, ) is_valid_signature = bls.verify( message=message, pubkey=group_public_key, signature=attestation.aggregate_signature, domain=domain, ) if not is_valid_signature: raise ValidationError( "Attestation aggregate_signature is invalid. " "message={}, participant_indices={} " "domain={}".format( message, participant_indices, domain, ) )
def get_attesting_indices(state: 'BeaconState', attestations: Sequence[PendingAttestation], config: Eth2Config) -> Iterable[ValidatorIndex]: output: Set[ValidatorIndex] = set() for a in attestations: participants = get_attestation_participants( state, a.data, a.aggregation_bitfield, CommitteeConfig(config), ) output = output.union(participants) for result in sorted(output): yield result