Exemple #1
0
def test_get_block_root(sample_beacon_state_params, current_slot, target_slot,
                        success, slots_per_epoch, slots_per_historical_root,
                        sample_block):
    blocks, latest_block_roots = generate_mock_latest_historical_roots(
        sample_block,
        current_slot,
        slots_per_epoch,
        slots_per_historical_root,
    )
    state = BeaconState(**sample_beacon_state_params).copy(
        slot=current_slot,
        latest_block_roots=latest_block_roots,
    )

    if success:
        block_root = get_block_root(
            state,
            target_slot,
            slots_per_historical_root,
        )
        assert block_root == blocks[target_slot].root
    else:
        with pytest.raises(ValidationError):
            get_block_root(
                state,
                target_slot,
                slots_per_historical_root,
            )
def get_epoch_boundary_attesting_balances(
        current_epoch: Epoch, previous_epoch: Epoch, state: 'BeaconState',
        config: 'BeaconConfig') -> Tuple[Gwei, Gwei]:

    current_epoch_attestations = get_current_epoch_attestations(
        state, config.SLOTS_PER_EPOCH)
    previous_epoch_attestations = get_previous_epoch_attestations(
        state,
        config.SLOTS_PER_EPOCH,
        config.GENESIS_EPOCH,
    )

    previous_epoch_boundary_root = get_block_root(
        state,
        get_epoch_start_slot(previous_epoch, config.SLOTS_PER_EPOCH),
        config.LATEST_BLOCK_ROOTS_LENGTH,
    )

    previous_epoch_boundary_attester_indices = get_epoch_boundary_attester_indices(
        state,
        current_epoch_attestations + previous_epoch_attestations,
        state.previous_justified_epoch,
        previous_epoch_boundary_root,
        CommitteeConfig(config),
    )

    previous_epoch_boundary_attesting_balance = get_total_balance(
        state.validator_balances,
        previous_epoch_boundary_attester_indices,
        config.MAX_DEPOSIT_AMOUNT,
    )

    current_epoch_boundary_root = get_block_root(
        state,
        get_epoch_start_slot(current_epoch, config.SLOTS_PER_EPOCH),
        config.LATEST_BLOCK_ROOTS_LENGTH,
    )

    current_epoch_boundary_attester_indices = get_epoch_boundary_attester_indices(
        state,
        current_epoch_attestations,
        state.justified_epoch,
        current_epoch_boundary_root,
        CommitteeConfig(config),
    )

    current_epoch_boundary_attesting_balance = get_total_balance(
        state.validator_balances,
        current_epoch_boundary_attester_indices,
        config.MAX_DEPOSIT_AMOUNT,
    )
    return previous_epoch_boundary_attesting_balance, current_epoch_boundary_attesting_balance
def _determine_new_finalized_checkpoint(state: BeaconState,
                                        justification_bits: Bitfield,
                                        config: Eth2Config) -> Checkpoint:
    current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH)

    new_finalized_epoch = _determine_new_finalized_epoch(
        state.finalized_checkpoint.epoch,
        state.previous_justified_checkpoint.epoch,
        state.current_justified_checkpoint.epoch,
        current_epoch,
        justification_bits,
    )
    if new_finalized_epoch != state.finalized_checkpoint.epoch:
        # NOTE: we only want to call ``get_block_root``
        # upon some change, not unconditionally
        # Given the way it reads the block roots, it can cause
        # validation problems with some configurations, esp. in testing.
        # This is implicitly happening above for the justified roots.
        new_finalized_root = get_block_root(
            state,
            new_finalized_epoch,
            config.SLOTS_PER_EPOCH,
            config.SLOTS_PER_HISTORICAL_ROOT,
        )
    else:
        new_finalized_root = state.finalized_checkpoint.root

    return Checkpoint.create(epoch=new_finalized_epoch,
                             root=new_finalized_root)
Exemple #4
0
def _determine_new_justified_checkpoint_and_bitfield(
        state: BeaconState, config: Eth2Config) -> Tuple[Checkpoint, Bitfield]:
    (
        new_current_justified_epoch,
        justification_bits,
    ) = _determine_new_justified_epoch_and_bitfield(
        state,
        config,
    )

    if new_current_justified_epoch != state.current_justified_checkpoint.epoch:
        new_current_justified_root = get_block_root(
            state,
            new_current_justified_epoch,
            config.SLOTS_PER_EPOCH,
            config.SLOTS_PER_HISTORICAL_ROOT,
        )
    else:
        new_current_justified_root = state.current_justified_checkpoint.root

    return (
        Checkpoint(
            epoch=new_current_justified_epoch,
            root=new_current_justified_root,
        ),
        justification_bits,
    )
Exemple #5
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,
        )
def get_previous_epoch_matching_head_attestations(
        state: 'BeaconState', slots_per_epoch: int,
        slots_per_historical_root: int) -> Iterable[PendingAttestation]:
    for attestation in state.previous_epoch_attestations:
        beacon_block_root = get_block_root(
            state,
            attestation.data.slot,
            slots_per_historical_root,
        )
        if attestation.data.beacon_block_root == beacon_block_root:
            yield attestation
Exemple #7
0
def validate_attestation(state: BeaconState,
                         attestation: Attestation,
                         genesis_epoch: EpochNumber,
                         epoch_length: int,
                         min_attestation_inclusion_delay: int,
                         latest_block_roots_length: int,
                         target_committee_size: int,
                         shard_count: int) -> None:
    """
    Validate the given ``attestation``.
    Raise ``ValidationError`` if it's invalid.
    """

    validate_attestation_slot(
        attestation.data,
        state.slot,
        epoch_length,
        min_attestation_inclusion_delay,
    )

    validate_attestation_justified_epoch(
        attestation.data,
        state.current_epoch(epoch_length),
        state.previous_justified_epoch,
        state.justified_epoch,
        epoch_length,
    )

    validate_attestation_justified_block_root(
        attestation.data,
        justified_block_root=get_block_root(
            state=state,
            slot=get_epoch_start_slot(attestation.data.justified_epoch, epoch_length),
            latest_block_roots_length=latest_block_roots_length,
        ),
    )

    validate_attestation_latest_crosslink_root(
        attestation.data,
        latest_crosslink_root=state.latest_crosslinks[attestation.data.shard].shard_block_root,
    )

    validate_attestation_shard_block_root(attestation.data)

    validate_attestation_aggregate_signature(
        state,
        attestation,
        genesis_epoch,
        epoch_length,
        target_committee_size,
        shard_count,
    )
def validate_attestation(state: BeaconState, attestation: Attestation,
                         min_attestation_inclusion_delay: int,
                         slots_per_historical_root: int,
                         committee_config: CommitteeConfig) -> None:
    """
    Validate the given ``attestation``.
    Raise ``ValidationError`` if it's invalid.
    """
    slots_per_epoch = committee_config.SLOTS_PER_EPOCH

    validate_attestation_slot(
        attestation.data,
        state.slot,
        slots_per_epoch,
        min_attestation_inclusion_delay,
        committee_config.GENESIS_SLOT,
    )

    validate_attestation_source_epoch(
        attestation.data,
        state.current_epoch(slots_per_epoch),
        state.previous_justified_epoch,
        state.justified_epoch,
        slots_per_epoch,
    )

    validate_attestation_source_root(
        attestation.data,
        justified_epoch=get_block_root(
            state=state,
            slot=get_epoch_start_slot(
                attestation.data.source_epoch,
                slots_per_epoch,
            ),
            slots_per_historical_root=slots_per_historical_root,
        ),
    )

    validate_attestation_previous_crosslink_or_root(
        attestation_data=attestation.data,
        state_latest_crosslink=state.latest_crosslinks[attestation.data.shard],
        slots_per_epoch=slots_per_epoch,
    )

    validate_attestation_crosslink_data_root(attestation.data)

    validate_attestation_aggregate_signature(
        state,
        attestation,
        committee_config,
    )
Exemple #9
0
def validate_attestation(state: BeaconState, attestation: Attestation,
                         min_attestation_inclusion_delay: int,
                         latest_block_roots_length: int,
                         committee_config: CommitteeConfig) -> None:
    """
    Validate the given ``attestation``.
    Raise ``ValidationError`` if it's invalid.
    """
    epoch_length = committee_config.EPOCH_LENGTH

    validate_attestation_slot(
        attestation.data,
        state.slot,
        epoch_length,
        min_attestation_inclusion_delay,
    )

    validate_attestation_justified_epoch(
        attestation.data,
        state.current_epoch(epoch_length),
        state.previous_justified_epoch,
        state.justified_epoch,
        epoch_length,
    )

    validate_attestation_justified_block_root(
        attestation.data,
        justified_block_root=get_block_root(
            state=state,
            slot=get_epoch_start_slot(
                attestation.data.justified_epoch,
                epoch_length,
            ),
            latest_block_roots_length=latest_block_roots_length,
        ),
    )

    validate_attestation_latest_crosslink_root(
        attestation.data,
        latest_crosslink_root=state.latest_crosslinks[
            attestation.data.shard].shard_block_root,
    )

    validate_attestation_shard_block_root(attestation.data)

    validate_attestation_aggregate_signature(
        state,
        attestation,
        committee_config,
    )
Exemple #10
0
def _get_epoch_boundary_root(state: BeaconState, config: BeaconConfig,
                             beacon_block_root: Hash32) -> Hash32:
    epoch_start_slot = get_epoch_start_slot(
        slot_to_epoch(state.slot, config.SLOTS_PER_EPOCH),
        config.SLOTS_PER_EPOCH,
    )
    if epoch_start_slot == state.slot:
        return beacon_block_root
    else:
        return get_block_root(
            state,
            epoch_start_slot,
            config.LATEST_BLOCK_ROOTS_LENGTH,
        )
def _get_epoch_boundary_attesting_indices(
        state: 'BeaconState', attestations: Sequence[PendingAttestation],
        epoch: Epoch, config: Eth2Config) -> Tuple[ValidatorIndex, ...]:
    target_root = get_block_root(
        state,
        get_epoch_start_slot(epoch, config.SLOTS_PER_EPOCH),
        config.SLOTS_PER_HISTORICAL_ROOT,
    )
    relevant_attestations = (a for a in attestations
                             if a.data.target_root == target_root)
    return get_attesting_indices(
        state,
        relevant_attestations,
        config,
    )
Exemple #12
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,
        )
def get_previous_epoch_head_attestations(
        state: 'BeaconState', slots_per_epoch: int, genesis_epoch: Epoch,
        latest_block_roots_length: int) -> Iterable[PendingAttestationRecord]:
    previous_epoch_attestations = get_previous_epoch_attestations(
        state,
        slots_per_epoch,
        genesis_epoch,
    )
    for attestation in previous_epoch_attestations:
        beacon_block_root = get_block_root(
            state,
            attestation.data.slot,
            latest_block_roots_length,
        )
        if attestation.data.beacon_block_root == beacon_block_root:
            yield attestation
def get_previous_epoch_boundary_attestations(
        state: 'BeaconState', slots_per_epoch: int,
        latest_block_roots_length: int) -> Iterable[PendingAttestation]:
    if not state.previous_epoch_attestations:
        return tuple()

    beacon_block_root = get_block_root(
        state,
        get_epoch_start_slot(
            state.previous_epoch(slots_per_epoch),
            slots_per_epoch,
        ),
        latest_block_roots_length,
    )
    for attestation in state.previous_epoch_attestations:
        if attestation.data.beacon_block_root == beacon_block_root:
            yield attestation
Exemple #15
0
def validate_serenity_attestation(state: BeaconState, attestation: Attestation,
                                  epoch_length: int,
                                  min_attestation_inclusion_delay: int,
                                  latest_block_roots_length: int) -> None:
    """
    Validate the given ``attestation``.
    Raise ``ValidationError`` if it's invalid.
    """

    validate_serenity_attestation_slot(
        attestation.data,
        state.slot,
        epoch_length,
        min_attestation_inclusion_delay,
    )

    validate_serenity_attestation_justified_slot(
        attestation.data,
        state.slot,
        state.previous_justified_slot,
        state.justified_slot,
        epoch_length,
    )

    validate_serenity_attestation_justified_block_root(
        attestation.data,
        justified_block_root=get_block_root(
            state=state,
            slot=attestation.data.justified_slot,
            latest_block_roots_length=latest_block_roots_length,
        ),
    )

    validate_serenity_attestation_latest_crosslink_root(
        attestation.data,
        latest_crosslink_root=state.latest_crosslinks[
            attestation.data.shard].shard_block_root,
    )

    validate_serenity_attestation_shard_block_root(attestation.data)

    validate_serenity_attestation_aggregate_signature(
        state,
        attestation,
        epoch_length,
    )
Exemple #16
0
def _determine_new_justified_checkpoint_and_bitfield(
        state: BeaconState,
        config: Eth2Config) -> Tuple[Epoch, Hash32, int]:

    (
        new_current_justified_epoch,
        justification_bitfield,
    ) = _determine_new_justified_epoch_and_bitfield(
        state,
        config,
    )

    new_current_justified_root = get_block_root(
        state,
        new_current_justified_epoch,
        config.SLOTS_PER_EPOCH,
        config.SLOTS_PER_HISTORICAL_ROOT,
    )

    return (
        new_current_justified_epoch,
        new_current_justified_root,
        justification_bitfield,
    )
Exemple #17
0
def create_mock_slashable_attestation(
        state: BeaconState, config: Eth2Config, keymap: Dict[BLSPubkey, int],
        attestation_slot: Slot) -> SlashableAttestation:
    """
    Create `SlashableAttestation` that is signed by one attester.
    """
    attester_index = ValidatorIndex(0)
    committee = (attester_index, )
    shard = Shard(0)

    # Use genesis block root as `beacon_block_root`, only for tests.
    beacon_block_root = get_block_root(
        state,
        config.GENESIS_SLOT,
        config.SLOTS_PER_HISTORICAL_ROOT,
    )

    # 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.current_justified_epoch,
                             config.SLOTS_PER_EPOCH),
        config.SLOTS_PER_HISTORICAL_ROOT,
    )
    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=source_root,
        target_root=target_root,
        shard=shard,
        previous_crosslink=previous_crosslink,
        crosslink_data_root=ZERO_HASH32,
    )

    message_hash, voting_committee_indices = _get_mock_message_and_voting_committee_indices(
        attestation_data,
        committee,
        num_voted_attesters=1,
    )

    signature = sign_transaction(
        message_hash=message_hash,
        privkey=keymap[state.validator_registry[
            voting_committee_indices[0]].pubkey],
        fork=state.fork,
        slot=attestation_slot,
        signature_domain=SignatureDomain.DOMAIN_ATTESTATION,
        slots_per_epoch=config.SLOTS_PER_EPOCH,
    )
    validator_indices = tuple(committee[i] for i in voting_committee_indices)

    return SlashableAttestation(
        validator_indices=sorted(validator_indices),
        data=attestation_data,
        custody_bitfield=get_empty_bitfield(len(voting_committee_indices)),
        aggregate_signature=signature,
    )
Exemple #18
0
def process_justification(state: BeaconState,
                          config: Eth2Config) -> BeaconState:
    current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH)
    previous_epoch = state.previous_epoch(config.SLOTS_PER_EPOCH)

    current_epoch_justifiable = _is_epoch_justifiable(
        state,
        state.current_epoch_attestations,
        current_epoch,
        config,
    )
    previous_epoch_justifiable = _is_epoch_justifiable(
        state,
        state.previous_epoch_attestations,
        previous_epoch,
        config,
    )

    _justification_bitfield = state.justification_bitfield << 1
    if previous_epoch_justifiable and current_epoch_justifiable:
        justification_bitfield = _justification_bitfield | 3
    elif previous_epoch_justifiable:
        justification_bitfield = _justification_bitfield | 2
    elif current_epoch_justifiable:
        justification_bitfield = _justification_bitfield | 1
    else:
        justification_bitfield = _justification_bitfield

    if current_epoch_justifiable:
        new_justified_epoch = current_epoch
    elif previous_epoch_justifiable:
        new_justified_epoch = previous_epoch
    else:
        new_justified_epoch = state.current_justified_epoch

    new_finalized_epoch, _ = _get_finalized_epoch(
        justification_bitfield,
        state.previous_justified_epoch,
        state.current_justified_epoch,
        state.finalized_epoch,
        previous_epoch,
    )

    # Update state
    state = state.copy(
        previous_justified_epoch=state.current_justified_epoch,
        previous_justified_root=state.current_justified_root,
        justification_bitfield=justification_bitfield,
    )

    if new_justified_epoch != state.current_justified_epoch:
        state = state.copy(
            current_justified_epoch=new_justified_epoch,
            current_justified_root=get_block_root(
                state,
                get_epoch_start_slot(new_justified_epoch,
                                     config.SLOTS_PER_EPOCH),
                config.SLOTS_PER_HISTORICAL_ROOT,
            ),
        )

    if new_finalized_epoch != state.finalized_epoch:
        state = state.copy(finalized_epoch=new_finalized_epoch,
                           finalized_root=get_block_root(
                               state,
                               get_epoch_start_slot(new_finalized_epoch,
                                                    config.SLOTS_PER_EPOCH),
                               config.SLOTS_PER_HISTORICAL_ROOT,
                           ))

    return state
def test_get_attestation_deltas(
    genesis_state,
    config,
    slots_per_epoch,
    target_committee_size,
    max_committees_per_slot,
    min_attestation_inclusion_delay,
    inactivity_penalty_quotient,
    finalized_epoch,
    current_slot,
    sample_pending_attestation_record_params,
    sample_attestation_data_params,
):

    state = genesis_state.mset(
        "slot",
        current_slot,
        "finalized_checkpoint",
        Checkpoint.create(epoch=finalized_epoch),
    )
    previous_epoch = state.previous_epoch(config.SLOTS_PER_EPOCH,
                                          config.GENESIS_EPOCH)
    has_inactivity_penalty = (previous_epoch - finalized_epoch >
                              config.MIN_EPOCHS_TO_INACTIVITY_PENALTY)

    indices_to_check = set()

    prev_epoch_attestations = tuple()

    for committee, committee_index, slot in iterate_committees_at_epoch(
            state, previous_epoch, config):
        participants_bitfield = get_empty_bitfield(len(committee))
        for i, index in enumerate(committee):
            indices_to_check.add(index)
            participants_bitfield = set_voted(participants_bitfield, i)
        prev_epoch_attestations += (PendingAttestation.create(
            **sample_pending_attestation_record_params).mset(
                "aggregation_bits",
                participants_bitfield,
                "inclusion_delay",
                min_attestation_inclusion_delay,
                "proposer_index",
                get_beacon_proposer_index(state.set("slot", slot),
                                          CommitteeConfig(config)),
                "data",
                AttestationData.create(**sample_attestation_data_params).mset(
                    "slot",
                    slot,
                    "index",
                    committee_index,
                    "beacon_block_root",
                    get_block_root_at_slot(state, slot,
                                           config.SLOTS_PER_HISTORICAL_ROOT),
                    "target",
                    Checkpoint.create(
                        epoch=previous_epoch,
                        root=get_block_root(
                            state,
                            previous_epoch,
                            config.SLOTS_PER_EPOCH,
                            config.SLOTS_PER_HISTORICAL_ROOT,
                        ),
                    ),
                ),
            ), )
    state = state.set("previous_epoch_attestations", prev_epoch_attestations)

    rewards_received, penalties_received = get_attestation_deltas(
        state, config)
    if has_inactivity_penalty:
        assert sum(penalties_received) > 0
    else:
        assert sum(penalties_received) == 0
    assert all(reward > 0 for reward in rewards_received)
Exemple #20
0
def _process_rewards_and_penalties_for_finality(
    state: BeaconState, config: BeaconConfig,
    previous_epoch_active_validator_indices: Set[ValidatorIndex],
    previous_total_balance: Gwei,
    previous_epoch_attestations: Sequence[Attestation],
    previous_epoch_attester_indices: Set[ValidatorIndex],
    inclusion_infos: Dict[ValidatorIndex, InclusionInfo],
    effective_balances: Dict[ValidatorIndex,
                             Gwei], base_rewards: Dict[ValidatorIndex, Gwei],
    old_rewards_received: Dict[ValidatorIndex, SignedGwei]
) -> Dict[ValidatorIndex, SignedGwei]:
    previous_epoch_boundary_attestations = (
        a for a in previous_epoch_attestations
        if a.data.epoch_boundary_root == get_block_root(
            state,
            get_epoch_start_slot(
                state.previous_epoch(config.SLOTS_PER_EPOCH,
                                     config.GENESIS_EPOCH),
                config.SLOTS_PER_EPOCH,
            ),
            config.LATEST_BLOCK_ROOTS_LENGTH,
        ))
    previous_epoch_boundary_attester_indices = get_attester_indices_from_attesttion(
        state=state,
        attestations=previous_epoch_boundary_attestations,
        committee_config=CommitteeConfig(config),
    )

    previous_epoch_head_attestations = get_previous_epoch_head_attestations(
        state,
        config.SLOTS_PER_EPOCH,
        config.GENESIS_EPOCH,
        config.LATEST_BLOCK_ROOTS_LENGTH,
    )
    previous_epoch_head_attester_indices = get_attester_indices_from_attesttion(
        state=state,
        attestations=previous_epoch_head_attestations,
        committee_config=CommitteeConfig(config),
    )

    rewards_received = {index: Gwei(0) for index in old_rewards_received}
    penalties_received = rewards_received.copy()
    epochs_since_finality = state.next_epoch(
        config.SLOTS_PER_EPOCH) - state.finalized_epoch
    if epochs_since_finality <= 4:
        # 1.1 Expected FFG source:
        previous_epoch_attesting_balance = get_total_balance_from_effective_balances(
            effective_balances,
            previous_epoch_attester_indices,
        )
        # Reward validators in `previous_epoch_attester_indices`
        # # Punish active validators not in `previous_epoch_attester_indices`
        excluded_active_validators_indices = previous_epoch_active_validator_indices.difference(
            previous_epoch_attester_indices, )
        rewards = {
            index:
            Gwei(base_rewards[index] * previous_epoch_attesting_balance //
                 previous_total_balance)
            for index in previous_epoch_attester_indices
        }
        penalties = {
            index: base_rewards[index]
            for index in excluded_active_validators_indices
        }
        rewards_received, penalties_received = _apply_rewards_and_penalties(
            RewardSettlementContext(
                rewards=rewards,
                indices_to_reward=previous_epoch_attester_indices,
                penalties=penalties,
                indices_to_penalize=excluded_active_validators_indices,
                rewards_received=rewards_received,
                penalties_received=penalties_received,
            ), )

        # 1.2 Expected FFG target:
        previous_epoch_boundary_attesting_balance = get_total_balance_from_effective_balances(
            effective_balances,
            previous_epoch_boundary_attester_indices,
        )
        # Reward validators in `previous_epoch_boundary_attester_indices`
        # Punish active validators not in `previous_epoch_boundary_attester_indices`
        excluded_active_validators_indices = previous_epoch_active_validator_indices.difference(
            previous_epoch_boundary_attester_indices, )
        rewards = {
            index: Gwei(base_rewards[index] *
                        previous_epoch_boundary_attesting_balance //
                        previous_total_balance)
            for index in previous_epoch_boundary_attester_indices
        }
        penalties = {
            index: base_rewards[index]
            for index in excluded_active_validators_indices
        }
        rewards_received, penalties_received = _apply_rewards_and_penalties(
            RewardSettlementContext(
                rewards=rewards,
                indices_to_reward=previous_epoch_boundary_attester_indices,
                penalties=penalties,
                indices_to_penalize=excluded_active_validators_indices,
                rewards_received=rewards_received,
                penalties_received=penalties_received,
            ), )

        # 1.3 Expected beacon chain head:
        previous_epoch_head_attesting_balance = get_total_balance_from_effective_balances(
            effective_balances,
            previous_epoch_head_attester_indices,
        )
        # Reward validators in `previous_epoch_head_attester_indices`
        # Punish active validators not in `previous_epoch_head_attester_indices`
        excluded_active_validators_indices = previous_epoch_active_validator_indices.difference(
            previous_epoch_head_attester_indices, )
        rewards = {
            index:
            Gwei(base_rewards[index] * previous_epoch_head_attesting_balance //
                 previous_total_balance)
            for index in previous_epoch_head_attester_indices
        }
        penalties = {
            index: base_rewards[index]
            for index in excluded_active_validators_indices
        }
        rewards_received, penalties_received = _apply_rewards_and_penalties(
            RewardSettlementContext(
                rewards=rewards,
                indices_to_reward=previous_epoch_head_attester_indices,
                penalties=penalties,
                indices_to_penalize=excluded_active_validators_indices,
                rewards_received=rewards_received,
                penalties_received=penalties_received,
            ), )

        # 1.4 Inclusion distance:
        # Reward validators in `previous_epoch_attester_indices`
        rewards = {
            index: Gwei(base_rewards[index] *
                        config.MIN_ATTESTATION_INCLUSION_DELAY //
                        inclusion_infos[index].inclusion_distance)
            for index in previous_epoch_attester_indices
        }
        rewards_received, penalties_received = _apply_rewards_and_penalties(
            RewardSettlementContext(
                rewards=rewards,
                indices_to_reward=previous_epoch_attester_indices,
                rewards_received=rewards_received,
                penalties_received=penalties_received,
            ), )

    # epochs_since_finality > 4
    else:
        # Punish active validators not in `previous_epoch_attester_indices`
        excluded_active_validators_indices = previous_epoch_active_validator_indices.difference(
            previous_epoch_attester_indices, )
        inactivity_penalties = {
            index: base_rewards[index] +
            (effective_balances[index] * epochs_since_finality //
             config.INACTIVITY_PENALTY_QUOTIENT // 2)
            for index in excluded_active_validators_indices
        }
        rewards_received, penalties_received = _apply_rewards_and_penalties(
            RewardSettlementContext(
                penalties=inactivity_penalties,
                indices_to_penalize=excluded_active_validators_indices,
                rewards_received=rewards_received,
                penalties_received=penalties_received,
            ), )

        # Punish active validators not in `previous_epoch_boundary_attester_indices`
        excluded_active_validators_indices = previous_epoch_active_validator_indices.difference(
            previous_epoch_boundary_attester_indices, )
        inactivity_penalties = {
            index: base_rewards[index] +
            (effective_balances[index] * epochs_since_finality //
             config.INACTIVITY_PENALTY_QUOTIENT // 2)
            for index in excluded_active_validators_indices
        }
        rewards_received, penalties_received = _apply_rewards_and_penalties(
            RewardSettlementContext(
                penalties=inactivity_penalties,
                indices_to_penalize=excluded_active_validators_indices,
                rewards_received=rewards_received,
                penalties_received=penalties_received,
            ), )

        # Punish active validators not in `previous_epoch_head_attester_indices`
        excluded_active_validators_indices = previous_epoch_active_validator_indices.difference(
            previous_epoch_head_attester_indices, )
        penalties = {
            index: base_rewards[index]
            for index in excluded_active_validators_indices
        }
        rewards_received, penalties_received = _apply_rewards_and_penalties(
            RewardSettlementContext(
                penalties=penalties,
                indices_to_penalize=excluded_active_validators_indices,
                rewards_received=rewards_received,
                penalties_received=penalties_received,
            ), )

        # Punish penalized active validators
        penalties = {
            index: 3 * base_rewards[index] + 2 *
            (effective_balances[index] * epochs_since_finality //
             config.INACTIVITY_PENALTY_QUOTIENT // 2)
            for index in previous_epoch_active_validator_indices
            if state.validator_registry[index].slashed is True
        }
        rewards_received, penalties_received = _apply_rewards_and_penalties(
            RewardSettlementContext(
                penalties=penalties,
                indices_to_penalize={index
                                     for index in penalties},
                rewards_received=rewards_received,
                penalties_received=penalties_received,
            ), )

        # Punish validators in `previous_epoch_attester_indices`
        penalties = {
            index: Gwei(base_rewards[index] -
                        (base_rewards[index] *
                         config.MIN_ATTESTATION_INCLUSION_DELAY //
                         inclusion_infos[index].inclusion_distance))
            for index in previous_epoch_attester_indices
        }
        rewards_received, penalties_received = _apply_rewards_and_penalties(
            RewardSettlementContext(
                penalties=penalties,
                indices_to_penalize=previous_epoch_attester_indices,
                rewards_received=rewards_received,
                penalties_received=penalties_received,
            ), )

    historical_rewards_received = old_rewards_received.copy()
    for index in rewards_received:
        historical_rewards_received = _update_rewards_or_penalies(
            index,
            rewards_received[index] - penalties_received[index],
            historical_rewards_received,
        )
    return historical_rewards_received
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]