Ejemplo n.º 1
0
def test_validate_attestation_aggregate_signature(genesis_state,
                                                  slots_per_epoch,
                                                  random,
                                                  sample_attestation_data_params,
                                                  is_valid,
                                                  target_committee_size,
                                                  shard_count,
                                                  keymap,
                                                  committee_config):
    state = genesis_state

    # choose committee
    slot = 0
    crosslink_committee = get_crosslink_committees_at_slot(
        state=state,
        slot=slot,
        committee_config=committee_config,
    )[0]
    committee, shard = crosslink_committee
    committee_size = len(committee)
    assert committee_size > 0

    # randomly select 3/4 participants from committee
    votes_count = len(committee) * 3 // 4
    assert votes_count > 0

    attestation_data = AttestationData(**sample_attestation_data_params).copy(
        slot=slot,
        shard=shard,
    )

    attestation = create_mock_signed_attestation(
        state,
        attestation_data,
        committee,
        votes_count,
        keymap,
        slots_per_epoch,
    )

    if is_valid:
        validate_attestation_aggregate_signature(
            state,
            attestation,
            committee_config,
        )
    else:
        # mess up signature
        attestation = attestation.copy(
            aggregate_signature=(
                attestation.aggregate_signature[0] + 10,
                attestation.aggregate_signature[1] - 1
            )
        )
        with pytest.raises(ValidationError):
            validate_attestation_aggregate_signature(
                state,
                attestation,
                committee_config,
            )
Ejemplo n.º 2
0
def create_mock_signed_attestations_at_slot(
        state: BeaconState,
        config: Eth2Config,
        attestation_slot: Slot,
        beacon_block_root: Hash32,
        keymap: Dict[BLSPubkey, int],
        voted_attesters_ratio: float=1.0) -> Iterable[Attestation]:
    """
    Create the mocking attestations of the given ``attestation_slot`` slot with ``keymap``.
    """
    slots_per_epoch = config.SLOTS_PER_EPOCH

    crosslink_committees_at_slot = get_crosslink_committees_at_slot(
        # To avoid the epoch boundary cases
        state.copy(
            slot=state.slot + 1,
        ),
        attestation_slot,
        CommitteeConfig(config),
    )

    # Get `target_root`
    target_root = _get_target_root(state, config, beacon_block_root)

    # Get `source_root`
    source_root = get_block_root(
        state,
        get_epoch_start_slot(state.justified_epoch, slots_per_epoch),
        config.SLOTS_PER_HISTORICAL_ROOT,
    )

    for crosslink_committee in crosslink_committees_at_slot:
        committee, shard = crosslink_committee

        num_voted_attesters = int(len(committee) * voted_attesters_ratio)
        previous_crosslink = state.latest_crosslinks[shard]

        attestation_data = AttestationData(
            slot=attestation_slot,
            beacon_block_root=beacon_block_root,
            source_epoch=state.justified_epoch,
            source_root=source_root,
            target_root=target_root,
            shard=shard,
            previous_crosslink=previous_crosslink,
            crosslink_data_root=ZERO_HASH32,
        )

        num_voted_attesters = int(len(committee) * voted_attesters_ratio)

        yield create_mock_signed_attestation(
            state,
            attestation_data,
            committee,
            num_voted_attesters,
            keymap,
            config.SLOTS_PER_EPOCH,
        )
Ejemplo n.º 3
0
def _process_rewards_and_penalties_for_crosslinks(
    state: BeaconState, config: Eth2Config,
    effective_balances: Dict[ValidatorIndex,
                             Gwei], base_rewards: Dict[ValidatorIndex, Gwei]
) -> Tuple[Dict[ValidatorIndex, Gwei], Dict[ValidatorIndex,
                                            Gwei]]:  # noqa: E501
    previous_epoch_start_slot = get_epoch_start_slot(
        state.previous_epoch(config.SLOTS_PER_EPOCH),
        config.SLOTS_PER_EPOCH,
    )
    current_epoch_start_slot = get_epoch_start_slot(
        state.current_epoch(config.SLOTS_PER_EPOCH),
        config.SLOTS_PER_EPOCH,
    )
    rewards_received = {
        ValidatorIndex(index): Gwei(0)
        for index in range(len(state.validator_registry))
    }
    penalties_received = rewards_received.copy()
    for slot in range(previous_epoch_start_slot, current_epoch_start_slot):
        crosslink_committees_at_slot = get_crosslink_committees_at_slot(
            state,
            slot,
            CommitteeConfig(config),
        )
        for crosslink_committee, shard in crosslink_committees_at_slot:
            winning_root, attesting_validator_indices = get_winning_root_and_participants(
                state=state,
                shard=shard,
                effective_balances=effective_balances,
                committee_config=CommitteeConfig(config),
            )
            total_attesting_balance = get_total_balance(
                state.validator_balances,
                attesting_validator_indices,
                config.MAX_DEPOSIT_AMOUNT,
            )
            total_balance = get_total_balance_from_effective_balances(
                effective_balances,
                crosslink_committee,
            )
            for index in attesting_validator_indices:
                rewards_received = _update_rewards_or_penalies(
                    index,
                    base_rewards[index] * total_attesting_balance //
                    total_balance,
                    rewards_received,
                )
            for index in set(crosslink_committee).difference(
                    attesting_validator_indices):
                penalties_received = _update_rewards_or_penalies(
                    index,
                    base_rewards[index],
                    penalties_received,
                )
    return (rewards_received, penalties_received)
Ejemplo n.º 4
0
def create_mock_signed_attestations_at_slot(
        state: BeaconState,
        config: Eth2Config,
        state_machine: BaseBeaconStateMachine,
        attestation_slot: Slot,
        beacon_block_root: Hash32,
        keymap: Dict[BLSPubkey, int],
        voted_attesters_ratio: float = 1.0) -> Iterable[Attestation]:
    """
    Create the mocking attestations of the given ``attestation_slot`` slot with ``keymap``.
    """
    state_transition = state_machine.state_transition
    state = state_transition.apply_state_transition_without_block(
        state,
        attestation_slot,
    )
    crosslink_committees_at_slot = get_crosslink_committees_at_slot(
        state,
        attestation_slot,
        CommitteeConfig(config),
    )

    # Get `target_root`
    target_root = _get_target_root(state, config, beacon_block_root)

    for crosslink_committee in crosslink_committees_at_slot:
        committee, shard = crosslink_committee

        num_voted_attesters = int(len(committee) * voted_attesters_ratio)
        previous_crosslink = state.latest_crosslinks[shard]

        attestation_data = AttestationData(
            slot=attestation_slot,
            beacon_block_root=beacon_block_root,
            source_epoch=state.current_justified_epoch,
            source_root=state.current_justified_root,
            target_root=target_root,
            shard=shard,
            previous_crosslink=previous_crosslink,
            crosslink_data_root=ZERO_HASH32,
        )

        num_voted_attesters = int(len(committee) * voted_attesters_ratio)

        yield create_mock_signed_attestation(
            state,
            attestation_data,
            committee,
            num_voted_attesters,
            keymap,
            config.SLOTS_PER_EPOCH,
        )
Ejemplo n.º 5
0
def get_committee_assignment(
        state: BeaconState,
        config: BeaconConfig,
        epoch: Epoch,
        validator_index: ValidatorIndex,
        registry_change: bool = False) -> CommitteeAssignment:
    """
    Return the ``CommitteeAssignment`` in the ``epoch`` for ``validator_index``
    and ``registry_change``.
    ``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.
    """
    current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH)
    previous_epoch = state.previous_epoch(config.SLOTS_PER_EPOCH,
                                          config.GENESIS_EPOCH)
    next_epoch = Epoch(current_epoch + 1)

    validate_epoch_within_previous_and_next(epoch, previous_epoch, next_epoch)

    epoch_start_slot = get_epoch_start_slot(epoch, config.SLOTS_PER_EPOCH)

    committee_config = CommitteeConfig(config)

    for slot in range(epoch_start_slot,
                      epoch_start_slot + config.SLOTS_PER_EPOCH):
        crosslink_committees = get_crosslink_committees_at_slot(
            state,
            slot,
            committee_config,
            registry_change=registry_change,
        )
        selected_committees = [
            committee for committee in crosslink_committees
            if validator_index in committee[0]
        ]
        if len(selected_committees) > 0:
            validators = selected_committees[0][0]
            shard = selected_committees[0][1]
            is_proposer = validator_index == get_beacon_proposer_index(
                state,
                Slot(slot),
                committee_config,
                registry_change=registry_change,
            )

            return CommitteeAssignment(validators, shard, Slot(slot),
                                       is_proposer)

    raise NoCommitteeAssignment
Ejemplo n.º 6
0
def create_mock_signed_attestations_at_slot(
        state: BeaconState,
        config: BeaconConfig,
        attestation_slot: SlotNumber,
        keymap: Dict[BLSPubkey, int],
        voted_attesters_ratio: float=1.0) -> Iterable[Attestation]:
    """
    Create the mocking attestations of the given ``attestation_slot`` slot with ``keymap``.
    """
    crosslink_committees_at_slot = get_crosslink_committees_at_slot(
        state.copy(
            slot=state.slot + 1,
        ),
        slot=attestation_slot,
        genesis_epoch=config.GENESIS_EPOCH,
        epoch_length=config.EPOCH_LENGTH,
        target_committee_size=config.TARGET_COMMITTEE_SIZE,
        shard_count=config.SHARD_COUNT,
    )
    for crosslink_committee in crosslink_committees_at_slot:
        committee, shard = crosslink_committee

        num_voted_attesters = int(len(committee) * voted_attesters_ratio)
        latest_crosslink_root = state.latest_crosslinks[shard].shard_block_root

        attestation_data = AttestationData(
            slot=attestation_slot,
            shard=shard,
            beacon_block_root=ZERO_HASH32,
            epoch_boundary_root=ZERO_HASH32,
            shard_block_root=ZERO_HASH32,
            latest_crosslink_root=latest_crosslink_root,
            justified_epoch=state.previous_justified_epoch,
            justified_block_root=get_block_root(
                state,
                get_epoch_start_slot(state.previous_justified_epoch, config.EPOCH_LENGTH),
                config.LATEST_BLOCK_ROOTS_LENGTH,
            ),
        )

        yield create_mock_signed_attestation(
            state,
            attestation_data,
            committee,
            num_voted_attesters,
            keymap,
            config.EPOCH_LENGTH,
        )
Ejemplo n.º 7
0
def test_get_crosslink_committees_at_slot(n_validators_state, current_slot,
                                          slot, epoch_length,
                                          target_committee_size, shard_count,
                                          genesis_epoch):

    state = n_validators_state.copy(slot=current_slot, )

    crosslink_committees_at_slot = get_crosslink_committees_at_slot(
        state=state,
        slot=slot,
        genesis_epoch=genesis_epoch,
        epoch_length=epoch_length,
        target_committee_size=target_committee_size,
        shard_count=shard_count,
    )
    assert len(crosslink_committees_at_slot) > 0
    for crosslink_committee in crosslink_committees_at_slot:
        committee, shard = crosslink_committee
        assert len(committee) > 0
        assert shard < shard_count
Ejemplo n.º 8
0
def get_next_epoch_committee_assignment(
        state: BeaconState, config: BeaconConfig,
        validator_index: ValidatorIndex,
        registry_change: bool) -> CommitteeAssignment:
    """
    Return the ``CommitteeAssignment`` in the next epoch for ``validator_index``
    and ``registry_change``.
    ``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.
    """
    current_epoch = state.current_epoch(config.EPOCH_LENGTH)
    next_epoch = current_epoch + 1
    next_epoch_start_slot = get_epoch_start_slot(next_epoch,
                                                 config.EPOCH_LENGTH)
    for slot in range(next_epoch_start_slot,
                      next_epoch_start_slot + config.EPOCH_LENGTH):
        crosslink_committees = get_crosslink_committees_at_slot(
            state,
            slot,
            CommitteeConfig(config),
            registry_change=registry_change,
        )
        selected_committees = [
            committee for committee in crosslink_committees
            if validator_index in committee[0]
        ]
        if len(selected_committees) > 0:
            validators = selected_committees[0][0]
            shard = selected_committees[0][1]
            first_committee_at_slot = crosslink_committees[0][
                0]  # List[ValidatorIndex]
            is_proposer = first_committee_at_slot[
                slot % len(first_committee_at_slot)] == validator_index

            return CommitteeAssignment(validators, shard, slot, is_proposer)

    raise NoCommitteeAssignment
Ejemplo n.º 9
0
def test_get_crosslink_committees_at_slot(
        monkeypatch, genesis_slot, n_validators_state, current_slot, slot,
        slots_per_epoch, target_committee_size, shard_count, genesis_epoch,
        committee_config, registry_change, should_reseed,
        previous_shuffling_epoch, current_shuffling_epoch, shuffling_epoch):
    # Mock generate_seed
    new_seed = b'\x88' * 32

    def mock_generate_seed(state, epoch, committee_config):
        return new_seed

    monkeypatch.setattr('eth2.beacon.helpers.generate_seed',
                        mock_generate_seed)

    state = n_validators_state.copy(
        slot=current_slot,
        previous_shuffling_epoch=previous_shuffling_epoch,
        current_shuffling_epoch=current_shuffling_epoch,
        previous_shuffling_seed=b'\x11' * 32,
        current_shuffling_seed=b'\x22' * 32,
    )

    crosslink_committees_at_slot = get_crosslink_committees_at_slot(
        state=state,
        slot=slot,
        committee_config=committee_config,
        registry_change=registry_change,
    )
    assert len(crosslink_committees_at_slot) > 0
    for crosslink_committee in crosslink_committees_at_slot:
        committee, shard = crosslink_committee
        assert len(committee) > 0
        assert shard < shard_count

    #
    # Check shuffling_start_shard
    #
    offset = slot % slots_per_epoch

    result_slot_start_shard = crosslink_committees_at_slot[0][1]

    current_committees_per_epoch = get_current_epoch_committee_count(
        state=state,
        shard_count=shard_count,
        slots_per_epoch=slots_per_epoch,
        target_committee_size=target_committee_size,
    )

    if registry_change:
        committees_per_epoch = current_committees_per_epoch
        shuffling_start_shard = (state.current_shuffling_start_shard +
                                 current_committees_per_epoch) % shard_count
    elif should_reseed:
        committees_per_epoch = get_next_epoch_committee_count(
            state=state,
            shard_count=shard_count,
            slots_per_epoch=slots_per_epoch,
            target_committee_size=target_committee_size,
        )
        shuffling_start_shard = state.current_shuffling_start_shard
    else:
        committees_per_epoch = current_committees_per_epoch
        shuffling_start_shard = state.current_shuffling_start_shard

    committees_per_slot = committees_per_epoch // slots_per_epoch
    assert result_slot_start_shard == (
        shuffling_start_shard + committees_per_slot * offset) % shard_count

    #
    # Check seed
    #
    epoch = slot_to_epoch(slot, slots_per_epoch)
    current_epoch = state.current_epoch(slots_per_epoch)
    previous_epoch = state.previous_epoch(slots_per_epoch)
    next_epoch = current_epoch + 1

    if epoch == current_epoch:
        seed = state.current_shuffling_seed
    elif epoch == previous_epoch:
        seed = state.previous_shuffling_seed
    elif epoch == next_epoch:
        if registry_change or should_reseed:
            seed = new_seed
        else:
            seed = state.current_shuffling_seed

    shuffling = get_shuffling(
        seed=seed,
        validators=state.validator_registry,
        epoch=shuffling_epoch,
        committee_config=committee_config,
    )
    assert shuffling[committees_per_slot *
                     offset] == crosslink_committees_at_slot[0][0]
Ejemplo n.º 10
0
def process_crosslinks(state: BeaconState, config: BeaconConfig) -> BeaconState:
    """
    Implement 'per-epoch-processing.crosslinks' portion of Phase 0 spec:
    https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#crosslinks

    For each shard from the past two epochs, find the shard block
    root that has been attested to by the most stake.
    If enough(>= 2/3 total stake) attesting stake, update the crosslink record of that shard.
    Return resulting ``state``
    """
    latest_crosslinks = state.latest_crosslinks
    previous_epoch_attestations = get_previous_epoch_attestations(
        state,
        config.EPOCH_LENGTH,
        config.GENESIS_EPOCH,
    )
    current_epoch_attestations = get_current_epoch_attestations(state, config.EPOCH_LENGTH)
    prev_epoch_start_slot = get_epoch_start_slot(
        state.previous_epoch(config.EPOCH_LENGTH, config.GENESIS_EPOCH),
        config.EPOCH_LENGTH,
    )
    next_epoch_start_slot = get_epoch_start_slot(
        state.next_epoch(config.EPOCH_LENGTH),
        config.EPOCH_LENGTH,
    )
    for slot in range(prev_epoch_start_slot, next_epoch_start_slot):
        crosslink_committees_at_slot = get_crosslink_committees_at_slot(
            state,
            slot,
            CommitteeConfig(config),
        )
        for crosslink_committee, shard in crosslink_committees_at_slot:
            try:
                winning_root, total_attesting_balance = get_winning_root(
                    state=state,
                    shard=shard,
                    # Use `_filter_attestations_by_shard` to filter out attestations
                    # not attesting to this shard so we don't need to going over
                    # irrelevent attestations over and over again.
                    attestations=_filter_attestations_by_shard(
                        previous_epoch_attestations + current_epoch_attestations,
                        shard,
                    ),
                    max_deposit_amount=config.MAX_DEPOSIT_AMOUNT,
                    committee_config=CommitteeConfig(config),
                )
            except NoWinningRootError:
                # No winning shard block root found for this shard.
                pass
            else:
                total_balance = sum(
                    get_effective_balance(state.validator_balances, i, config.MAX_DEPOSIT_AMOUNT)
                    for i in crosslink_committee
                )
                if 3 * total_attesting_balance >= 2 * total_balance:
                    latest_crosslinks = update_tuple_item(
                        latest_crosslinks,
                        shard,
                        CrosslinkRecord(
                            epoch=state.current_epoch(config.EPOCH_LENGTH),
                            shard_block_root=winning_root,
                        ),
                    )
                else:
                    # Don't update the crosslink of this shard
                    pass
    state = state.copy(
        latest_crosslinks=latest_crosslinks,
    )
    return state
Ejemplo n.º 11
0
def _process_rewards_and_penalties_for_crosslinks(
    state: BeaconState, config: BeaconConfig,
    previous_epoch_attestations: Iterable[PendingAttestationRecord],
    effective_balances: Dict[ValidatorIndex,
                             Gwei], base_rewards: Dict[ValidatorIndex, Gwei],
    old_rewards_received: Dict[ValidatorIndex, SignedGwei]
) -> Dict[ValidatorIndex, SignedGwei]:
    rewards_received = old_rewards_received.copy()
    previous_epoch_start_slot = get_epoch_start_slot(
        state.previous_epoch(config.SLOTS_PER_EPOCH, config.GENESIS_EPOCH),
        config.SLOTS_PER_EPOCH,
    )
    current_epoch_start_slot = get_epoch_start_slot(
        state.current_epoch(config.SLOTS_PER_EPOCH),
        config.SLOTS_PER_EPOCH,
    )
    # Also need current epoch attestations to compute the winning root.
    current_epoch_attestations = get_current_epoch_attestations(
        state, config.SLOTS_PER_EPOCH)
    for slot in range(previous_epoch_start_slot, current_epoch_start_slot):
        crosslink_committees_at_slot = get_crosslink_committees_at_slot(
            state,
            slot,
            CommitteeConfig(config),
        )
        for crosslink_committee, shard in crosslink_committees_at_slot:
            filtered_attestations = _filter_attestations_by_shard(
                previous_epoch_attestations + current_epoch_attestations,
                shard,
            )
            try:
                winning_root, total_attesting_balance = get_winning_root(
                    state=state,
                    shard=shard,
                    attestations=filtered_attestations,
                    max_deposit_amount=config.MAX_DEPOSIT_AMOUNT,
                    committee_config=CommitteeConfig(config),
                )
            except NoWinningRootError:
                # No winning shard block root found for this shard.
                # Hence no one is counted as attesting validator.
                attesting_validator_indices: Iterable[ValidatorIndex] = set()
            else:
                attesting_validator_indices = get_attester_indices_from_attesttion(
                    state=state,
                    attestations=(a for a in filtered_attestations
                                  if a.data.shard == shard and
                                  a.data.crosslink_data_root == winning_root),
                    committee_config=CommitteeConfig(config),
                )
            total_balance = get_total_balance_from_effective_balances(
                effective_balances,
                crosslink_committee,
            )
            for index in attesting_validator_indices:
                reward = base_rewards[
                    index] * total_attesting_balance // total_balance
                rewards_received[index] = SignedGwei(rewards_received[index] +
                                                     reward)
            for index in set(crosslink_committee).difference(
                    attesting_validator_indices):
                penalty = base_rewards[index]
                rewards_received[index] = SignedGwei(rewards_received[index] -
                                                     penalty)
    return rewards_received
def test_process_rewards_and_penalties_for_crosslinks(
        random,
        n_validators_state,
        config,
        slots_per_epoch,
        target_committee_size,
        shard_count,
        current_slot,
        num_attesting_validators,
        max_deposit_amount,
        min_attestation_inclusion_delay,
        sample_attestation_data_params,
        sample_pending_attestation_record_params):
    previous_epoch = current_slot // slots_per_epoch - 1
    state = n_validators_state.copy(
        slot=current_slot,
    )
    # Compute previous epoch committees
    prev_epoch_start_slot = get_epoch_start_slot(previous_epoch, slots_per_epoch)
    prev_epoch_crosslink_committees = [
        get_crosslink_committees_at_slot(
            state,
            slot,
            CommitteeConfig(config),
        )[0] for slot in range(prev_epoch_start_slot, prev_epoch_start_slot + slots_per_epoch)
    ]

    # Record which validators attest during each slot for reward collation.
    each_slot_attestion_validators_list = []

    previous_epoch_attestations = []
    for i in range(slots_per_epoch):
        committee, shard = prev_epoch_crosslink_committees[i]
        # Randomly sample `num_attesting_validators` validators
        # from the committee to attest in this slot.
        crosslink_data_root_attesting_validators = random.sample(
            committee,
            num_attesting_validators,
        )
        each_slot_attestion_validators_list.append(crosslink_data_root_attesting_validators)
        participants_bitfield = get_empty_bitfield(target_committee_size)
        for index in crosslink_data_root_attesting_validators:
            participants_bitfield = set_voted(participants_bitfield, committee.index(index))
        data_slot = i + previous_epoch * slots_per_epoch
        previous_epoch_attestations.append(
            PendingAttestationRecord(**sample_pending_attestation_record_params).copy(
                data=AttestationData(**sample_attestation_data_params).copy(
                    slot=data_slot,
                    shard=shard,
                ),
                aggregation_bitfield=participants_bitfield,
                slot_included=(data_slot + min_attestation_inclusion_delay),
            )
        )

    active_validators = set(
        [
            i for i in range(len(state.validator_registry))
        ]
    )

    effective_balances = {
        index: get_effective_balance(
            state.validator_balances,
            index,
            config.MAX_DEPOSIT_AMOUNT,
        )
        for index in active_validators
    }

    validator_balance = max_deposit_amount
    total_active_balance = len(active_validators) * validator_balance

    _base_reward_quotient = (
        integer_squareroot(total_active_balance) // config.BASE_REWARD_QUOTIENT
    )
    base_rewards = {
        index: get_base_reward(
            state=state,
            index=index,
            base_reward_quotient=_base_reward_quotient,
            max_deposit_amount=max_deposit_amount,
        )
        for index in active_validators
    }

    rewards_received = {
        index: 0
        for index in range(len(state.validator_registry))
    }

    rewards_received = _process_rewards_and_penalties_for_crosslinks(
        state,
        config,
        tuple(previous_epoch_attestations),
        effective_balances,
        base_rewards,
        rewards_received,
    )

    expected_rewards_received = {
        index: 0
        for index in range(len(state.validator_registry))
    }
    for i in range(slots_per_epoch):
        crosslink_committee, shard = prev_epoch_crosslink_committees[i]
        attesting_validators = each_slot_attestion_validators_list[i]
        total_attesting_balance = len(attesting_validators) * validator_balance
        total_committee_balance = len(crosslink_committee) * validator_balance
        _base_reward_quotient = (
            integer_squareroot(total_active_balance) // config.BASE_REWARD_QUOTIENT
        )
        for index in attesting_validators:
            reward = get_base_reward(
                state=state,
                index=index,
                base_reward_quotient=_base_reward_quotient,
                max_deposit_amount=max_deposit_amount,
            ) * total_attesting_balance // total_committee_balance
            expected_rewards_received[index] += reward
        for index in set(crosslink_committee).difference(attesting_validators):
            penalty = get_base_reward(
                state=state,
                index=index,
                base_reward_quotient=_base_reward_quotient,
                max_deposit_amount=max_deposit_amount,
            )
            expected_rewards_received[index] -= penalty

    # Check the rewards/penalties match
    for index, reward_received in rewards_received.items():
        assert rewards_received[index] == expected_rewards_received[index]
def test_process_rewards_and_penalties_for_finality(
        n_validators_state,
        config,
        slots_per_epoch,
        target_committee_size,
        shard_count,
        min_attestation_inclusion_delay,
        inactivity_penalty_quotient,
        finalized_epoch,
        current_slot,
        penalized_validator_indices,
        previous_epoch_active_validator_indices,
        previous_epoch_attester_indices,
        previous_epoch_boundary_head_attester_indices,
        inclusion_distances,
        effective_balance,
        base_reward,
        expected_rewards_received,
        sample_pending_attestation_record_params,
        sample_attestation_data_params):
    validator_registry = n_validators_state.validator_registry
    for index in penalized_validator_indices:
        validator_record = validator_registry[index].copy(
            slashed=True,
        )
        validator_registry = update_tuple_item(validator_registry, index, validator_record)
    state = n_validators_state.copy(
        slot=current_slot,
        finalized_epoch=finalized_epoch,
        validator_registry=validator_registry,
    )
    previous_total_balance = len(previous_epoch_active_validator_indices) * effective_balance

    attestation_slot = current_slot - slots_per_epoch
    inclusion_infos = {
        index: InclusionInfo(
            attestation_slot + inclusion_distances[index],
            attestation_slot,
        )
        for index in previous_epoch_attester_indices
    }

    effective_balances = {
        index: effective_balance
        for index in previous_epoch_active_validator_indices
    }

    base_rewards = {
        index: base_reward
        for index in previous_epoch_active_validator_indices
    }

    rewards_received = {
        index: 0
        for index in range(len(state.validator_registry))
    }

    prev_epoch_start_slot = get_epoch_start_slot(
        state.previous_epoch(config.SLOTS_PER_EPOCH, config.GENESIS_EPOCH), slots_per_epoch,
    )
    prev_epoch_crosslink_committees = [
        get_crosslink_committees_at_slot(
            state,
            slot,
            CommitteeConfig(config),
        )[0] for slot in range(prev_epoch_start_slot, prev_epoch_start_slot + slots_per_epoch)
    ]

    prev_epoch_attestations = []
    for i in range(slots_per_epoch):
        committee, shard = prev_epoch_crosslink_committees[i]
        participants_bitfield = get_empty_bitfield(target_committee_size)
        for index in previous_epoch_boundary_head_attester_indices:
            if index in committee:
                participants_bitfield = set_voted(participants_bitfield, committee.index(index))
        prev_epoch_attestations.append(
            PendingAttestationRecord(**sample_pending_attestation_record_params).copy(
                data=AttestationData(**sample_attestation_data_params).copy(
                    slot=(prev_epoch_start_slot + i),
                    shard=shard,
                    epoch_boundary_root=get_block_root(
                        state,
                        prev_epoch_start_slot,
                        config.LATEST_BLOCK_ROOTS_LENGTH,
                    ),
                    beacon_block_root=get_block_root(
                        state,
                        (prev_epoch_start_slot + i),
                        config.LATEST_BLOCK_ROOTS_LENGTH,
                    ),
                ),
                aggregation_bitfield=participants_bitfield,
            )
        )
    state = state.copy(
        latest_attestations=prev_epoch_attestations,
    )

    rewards_received = _process_rewards_and_penalties_for_finality(
        state,
        config,
        previous_epoch_active_validator_indices,
        previous_total_balance,
        prev_epoch_attestations,
        previous_epoch_attester_indices,
        inclusion_infos,
        effective_balances,
        base_rewards,
        rewards_received,
    )

    for index, reward_received in rewards_received.items():
        assert reward_received == expected_rewards_received[index]
def test_process_crosslinks(
        random,
        n_validators_state,
        config,
        slots_per_epoch,
        target_committee_size,
        shard_count,
        success_crosslink_in_cur_epoch,
        sample_attestation_data_params,
        sample_attestation_params):
    shard = 1
    crosslink_data_root = hash_eth2(b'crosslink_data_root')
    current_slot = config.SLOTS_PER_EPOCH * 2 - 1

    genesis_crosslinks = tuple([
        CrosslinkRecord(epoch=config.GENESIS_EPOCH, crosslink_data_root=ZERO_HASH32)
        for _ in range(shard_count)
    ])
    state = n_validators_state.copy(
        slot=current_slot,
        latest_crosslinks=genesis_crosslinks,
    )

    # Generate current epoch attestations
    cur_epoch_attestations = []
    for slot_in_cur_epoch in range(state.slot - config.SLOTS_PER_EPOCH, state.slot):
        if len(cur_epoch_attestations) > 0:
            break
        for committee, _shard in get_crosslink_committees_at_slot(
            state,
            slot_in_cur_epoch,
            CommitteeConfig(config),
        ):
            if _shard == shard:
                # Sample validators attesting to this shard.
                # Number of attesting validators sampled depends on `success_crosslink_in_cur_epoch`
                # if True, have >2/3 committee attest
                if success_crosslink_in_cur_epoch:
                    attesting_validators = random.sample(committee, (2 * len(committee) // 3 + 1))
                else:
                    attesting_validators = random.sample(committee, (2 * len(committee) // 3 - 1))
                # Generate the bitfield
                aggregation_bitfield = get_empty_bitfield(len(committee))
                for v_index in attesting_validators:
                    aggregation_bitfield = set_voted(
                        aggregation_bitfield, committee.index(v_index))
                # Generate the attestation
                cur_epoch_attestations.append(
                    Attestation(**sample_attestation_params).copy(
                        aggregation_bitfield=aggregation_bitfield,
                        data=AttestationData(**sample_attestation_data_params).copy(
                            slot=slot_in_cur_epoch,
                            shard=shard,
                            crosslink_data_root=crosslink_data_root,
                        ),
                    )
                )

    state = state.copy(
        latest_attestations=cur_epoch_attestations,
    )
    assert (state.latest_crosslinks[shard].epoch == config.GENESIS_EPOCH and
            state.latest_crosslinks[shard].crosslink_data_root == ZERO_HASH32)

    new_state = process_crosslinks(state, config)
    crosslink_record = new_state.latest_crosslinks[shard]
    if success_crosslink_in_cur_epoch:
        attestation = cur_epoch_attestations[0]
        assert (crosslink_record.epoch == slot_to_epoch(current_slot, slots_per_epoch) and
                crosslink_record.crosslink_data_root == attestation.data.crosslink_data_root and
                attestation.data.crosslink_data_root == crosslink_data_root)
    else:
        assert (crosslink_record.epoch == config.GENESIS_EPOCH and
                crosslink_record.crosslink_data_root == ZERO_HASH32)
Ejemplo n.º 15
0
def process_crosslinks(state: BeaconState, config: Eth2Config) -> BeaconState:
    """
    Implement 'per-epoch-processing.crosslinks' portion of Phase 0 spec:
    https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#crosslinks

    For each shard from the past two epochs, find the shard block
    root that has been attested to by the most stake.
    If enough(>= 2/3 total stake) attesting stake, update the crosslink record of that shard.
    Return resulting ``state``
    """
    latest_crosslinks = state.latest_crosslinks
    effective_balances = {
        ValidatorIndex(index): get_effective_balance(
            state.validator_balances,
            ValidatorIndex(index),
            config.MAX_DEPOSIT_AMOUNT,
        )
        for index in range(len(state.validator_registry))
    }
    previous_epoch_start_slot = get_epoch_start_slot(
        state.previous_epoch(config.SLOTS_PER_EPOCH),
        config.SLOTS_PER_EPOCH,
    )
    next_epoch_start_slot = get_epoch_start_slot(
        state.next_epoch(config.SLOTS_PER_EPOCH),
        config.SLOTS_PER_EPOCH,
    )
    for slot in range(previous_epoch_start_slot, next_epoch_start_slot):
        crosslink_committees_at_slot = get_crosslink_committees_at_slot(
            state,
            slot,
            CommitteeConfig(config),
        )
        for crosslink_committee, shard in crosslink_committees_at_slot:
            winning_root, attesting_validator_indices = get_winning_root_and_participants(
                state=state,
                shard=shard,
                effective_balances=effective_balances,
                committee_config=CommitteeConfig(config),
            )
            if len(attesting_validator_indices) > 0:
                total_attesting_balance = get_total_balance(
                    state.validator_balances,
                    attesting_validator_indices,
                    config.MAX_DEPOSIT_AMOUNT,
                )
                total_balance = get_total_balance(
                    state.validator_balances,
                    crosslink_committee,
                    config.MAX_DEPOSIT_AMOUNT,
                )
                if 3 * total_attesting_balance >= 2 * total_balance:
                    latest_crosslinks = update_tuple_item(
                        latest_crosslinks,
                        shard,
                        CrosslinkRecord(
                            epoch=slot_to_epoch(Slot(slot),
                                                config.SLOTS_PER_EPOCH),
                            crosslink_data_root=winning_root,
                        ),
                    )
    state = state.copy(latest_crosslinks=latest_crosslinks, )
    return state