Exemplo n.º 1
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
Exemplo n.º 2
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
Exemplo n.º 3
0
def test_get_winning_root(random, monkeypatch, target_committee_size,
                          block_root_1_participants, block_root_2_participants,
                          config, committee_config, n_validators_state,
                          sample_attestation_data_params,
                          sample_attestation_params):
    shard = 1
    committee = tuple([i for i in range(target_committee_size)])

    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)

    competing_block_roots = [
        hash_eth2(bytearray(random.getrandbits(8) for _ in range(10))),
        hash_eth2(bytearray(random.getrandbits(8) for _ in range(10)))
    ]

    # Generate bitfield of each participants set
    root_1_participants_bitfield = get_aggregation_bitfield(
        block_root_1_participants,
        target_committee_size,
    )
    root_2_participants_bitfield = get_aggregation_bitfield(
        block_root_2_participants,
        target_committee_size,
    )
    # `attestions` contains attestation to different block root by different set of participants
    attestations = (
        # Attestation to `crosslink_data_root_1` by `attestation_participants_1`
        Attestation(**sample_attestation_params).copy(
            aggregation_bitfield=root_1_participants_bitfield,
            data=AttestationData(**sample_attestation_data_params).copy(
                shard=shard,
                crosslink_data_root=competing_block_roots[0],
            ),
        ),
        # Attestation to `crosslink_data_root_2` by `attestation_participants_2`
        Attestation(**sample_attestation_params).copy(
            aggregation_bitfield=root_2_participants_bitfield,
            data=AttestationData(**sample_attestation_data_params).copy(
                shard=shard,
                crosslink_data_root=competing_block_roots[1],
            ),
        ),
    )

    try:
        winning_root, attesting_balance = get_winning_root(
            state=n_validators_state,
            shard=shard,
            attestations=attestations,
            max_deposit_amount=config.MAX_DEPOSIT_AMOUNT,
            committee_config=committee_config,
        )
        attesting_validators_indices = get_attester_indices_from_attesttion(
            state=n_validators_state,
            attestations=(a for a in attestations if a.data.shard == shard
                          and a.data.crosslink_data_root == winning_root),
            committee_config=committee_config,
        )
        total_attesting_balance = get_total_balance(
            n_validators_state.validator_balances,
            attesting_validators_indices,
            config.MAX_DEPOSIT_AMOUNT,
        )
        assert attesting_balance == total_attesting_balance
    except NoWinningRootError:
        assert len(block_root_1_participants) == 0 and len(
            block_root_2_participants) == 0
    else:
        if len(block_root_1_participants) == len(block_root_2_participants):
            if competing_block_roots[0] < competing_block_roots[1]:
                assert winning_root == competing_block_roots[0]
            else:
                assert winning_root == competing_block_roots[1]
        elif len(block_root_1_participants) < len(block_root_2_participants):
            assert winning_root == competing_block_roots[1]
        else:
            assert winning_root == competing_block_roots[0]
Exemplo n.º 4
0
def test_get_winning_root(
        random,
        monkeypatch,
        target_committee_size,
        block_root_1_participants,
        block_root_2_participants,
        config,
        committee_config,
        n_validators_state,
        sample_attestation_data_params,
        sample_attestation_params):
    shard = 1
    committee = tuple([i for i in range(target_committee_size)])

    from eth2.beacon import committee_helpers

    def mock_get_crosslink_committees_at_slot(state,
                                              slot,
                                              committee_config):
        return (
            (committee, shard,),
        )

    monkeypatch.setattr(
        committee_helpers,
        'get_crosslink_committees_at_slot',
        mock_get_crosslink_committees_at_slot
    )

    competing_block_roots = [
        hash_eth2(bytearray(random.getrandbits(8) for _ in range(10))),
        hash_eth2(bytearray(random.getrandbits(8) for _ in range(10)))
    ]

    # Generate bitfield of each participants set
    root_1_participants_bitfield = get_empty_bitfield(target_committee_size)
    root_2_participants_bitfield = get_empty_bitfield(target_committee_size)
    for i in block_root_1_participants:
        root_1_participants_bitfield = set_voted(root_1_participants_bitfield, i)
    for i in block_root_2_participants:
        root_2_participants_bitfield = set_voted(root_2_participants_bitfield, i)

    # `attestions` contains attestation to different block root by different set of participants
    attestations = [
        # Attestation to `shard_block_root_1` by `attestation_participants_1`
        Attestation(**sample_attestation_params).copy(
            data=AttestationData(**sample_attestation_data_params).copy(
                shard=shard,
                shard_block_root=competing_block_roots[0],
            ),
            aggregation_bitfield=root_1_participants_bitfield
        ),
        # Attestation to `shard_block_root_2` by `attestation_participants_2`
        Attestation(**sample_attestation_params).copy(
            data=AttestationData(**sample_attestation_data_params).copy(
                shard=shard,
                shard_block_root=competing_block_roots[1],
            ),
            aggregation_bitfield=root_2_participants_bitfield
        ),
    ]

    try:
        winning_root, attesting_balance = get_winning_root(
            state=n_validators_state,
            shard=shard,
            attestations=attestations,
            max_deposit_amount=config.MAX_DEPOSIT_AMOUNT,
            committee_config=committee_config,
        )
        attesting_validators_indices = get_attesting_validator_indices(
            state=n_validators_state,
            attestations=attestations,
            shard=shard,
            shard_block_root=winning_root,
            committee_config=committee_config,
        )
        total_attesting_balance = sum(
            get_effective_balance(
                n_validators_state.validator_balances,
                i,
                config.MAX_DEPOSIT_AMOUNT
            )
            for i in attesting_validators_indices
        )
        assert attesting_balance == total_attesting_balance
    except NoWinningRootError:
        assert len(block_root_1_participants) == 0 and len(block_root_2_participants) == 0
    else:
        if len(block_root_1_participants) == len(block_root_2_participants):
            root_1_as_int = big_endian_to_int(competing_block_roots[0])
            root_2_as_int = big_endian_to_int(competing_block_roots[1])
            if root_1_as_int < root_2_as_int:
                assert winning_root == competing_block_roots[0]
            else:
                assert winning_root == competing_block_roots[1]
        elif len(block_root_1_participants) < len(block_root_2_participants):
            assert winning_root == competing_block_roots[1]
        else:
            assert winning_root == competing_block_roots[0]