Пример #1
0
def test_calculate_first_committee_at_slot(genesis_state,
                                           config):
    state = genesis_state
    slots_per_epoch = config.SLOTS_PER_EPOCH
    shard_count = config.SHARD_COUNT
    target_committee_size = config.TARGET_COMMITTEE_SIZE

    current_epoch = state.current_epoch(slots_per_epoch)

    active_validator_indices = get_active_validator_indices(state.validators, current_epoch)

    committees_per_slot = get_committees_per_slot(
        len(active_validator_indices),
        shard_count,
        slots_per_epoch,
        target_committee_size,
    )

    assert state.slot % config.SLOTS_PER_EPOCH == 0
    for slot in range(state.slot, state.slot + config.SLOTS_PER_EPOCH):
        offset = committees_per_slot * (slot % slots_per_epoch)
        shard = (
            get_epoch_start_shard(state, current_epoch, config) + offset
        ) % shard_count
        committee = get_crosslink_committee(
            state,
            current_epoch,
            shard,
            config,
        )

        assert committee == _calculate_first_committee_at_slot(state, slot, CommitteeConfig(config))
Пример #2
0
def test_get_unslashed_attesting_indices(genesis_state, config):
    state = genesis_state.copy(
        slot=compute_start_slot_of_epoch(3, config.SLOTS_PER_EPOCH))
    target_epoch = state.current_epoch(config.SLOTS_PER_EPOCH)
    target_shard = (state.start_shard + 3) % config.SHARD_COUNT
    some_committee = get_crosslink_committee(state, target_epoch, target_shard,
                                             CommitteeConfig(config))

    data = AttestationData(target=Checkpoint(epoch=target_epoch),
                           crosslink=Crosslink(shard=target_shard))
    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.update_validator_with_fn(
                    index, lambda v, *_: v.copy(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(data=data, aggregation_bits=bitfield), ),
        CommitteeConfig(config),
    )

    assert set(indices) == set(some_subset)
    assert len(indices) == len(some_subset)
Пример #3
0
def test_get_attesting_indices(genesis_state, config):
    state = genesis_state.copy(
        slot=get_epoch_start_slot(3, config.SLOTS_PER_EPOCH))
    target_epoch = state.current_epoch(config.SLOTS_PER_EPOCH)
    target_shard = (state.start_shard + 3) % config.SHARD_COUNT
    some_committee = get_crosslink_committee(
        state,
        target_epoch,
        target_shard,
        CommitteeConfig(config),
    )

    data = AttestationData(
        target_epoch=target_epoch,
        crosslink=Crosslink(shard=target_shard, ),
    )
    some_subset_count = random.randint(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,
        CommitteeConfig(config),
    )

    assert set(indices) == set(some_subset)
    assert len(indices) == len(some_subset)
Пример #4
0
def get_crosslink_deltas(
        state: BeaconState,
        config: Eth2Config) -> Tuple[Sequence[Gwei], Sequence[Gwei]]:
    rewards = tuple(0 for _ in range(len(state.validators)))
    penalties = tuple(0 for _ in range(len(state.validators)))
    epoch = state.previous_epoch(config.SLOTS_PER_EPOCH, config.GENESIS_EPOCH)
    active_validators_indices = get_active_validator_indices(
        state.validators, epoch)
    epoch_committee_count = get_committee_count(
        len(active_validators_indices),
        config.SHARD_COUNT,
        config.SLOTS_PER_EPOCH,
        config.TARGET_COMMITTEE_SIZE,
    )
    epoch_start_shard = get_start_shard(
        state,
        epoch,
        CommitteeConfig(config),
    )
    for shard_offset in range(epoch_committee_count):
        shard = Shard((epoch_start_shard + shard_offset) % config.SHARD_COUNT)
        crosslink_committee = set(
            get_crosslink_committee(
                state,
                epoch,
                shard,
                CommitteeConfig(config),
            ))
        _, attesting_indices = get_winning_crosslink_and_attesting_indices(
            state=state,
            epoch=epoch,
            shard=shard,
            config=config,
        )
        total_attesting_balance = get_total_balance(
            state,
            attesting_indices,
        )
        total_committee_balance = get_total_balance(
            state,
            crosslink_committee,
        )
        for index in crosslink_committee:
            base_reward = get_base_reward(state, index, config)
            if index in attesting_indices:
                rewards = update_tuple_item_with_fn(
                    rewards, index, lambda balance, delta: balance + delta,
                    base_reward * total_attesting_balance //
                    total_committee_balance)
            else:
                penalties = update_tuple_item_with_fn(
                    penalties,
                    index,
                    lambda balance, delta: balance + delta,
                    base_reward,
                )
    return tuple(Gwei(reward) for reward in rewards), tuple(
        Gwei(penalty) for penalty in penalties)
Пример #5
0
def process_crosslinks(state: BeaconState, config: Eth2Config) -> BeaconState:
    current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH)
    previous_epoch = state.previous_epoch(config.SLOTS_PER_EPOCH,
                                          config.GENESIS_EPOCH)

    new_current_crosslinks = state.current_crosslinks

    for epoch in (previous_epoch, current_epoch):
        active_validators_indices = get_active_validator_indices(
            state.validators, epoch)
        epoch_committee_count = get_committee_count(
            len(active_validators_indices),
            config.SHARD_COUNT,
            config.SLOTS_PER_EPOCH,
            config.TARGET_COMMITTEE_SIZE,
        )
        epoch_start_shard = get_start_shard(
            state,
            epoch,
            CommitteeConfig(config),
        )
        for shard_offset in range(epoch_committee_count):
            shard = Shard(
                (epoch_start_shard + shard_offset) % config.SHARD_COUNT)
            crosslink_committee = set(
                get_crosslink_committee(
                    state,
                    epoch,
                    shard,
                    CommitteeConfig(config),
                ))

            if not crosslink_committee:
                # empty crosslink committee this epoch
                continue

            winning_crosslink, attesting_indices = get_winning_crosslink_and_attesting_indices(
                state=state,
                epoch=epoch,
                shard=shard,
                config=config,
            )
            threshold_met = _is_threshold_met_against_committee(
                state,
                attesting_indices,
                crosslink_committee,
            )
            if threshold_met:
                new_current_crosslinks = update_tuple_item(
                    new_current_crosslinks,
                    shard,
                    winning_crosslink,
                )

    return state.copy(
        previous_crosslinks=state.current_crosslinks,
        current_crosslinks=new_current_crosslinks,
    )
Пример #6
0
def _mk_attestation_inputs_in_epoch(epoch, state, config):
    active_validators_indices = get_active_validator_indices(state.validators, epoch)
    epoch_committee_count = get_committee_count(
        len(active_validators_indices),
        config.SHARD_COUNT,
        config.SLOTS_PER_EPOCH,
        config.TARGET_COMMITTEE_SIZE,
    )
    epoch_start_shard = get_start_shard(
        state,
        epoch,
        CommitteeConfig(config),
    )
    for shard_offset in random.sample(range(epoch_committee_count), epoch_committee_count):
        shard = Shard((epoch_start_shard + shard_offset) % config.SHARD_COUNT)
        committee = get_crosslink_committee(
            state,
            epoch,
            shard,
            CommitteeConfig(config),
        )

        if not committee:
            # empty crosslink committee this epoch
            continue

        attestation_data = AttestationData(
            target=Checkpoint(
                epoch=epoch,
            ),
            crosslink=Crosslink(
                shard=shard,
            ),
        )
        committee_count = len(committee)
        aggregation_bits = bitfield.get_empty_bitfield(committee_count)
        for index in range(committee_count):
            aggregation_bits = bitfield.set_voted(aggregation_bits, index)

            for index in committee:
                yield (
                    index,
                    (
                        get_attestation_data_slot(
                            state,
                            attestation_data,
                            config,
                        ),
                        (
                            aggregation_bits,
                            attestation_data,
                        ),
                    ),
                )
Пример #7
0
def _validate_aggregation_bits(state: BeaconState, attestation: Attestation,
                               config: CommitteeConfig) -> None:
    data = attestation.data
    committee = get_crosslink_committee(state, data.target.epoch,
                                        data.crosslink.shard, config)
    if not (len(attestation.aggregation_bits) == len(attestation.custody_bits)
            == len(committee)):
        raise ValidationError(
            f"The attestation bit lengths not match:"
            f"\tlen(attestation.aggregation_bits)={len(attestation.aggregation_bits)}\n"
            f"\tlen(attestation.custody_bits)={len(attestation.custody_bits)}"
            f"\tlen(committee)={len(committee)}")
Пример #8
0
def test_find_winning_crosslink_and_attesting_indices_from_candidates(
        genesis_state, number_of_candidates, config):
    some_epoch = config.GENESIS_EPOCH + 20
    some_shard = 3

    state = genesis_state.copy(
        slot=compute_start_slot_of_epoch(some_epoch, config.SLOTS_PER_EPOCH),
        start_shard=some_shard,
        current_crosslinks=tuple(
            Crosslink(shard=i, data_root=(i).to_bytes(32, "little"))
            for i in range(config.SHARD_COUNT)),
    )

    full_committee = get_crosslink_committee(state, some_epoch, some_shard,
                                             CommitteeConfig(config))

    # break the committees up into different subsets to simulate different
    # attestations for the same crosslink
    committees = tuple(
        random_sample(
            len(full_committee) // number_of_candidates, full_committee)
        for _ in range(number_of_candidates))
    seen = set()
    filtered_committees = tuple()
    for committee in committees:
        deduplicated_committee = tuple()
        for index in committee:
            if index in seen:
                pass
            else:
                seen.add(index)
                deduplicated_committee += (index, )
        filtered_committees += (deduplicated_committee, )

    candidates = tuple(
        mk_pending_attestation_from_committee(
            state.current_crosslinks[some_shard],
            len(full_committee),
            some_shard,
            target_epoch=some_epoch,
        ) for committee in filtered_committees)

    if number_of_candidates == 0:
        expected_result = (Crosslink(), set())
    else:
        expected_result = (candidates[0].data.crosslink,
                           set(sorted(full_committee)))

    result = _find_winning_crosslink_and_attesting_indices_from_candidates(
        state, candidates, config)
    assert result == expected_result
Пример #9
0
def get_attesting_indices(
    state: BeaconState,
    attestation_data: AttestationData,
    bitfield: Bitfield,
    config: CommitteeConfig,
) -> Set[ValidatorIndex]:
    """
    Return the sorted attesting indices corresponding to ``attestation_data`` and ``bitfield``.
    """
    committee = get_crosslink_committee(state, attestation_data.target.epoch,
                                        attestation_data.crosslink.shard,
                                        config)
    return set(index for i, index in enumerate(committee)
               if has_voted(bitfield, i))
Пример #10
0
def get_committee_assignment(
    state: BeaconState,
    config: Eth2Config,
    epoch: Epoch,
    validator_index: ValidatorIndex,
) -> CommitteeAssignment:
    """
    Return the ``CommitteeAssignment`` in the ``epoch`` for ``validator_index``.
    ``CommitteeAssignment.committee`` is the tuple array of validators in the committee
    ``CommitteeAssignment.shard`` is the shard to which the committee is assigned
    ``CommitteeAssignment.slot`` is the slot at which the committee is assigned
    ``CommitteeAssignment.is_proposer`` is a bool signalling if the validator is expected to
        propose a beacon block at the assigned slot.
    """
    next_epoch = state.next_epoch(config.SLOTS_PER_EPOCH)
    if epoch > next_epoch:
        raise ValidationError(
            f"Epoch for committee assignment ({epoch}) must not be after next epoch {next_epoch}."
        )

    active_validators = get_active_validator_indices(state.validators, epoch)
    committees_per_slot = (
        get_committee_count(
            len(active_validators),
            config.SHARD_COUNT,
            config.SLOTS_PER_EPOCH,
            config.TARGET_COMMITTEE_SIZE,
        )
        // config.SLOTS_PER_EPOCH
    )
    epoch_start_slot = compute_start_slot_of_epoch(epoch, config.SLOTS_PER_EPOCH)
    epoch_start_shard = get_start_shard(state, epoch, CommitteeConfig(config))

    for slot in range(epoch_start_slot, epoch_start_slot + config.SLOTS_PER_EPOCH):
        offset = committees_per_slot * (slot % config.SLOTS_PER_EPOCH)
        slot_start_shard = (epoch_start_shard + offset) % config.SHARD_COUNT
        for i in range(committees_per_slot):
            shard = Shard((slot_start_shard + i) % config.SHARD_COUNT)
            committee = get_crosslink_committee(
                state, epoch, shard, CommitteeConfig(config)
            )
            if validator_index in committee:
                is_proposer = validator_index == get_beacon_proposer_index(
                    state.copy(slot=slot), CommitteeConfig(config)
                )
                return CommitteeAssignment(
                    committee, Shard(shard), Slot(slot), is_proposer
                )

    raise NoCommitteeAssignment
Пример #11
0
def test_get_crosslink_committee(genesis_state, config):
    indices = tuple()
    for shard in range(
            get_shard_delta(genesis_state, config.GENESIS_EPOCH,
                            CommitteeConfig(config))):
        some_committee = get_crosslink_committee(
            genesis_state,
            genesis_state.current_epoch(config.SLOTS_PER_EPOCH),
            genesis_state.start_shard + shard,
            CommitteeConfig(config),
        )
        indices += tuple(some_committee)

    assert set(indices) == set(range(len(genesis_state.validators)))
    assert len(indices) == len(genesis_state.validators)
Пример #12
0
def _find_collision(state, config, index, epoch):
    """
    Given a target epoch, make the attestation expected for the
    validator w/ the given index.
    """
    active_validators = get_active_validator_indices(state.validators, epoch)
    committees_per_slot = get_committee_count(
        len(active_validators),
        config.SHARD_COUNT,
        config.SLOTS_PER_EPOCH,
        config.TARGET_COMMITTEE_SIZE,
    ) // config.SLOTS_PER_EPOCH
    epoch_start_slot = compute_start_slot_of_epoch(
        epoch,
        config.SLOTS_PER_EPOCH,
    )
    epoch_start_shard = get_start_shard(state, epoch, CommitteeConfig(config))

    for slot in range(epoch_start_slot, epoch_start_slot + config.SLOTS_PER_EPOCH):
        offset = committees_per_slot * (slot % config.SLOTS_PER_EPOCH)
        slot_start_shard = (epoch_start_shard + offset) % config.SHARD_COUNT
        for i in range(committees_per_slot):
            shard = Shard((slot_start_shard + i) % config.SHARD_COUNT)
            committee = get_crosslink_committee(state, epoch, shard, CommitteeConfig(config))
            if index in committee:
                # TODO(ralexstokes) refactor w/ tools/builder
                attestation_data = AttestationData(
                    target=Checkpoint(
                        epoch=epoch,
                    ),
                    crosslink=Crosslink(
                        shard=shard,
                    ),
                )
                committee_count = len(committee)
                aggregation_bits = bitfield.get_empty_bitfield(committee_count)
                for i in range(committee_count):
                    aggregation_bits = bitfield.set_voted(aggregation_bits, i)

                return {
                    index: (
                        slot, (aggregation_bits, attestation_data)
                    )
                    for index in committee
                }
    else:
        raise Exception("should have found a duplicate validator")
Пример #13
0
def _mk_some_pending_attestations_with_some_participation_in_epoch(
        state: BeaconState, epoch: Epoch, config: Eth2Config,
        participation_ratio: float,
        number_of_shards_to_check: int) -> Iterable[PendingAttestation]:
    block_root = get_block_root(
        state,
        epoch,
        config.SLOTS_PER_EPOCH,
        config.SLOTS_PER_HISTORICAL_ROOT,
    )
    epoch_start_shard = get_epoch_start_shard(
        state,
        epoch,
        CommitteeConfig(config),
    )

    if epoch == state.current_epoch(config.SLOTS_PER_EPOCH):
        parent_crosslinks = state.current_crosslinks
    else:
        parent_crosslinks = state.previous_crosslinks

    for shard in range(epoch_start_shard,
                       epoch_start_shard + number_of_shards_to_check):
        shard = Shard(shard % config.SHARD_COUNT)
        crosslink_committee = get_crosslink_committee(
            state,
            epoch,
            shard,
            CommitteeConfig(config),
        )
        if not crosslink_committee:
            continue

        participants_count = math.ceil(participation_ratio *
                                       len(crosslink_committee))
        if not participants_count:
            return tuple()

        yield mk_pending_attestation_from_committee(
            parent_crosslinks[shard],
            participants_count,
            shard,
            target_epoch=epoch,
            target_root=block_root,
        )
Пример #14
0
def get_crosslink_committees_at_slot(
    state: BeaconState, slot: Slot, config: Eth2Config
) -> Tuple[Tuple[Tuple[ValidatorIndex, ...], Shard], ...]:
    epoch = slot_to_epoch(slot, config.SLOTS_PER_EPOCH)
    active_validators = get_active_validator_indices(state.validators, epoch)
    committees_per_slot = get_epoch_committee_count(
        len(active_validators),
        config.SHARD_COUNT,
        config.SLOTS_PER_EPOCH,
        config.TARGET_COMMITTEE_SIZE,
    ) // config.SLOTS_PER_EPOCH
    results = []
    offset = committees_per_slot * (slot % config.SLOTS_PER_EPOCH)
    slot_start_shard = Shard(
        (get_epoch_start_shard(state, epoch, CommitteeConfig(config)) + offset)
        % config.SHARD_COUNT)
    for i in range(committees_per_slot):
        shard = (slot_start_shard + i) % config.SHARD_COUNT
        committee = get_crosslink_committee(state, epoch, shard,
                                            CommitteeConfig(config))
        results.append((committee, Shard(shard)))

    return tuple(results)
Пример #15
0
def test_find_candidate_attestations_for_shard(genesis_state, config):
    some_epoch = config.GENESIS_EPOCH + 20
    # start on some shard and walk a subset of them
    some_shard = 3
    shard_offset = 24

    state = genesis_state.copy(
        slot=compute_start_slot_of_epoch(some_epoch, config.SLOTS_PER_EPOCH),
        start_shard=some_shard,
        current_crosslinks=tuple(
            Crosslink(shard=i, data_root=(i).to_bytes(32, "little"))
            for i in range(config.SHARD_COUNT)),
    )

    # sample a subset of the shards to make attestations for
    some_shards_with_attestations = random.sample(
        range(some_shard, some_shard + shard_offset), shard_offset // 2)

    committee_and_shard_pairs = tuple(
        (
            get_crosslink_committee(state, some_epoch, some_shard +
                                    i, CommitteeConfig(config)),
            some_shard + i,
        ) for i in range(shard_offset)
        if some_shard + i in some_shards_with_attestations)

    pending_attestations = {
        shard:
        mk_pending_attestation_from_committee(state.current_crosslinks[shard],
                                              len(committee), shard)
        for committee, shard in committee_and_shard_pairs
    }

    # invalidate some crosslinks to test the crosslink filter
    some_crosslinks_to_mangle = random.sample(
        some_shards_with_attestations,
        len(some_shards_with_attestations) // 2)

    shards_with_valid_crosslinks = set(some_shards_with_attestations) - set(
        some_crosslinks_to_mangle)

    crosslinks = tuple()
    for shard in range(config.SHARD_COUNT):
        if shard in shards_with_valid_crosslinks:
            crosslinks += (state.current_crosslinks[shard], )
        else:
            crosslinks += (Crosslink(), )

    state = state.copy(current_crosslinks=crosslinks)

    # check around the range of shards we built up
    for shard in range(0, some_shard + shard_offset + 3):
        if shard in some_shards_with_attestations:
            attestations = _get_attestations_for_shard(
                pending_attestations.values(), shard)
            assert attestations == (pending_attestations[shard], )

            if shard in some_crosslinks_to_mangle:
                assert not _get_attestations_for_valid_crosslink(
                    pending_attestations.values(), state, shard, config)
            else:
                attestations = _get_attestations_for_valid_crosslink(
                    pending_attestations.values(), state, shard, config)
                assert attestations == (pending_attestations[shard], )
        else:
            assert not _get_attestations_for_shard(
                pending_attestations.values(), shard)
            assert not _get_attestations_for_valid_crosslink(
                pending_attestations.values(), state, shard, config)