Example #1
0
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,
            )
Example #5
0
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