Beispiel #1
0
def _churn_validators(state: BeaconState, config: BeaconConfig,
                      check_should_churn_fn: Callable[..., Any],
                      churn_fn: Callable[..., Any],
                      max_balance_churn: int) -> BeaconState:
    """
    Churn the validators. The number of the churning validators is based on
    the given ``max_balance_churn``.

    :param check_should_churn_fn: the funcation to determine if the validator should be churn
    :param churn_fn``: the function to churn the validators; it could be ``activate_validator`` or
    ``exit_validator``
    """
    balance_churn = 0
    for index in range(len(state.validator_registry)):
        index = ValidatorIndex(index)
        should_churn = check_should_churn_fn(
            state,
            index,
        )
        if should_churn:
            # Check the balance churn would be within the allowance
            balance_churn += get_effective_balance(
                state.validator_balances,
                index,
                config.MAX_DEPOSIT_AMOUNT,
            )
            if balance_churn > max_balance_churn:
                break

            state = churn_fn(state, index)
    return state
Beispiel #2
0
def test_get_effective_balance(balance,
                               max_deposit_amount,
                               expected,
                               sample_validator_record_params):
    balances = (balance,)
    result = get_effective_balance(balances, 0, max_deposit_amount)
    assert result == expected
def get_total_attesting_balance(
        *,
        state: 'BeaconState',
        shard: ShardNumber,
        shard_block_root: Hash32,
        attestations: Sequence[PendingAttestationRecord],
        genesis_epoch: EpochNumber,
        epoch_length: int,
        max_deposit_amount: Gwei,
        target_committee_size: int,
        shard_count: int) -> Gwei:
    return Gwei(
        sum(
            get_effective_balance(state.validator_balances, i, max_deposit_amount)
            for i in get_attesting_validator_indices(
                state=state,
                attestations=attestations,
                shard=shard,
                shard_block_root=shard_block_root,
                genesis_epoch=genesis_epoch,
                epoch_length=epoch_length,
                target_committee_size=target_committee_size,
                shard_count=shard_count,
            )
        )
    )
def get_base_reward(*, state: 'BeaconState', index: ValidatorIndex,
                    base_reward_quotient: int,
                    max_deposit_amount: Gwei) -> Gwei:
    return Gwei(
        get_effective_balance(
            state.validator_balances,
            index,
            max_deposit_amount,
        ) // base_reward_quotient // 5)
def _settle_penality_to_validator_and_whistleblower(
        *, state: BeaconState, validator_index: ValidatorIndex,
        latest_penalized_exit_length: int, whistleblower_reward_quotient: int,
        epoch_length: int, max_deposit: Ether) -> BeaconState:
    """
    Apply penality/reward to validator and whistleblower and update the meta data

    More intuitive pseudo-code:
    current_epoch_penalization_index = (state.slot // EPOCH_LENGTH) % LATEST_PENALIZED_EXIT_LENGTH
    state.latest_penalized_exit_balances[current_epoch_penalization_index] += (
        get_effective_balance(state, index)
    )
    whistleblower_index = get_beacon_proposer_index(state, state.slot)
    whistleblower_reward = get_effective_balance(state, index) // WHISTLEBLOWER_REWARD_QUOTIENT
    state.validator_balances[whistleblower_index] += whistleblower_reward
    state.validator_balances[index] -= whistleblower_reward
    validator.penalized_slot = state.slot
    """
    # Update `state.latest_penalized_exit_balances`
    current_epoch_penalization_index = (
        state.slot // epoch_length) % latest_penalized_exit_length
    effective_balance = get_effective_balance(
        state.validator_balances,
        validator_index,
        max_deposit,
    )
    penalized_exit_balance = (
        state.latest_penalized_exit_balances[current_epoch_penalization_index]
        + effective_balance)
    latest_penalized_exit_balances = update_tuple_item(
        tuple_data=state.latest_penalized_exit_balances,
        index=current_epoch_penalization_index,
        new_value=penalized_exit_balance,
    )
    state = state.copy(
        latest_penalized_exit_balances=latest_penalized_exit_balances, )

    # Update whistleblower's balance
    whistleblower_reward = (effective_balance // whistleblower_reward_quotient)
    whistleblower_index = get_beacon_proposer_index(state, state.slot,
                                                    epoch_length)
    state = state.update_validator_balance(
        whistleblower_index,
        state.validator_balances[whistleblower_index] + whistleblower_reward,
    )

    # Update validator's balance and `penalized_slot` field
    validator = state.validator_registry[validator_index]
    validator = validator.copy(penalized_slot=state.slot, )
    state = state.update_validator(
        validator_index,
        validator,
        state.validator_balances[validator_index] - whistleblower_reward,
    )

    return state
def get_base_reward(*, state: 'BeaconState', index: ValidatorIndex,
                    base_reward_quotient: int, previous_total_balance: Gwei,
                    max_deposit_amount: Gwei) -> Gwei:
    if previous_total_balance == 0:
        return Gwei(0)
    adjusted_quotient = (integer_squareroot(previous_total_balance) //
                         base_reward_quotient)
    return Gwei(
        get_effective_balance(
            state.validator_balances,
            index,
            max_deposit_amount,
        ) // adjusted_quotient // 5)
Beispiel #7
0
def _compute_individual_penalty(state: BeaconState, config: BeaconConfig,
                                validator_index: ValidatorIndex,
                                total_penalties: Gwei,
                                total_balance: Gwei) -> Gwei:
    effective_balance = get_effective_balance(
        state.validator_balances,
        validator_index,
        config.MAX_DEPOSIT_AMOUNT,
    )
    return Gwei(
        max(
            effective_balance * min(total_penalties * 3, total_balance) //
            total_balance,
            effective_balance // config.MIN_PENALTY_QUOTIENT,
        ))
Beispiel #8
0
def get_total_attesting_balance(
        *,
        state: 'BeaconState',
        shard: ShardNumber,
        shard_block_root: Hash32,
        attestations: Sequence[PendingAttestationRecord],
        max_deposit_amount: Gwei,
        committee_config: CommitteeConfig) -> Gwei:
    return Gwei(
        sum(
            get_effective_balance(state.validator_balances, i, max_deposit_amount)
            for i in get_attesting_validator_indices(
                state=state,
                attestations=attestations,
                shard=shard,
                shard_block_root=shard_block_root,
                committee_config=committee_config,
            )
        )
    )
Beispiel #9
0
def process_slashings(state: BeaconState, config: BeaconConfig) -> BeaconState:
    """
    Process the slashings.
    """
    latest_slashed_exit_length = config.LATEST_SLASHED_EXIT_LENGTH
    max_deposit_amount = config.MAX_DEPOSIT_AMOUNT

    current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH)
    active_validator_indices = get_active_validator_indices(
        state.validator_registry, current_epoch)
    total_balance = Gwei(
        sum(
            get_effective_balance(state.validator_balances, i,
                                  max_deposit_amount)
            for i in active_validator_indices))
    total_penalties = _compute_total_penalties(
        state,
        config,
        current_epoch,
    )

    for validator_index, validator in enumerate(state.validator_registry):
        validator_index = ValidatorIndex(validator_index)
        is_halfway_to_withdrawable_epoch = (
            current_epoch == validator.withdrawable_epoch -
            latest_slashed_exit_length // 2)
        if validator.slashed and is_halfway_to_withdrawable_epoch:
            penalty = _compute_individual_penalty(
                state=state,
                config=config,
                validator_index=validator_index,
                total_penalties=total_penalties,
                total_balance=total_balance,
            )
            state = state.update_validator_balance(
                validator_index=validator_index,
                balance=state.validator_balances[validator_index] - penalty,
            )
    return state
Beispiel #10
0
def test_get_winning_root_and_participants(
        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,
                previous_crosslink=CrosslinkRecord(
                    epoch=config.GENESIS_EPOCH,
                    crosslink_data_root=ZERO_HASH32,
                ),
                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,
                previous_crosslink=CrosslinkRecord(
                    epoch=config.GENESIS_EPOCH,
                    crosslink_data_root=ZERO_HASH32,
                ),
                crosslink_data_root=competing_block_roots[1],
            ),
        ),
    )

    state = n_validators_state.copy(previous_epoch_attestations=attestations, )
    effective_balances = {
        index: get_effective_balance(
            state.validator_balances,
            index,
            config.MAX_DEPOSIT_AMOUNT,
        )
        for index in range(len(state.validator_registry))
    }

    winning_root, attesting_validator_indices = get_winning_root_and_participants(
        state=state,
        shard=shard,
        effective_balances=effective_balances,
        committee_config=committee_config,
    )
    if len(attesting_validator_indices) == 0:
        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]
                assert set(attesting_validator_indices) == set(
                    block_root_1_participants)
            else:
                assert winning_root == competing_block_roots[1]
                assert set(attesting_validator_indices) == set(
                    block_root_2_participants)
        elif len(block_root_1_participants) < len(block_root_2_participants):
            assert winning_root == competing_block_roots[1]
            assert set(attesting_validator_indices) == set(
                block_root_2_participants)
        else:
            assert winning_root == competing_block_roots[0]
            assert set(attesting_validator_indices) == set(
                block_root_1_participants)
Beispiel #11
0
def _settle_penality_to_validator_and_whistleblower(
        *, state: BeaconState, validator_index: ValidatorIndex,
        latest_slashed_exit_length: int, whistleblower_reward_quotient: int,
        max_deposit_amount: Gwei,
        committee_config: CommitteeConfig) -> BeaconState:
    """
    Apply penality/reward to validator and whistleblower and update the meta data

    More intuitive pseudo-code:
    current_epoch_penalization_index = (state.slot // SLOTS_PER_EPOCH) % LATEST_SLASHED_EXIT_LENGTH
    state.latest_slashed_balances[current_epoch_penalization_index] += (
        get_effective_balance(state, index)
    )
    whistleblower_index = get_beacon_proposer_index(state, state.slot)
    whistleblower_reward = get_effective_balance(state, index) // WHISTLEBLOWER_REWARD_QUOTIENT
    state.validator_balances[whistleblower_index] += whistleblower_reward
    state.validator_balances[index] -= whistleblower_reward
    validator.slashed = True
    validator.withdrawable_epoch = get_current_epoch(state) + LATEST_SLASHED_EXIT_LENGTH
    """
    slots_per_epoch = committee_config.SLOTS_PER_EPOCH

    # Update `state.latest_slashed_balances`
    current_epoch_penalization_index = state.current_epoch(
        slots_per_epoch) % latest_slashed_exit_length
    effective_balance = get_effective_balance(
        state.validator_balances,
        validator_index,
        max_deposit_amount,
    )
    slashed_exit_balance = (
        state.latest_slashed_balances[current_epoch_penalization_index] +
        effective_balance)
    latest_slashed_balances = update_tuple_item(
        tuple_data=state.latest_slashed_balances,
        index=current_epoch_penalization_index,
        new_value=slashed_exit_balance,
    )
    state = state.copy(latest_slashed_balances=latest_slashed_balances, )

    # Update whistleblower's balance
    whistleblower_reward = (effective_balance // whistleblower_reward_quotient)
    whistleblower_index = get_beacon_proposer_index(
        state,
        state.slot,
        committee_config,
    )
    state = state.update_validator_balance(
        whistleblower_index,
        state.validator_balances[whistleblower_index] + whistleblower_reward,
    )

    # Update validator's balance and `slashed`, `withdrawable_epoch` field
    validator = state.validator_registry[validator_index].copy(
        slashed=True,
        withdrawable_epoch=state.current_epoch(slots_per_epoch) +
        latest_slashed_exit_length,
    )
    state = state.update_validator(
        validator_index,
        validator,
        state.validator_balances[validator_index] - whistleblower_reward,
    )

    return state
Beispiel #12
0
def get_initial_beacon_state(*, initial_validator_deposits: Sequence[Deposit],
                             genesis_time: Timestamp,
                             latest_eth1_data: Eth1Data,
                             genesis_slot: SlotNumber,
                             genesis_fork_version: int,
                             genesis_start_shard: ShardNumber,
                             shard_count: int, latest_block_roots_length: int,
                             epoch_length: int, target_committee_size: int,
                             max_deposit: Ether,
                             latest_penalized_exit_length: int,
                             latest_randao_mixes_length: int,
                             entry_exit_delay: int) -> BeaconState:
    state = BeaconState(
        # Misc
        slot=genesis_slot,
        genesis_time=genesis_time,
        fork=Fork(
            previous_version=genesis_fork_version,
            current_version=genesis_fork_version,
            slot=genesis_slot,
        ),

        # Validator registry
        validator_registry=(),
        validator_balances=(),
        validator_registry_update_slot=genesis_slot,
        validator_registry_exit_count=0,
        validator_registry_delta_chain_tip=ZERO_HASH32,

        # Randomness and committees
        latest_randao_mixes=tuple(ZERO_HASH32
                                  for _ in range(latest_randao_mixes_length)),
        latest_vdf_outputs=tuple(ZERO_HASH32
                                 for _ in range(latest_randao_mixes_length //
                                                epoch_length)),
        # TODO Remove `persistent_committees`, `persistent_committee_reassignments`
        persistent_committees=(),
        persistent_committee_reassignments=(),
        previous_epoch_start_shard=genesis_start_shard,
        current_epoch_start_shard=genesis_start_shard,
        previous_epoch_calculation_slot=genesis_slot,
        current_epoch_calculation_slot=genesis_slot,
        previous_epoch_randao_mix=ZERO_HASH32,
        current_epoch_randao_mix=ZERO_HASH32,

        # Custody challenges
        custody_challenges=(),

        # Finality
        previous_justified_slot=genesis_slot,
        justified_slot=genesis_slot,
        justification_bitfield=0,
        finalized_slot=genesis_slot,

        # Recent state
        latest_crosslinks=tuple([
            CrosslinkRecord(slot=genesis_slot, shard_block_root=ZERO_HASH32)
            for _ in range(shard_count)
        ]),
        latest_block_roots=tuple(ZERO_HASH32
                                 for _ in range(latest_block_roots_length)),
        latest_penalized_balances=tuple(
            Gwei(0) for _ in range(latest_penalized_exit_length)),
        latest_attestations=(),
        batched_block_roots=(),

        # Ethereum 1.0 chain data
        latest_eth1_data=latest_eth1_data,
        eth1_data_votes=(),
    )

    # Process initial deposits
    for deposit in initial_validator_deposits:
        state = process_deposit(
            state=state,
            pubkey=deposit.deposit_data.deposit_input.pubkey,
            amount=deposit.deposit_data.amount,
            proof_of_possession=deposit.deposit_data.deposit_input.
            proof_of_possession,
            withdrawal_credentials=deposit.deposit_data.deposit_input.
            withdrawal_credentials,
            randao_commitment=deposit.deposit_data.deposit_input.
            randao_commitment,
            custody_commitment=deposit.deposit_data.deposit_input.
            custody_commitment,
        )

    for validator_index, _ in enumerate(state.validator_registry):
        validator_index = ValidatorIndex(validator_index)
        is_enough_effective_balance = get_effective_balance(
            state.validator_balances,
            validator_index,
            max_deposit,
        ) >= max_deposit * GWEI_PER_ETH
        if is_enough_effective_balance:
            state = activate_validator(
                state,
                validator_index,
                genesis=True,
                genesis_slot=genesis_slot,
                entry_exit_delay=entry_exit_delay,
            )

    return state
Beispiel #13
0
def get_genesis_beacon_state(
        *, genesis_validator_deposits: Sequence[Deposit],
        genesis_time: Timestamp, genesis_eth1_data: Eth1Data,
        genesis_slot: Slot, genesis_epoch: Epoch, genesis_fork_version: int,
        genesis_start_shard: Shard, shard_count: int, min_seed_lookahead: int,
        slots_per_historical_root: int, latest_active_index_roots_length: int,
        slots_per_epoch: int, max_deposit_amount: Gwei,
        latest_slashed_exit_length: int, latest_randao_mixes_length: int,
        activation_exit_delay: int, deposit_contract_tree_depth: int,
        block_class: Type[BaseBeaconBlock]) -> BeaconState:
    state = BeaconState(
        # Misc
        slot=genesis_slot,
        genesis_time=genesis_time,
        fork=Fork(
            previous_version=genesis_fork_version.to_bytes(4, 'little'),
            current_version=genesis_fork_version.to_bytes(4, 'little'),
            epoch=genesis_epoch,
        ),

        # Validator registry
        validator_registry=(),
        validator_balances=(),
        validator_registry_update_epoch=genesis_epoch,

        # Randomness and committees
        latest_randao_mixes=(ZERO_HASH32, ) * latest_randao_mixes_length,
        previous_shuffling_start_shard=genesis_start_shard,
        current_shuffling_start_shard=genesis_start_shard,
        previous_shuffling_epoch=genesis_epoch,
        current_shuffling_epoch=genesis_epoch,
        previous_shuffling_seed=ZERO_HASH32,
        current_shuffling_seed=ZERO_HASH32,

        # Finality
        previous_epoch_attestations=(),
        current_epoch_attestations=(),
        previous_justified_epoch=genesis_epoch,
        current_justified_epoch=genesis_epoch,
        previous_justified_root=ZERO_HASH32,
        current_justified_root=ZERO_HASH32,
        justification_bitfield=0,
        finalized_epoch=genesis_epoch,
        finalized_root=ZERO_HASH32,

        # Recent state
        latest_crosslinks=((CrosslinkRecord(
            epoch=genesis_epoch, crosslink_data_root=ZERO_HASH32), ) *
                           shard_count),
        latest_block_roots=(ZERO_HASH32, ) * slots_per_historical_root,
        latest_state_roots=(ZERO_HASH32, ) * slots_per_historical_root,
        latest_active_index_roots=(ZERO_HASH32, ) *
        latest_active_index_roots_length,
        latest_slashed_balances=(Gwei(0), ) * latest_slashed_exit_length,
        latest_block_header=get_temporary_block_header(
            BeaconBlock.create_empty_block(genesis_slot), ),
        historical_roots=(),

        # Ethereum 1.0 chain data
        latest_eth1_data=genesis_eth1_data,
        eth1_data_votes=(),
        deposit_index=0,
    )

    # Process genesis deposits
    for deposit in genesis_validator_deposits:
        state = process_deposit(
            state=state,
            deposit=deposit,
            slots_per_epoch=slots_per_epoch,
            deposit_contract_tree_depth=deposit_contract_tree_depth,
        )

    # Process genesis activations
    for validator_index, _ in enumerate(state.validator_registry):
        validator_index = ValidatorIndex(validator_index)
        is_enough_effective_balance = get_effective_balance(
            state.validator_balances,
            validator_index,
            max_deposit_amount,
        ) >= max_deposit_amount
        if is_enough_effective_balance:
            state = activate_validator(
                state=state,
                index=validator_index,
                is_genesis=True,
                genesis_epoch=genesis_epoch,
                slots_per_epoch=slots_per_epoch,
                activation_exit_delay=activation_exit_delay,
            )

    # TODO: chanege to hash_tree_root
    active_validator_indices = get_active_validator_indices(
        state.validator_registry,
        genesis_epoch,
    )
    genesis_active_index_root = hash_eth2(b''.join(
        [index.to_bytes(32, 'little') for index in active_validator_indices]))
    latest_active_index_roots = (
        genesis_active_index_root, ) * latest_active_index_roots_length
    state = state.copy(latest_active_index_roots=latest_active_index_roots, )

    current_shuffling_seed = generate_seed(
        state=state,
        epoch=genesis_epoch,
        slots_per_epoch=slots_per_epoch,
        min_seed_lookahead=min_seed_lookahead,
        activation_exit_delay=activation_exit_delay,
        latest_active_index_roots_length=latest_active_index_roots_length,
        latest_randao_mixes_length=latest_randao_mixes_length,
    )
    state = state.copy(current_shuffling_seed=current_shuffling_seed, )

    return state
Beispiel #14
0
def process_rewards_and_penalties(state: BeaconState,
                                  config: BeaconConfig) -> BeaconState:
    # Compute previous epoch active validator indices and the total balance they account for
    # for later use.
    previous_epoch_active_validator_indices = set(
        get_active_validator_indices(
            state.validator_registry,
            state.previous_epoch(config.SLOTS_PER_EPOCH,
                                 config.GENESIS_EPOCH)))
    previous_total_balance: Gwei = get_total_balance(
        state.validator_balances,
        tuple(previous_epoch_active_validator_indices),
        config.MAX_DEPOSIT_AMOUNT,
    )

    # Compute previous epoch attester indices and the total balance they account for
    # for later use.
    previous_epoch_attestations = get_previous_epoch_attestations(
        state,
        config.SLOTS_PER_EPOCH,
        config.GENESIS_EPOCH,
    )
    previous_epoch_attester_indices = get_attester_indices_from_attesttion(
        state=state,
        attestations=previous_epoch_attestations,
        committee_config=CommitteeConfig(config),
    )

    # Compute inclusion slot/distance of previous attestations for later use.
    inclusion_infos = get_inclusion_infos(
        state=state,
        attestations=previous_epoch_attestations,
        committee_config=CommitteeConfig(config),
    )

    # Compute effective balance of each previous epoch active validator for later use
    effective_balances = {
        index: get_effective_balance(
            state.validator_balances,
            index,
            config.MAX_DEPOSIT_AMOUNT,
        )
        for index in previous_epoch_active_validator_indices
    }
    # Compute base reward of each previous epoch active validator for later use
    _base_reward_quotient = (integer_squareroot(previous_total_balance) //
                             config.BASE_REWARD_QUOTIENT)
    base_rewards = {
        index: get_base_reward(
            state=state,
            index=index,
            base_reward_quotient=_base_reward_quotient,
            max_deposit_amount=config.MAX_DEPOSIT_AMOUNT,
        )
        for index in previous_epoch_active_validator_indices
    }

    # Initialize the reward (validator) received map
    rewards_received = {
        index: SignedGwei(0)
        for index in previous_epoch_active_validator_indices
    }

    # 1. Process rewards and penalties for justification and finalization
    rewards_received = pipe(
        rewards_received,
        _process_rewards_and_penalties_for_finality(
            state,
            config,
            previous_epoch_active_validator_indices,
            previous_total_balance,
            previous_epoch_attestations,
            previous_epoch_attester_indices,
            inclusion_infos,
            effective_balances,
            base_rewards,
        ),
        _process_rewards_and_penalties_for_attestation_inclusion(
            state,
            config,
            previous_epoch_attester_indices,
            inclusion_infos,
            base_rewards,
        ),
        _process_rewards_and_penalties_for_crosslinks(
            state,
            config,
            previous_epoch_attestations,
            effective_balances,
            base_rewards,
        ))

    # Apply the overall rewards/penalties
    for index in previous_epoch_active_validator_indices:
        state = state.update_validator_balance(
            index,
            # Prevent validator balance under flow
            max(state.validator_balances[index] + rewards_received[index], 0),
        )

    return state
Beispiel #15
0
def process_rewards_and_penalties(state: BeaconState,
                                  config: Eth2Config) -> BeaconState:
    # Compute previous epoch active validator indices and the total balance they account for
    # for later use.
    previous_epoch_active_validator_indices = set(
        get_active_validator_indices(
            state.validator_registry,
            state.previous_epoch(config.SLOTS_PER_EPOCH)))
    previous_total_balance: Gwei = get_total_balance(
        state.validator_balances,
        tuple(previous_epoch_active_validator_indices),
        config.MAX_DEPOSIT_AMOUNT,
    )

    # Compute previous epoch attester indices and the total balance they account for
    # for later use.
    previous_epoch_attestations = state.previous_epoch_attestations
    previous_epoch_attester_indices = get_attester_indices_from_attestations(
        state=state,
        attestations=previous_epoch_attestations,
        committee_config=CommitteeConfig(config),
    )

    # Compute inclusion slot/distance of previous attestations for later use.
    inclusion_infos = get_inclusion_infos(
        state=state,
        attestations=previous_epoch_attestations,
        committee_config=CommitteeConfig(config),
    )

    # Compute effective balance of each previous epoch active validator for later use
    effective_balances = {
        ValidatorIndex(index): get_effective_balance(
            state.validator_balances,
            ValidatorIndex(index),
            config.MAX_DEPOSIT_AMOUNT,
        )
        for index in range(len(state.validator_registry))
    }
    # Compute base reward of each previous epoch active validator for later use
    base_rewards = {
        ValidatorIndex(index): get_base_reward(
            state=state,
            index=ValidatorIndex(index),
            base_reward_quotient=config.BASE_REWARD_QUOTIENT,
            previous_total_balance=previous_total_balance,
            max_deposit_amount=config.MAX_DEPOSIT_AMOUNT,
        )
        for index in range(len(state.validator_registry))
    }

    # 1. Process rewards and penalties for justification and finalization
    finality_rewards, finality_penalties = _process_rewards_and_penalties_for_finality(
        state,
        config,
        previous_epoch_active_validator_indices,
        previous_total_balance,
        previous_epoch_attestations,
        previous_epoch_attester_indices,
        inclusion_infos,
        effective_balances,
        base_rewards,
    )
    # 2. Process rewards and penalties for crosslinks
    crosslinks_rewards, crosslinks_penalties = _process_rewards_and_penalties_for_crosslinks(
        state,
        config,
        effective_balances,
        base_rewards,
    )

    # Apply the overall rewards/penalties
    for index in range(len(state.validator_registry)):
        state = state.update_validator_balance(
            ValidatorIndex(index),
            # Prevent validator balance under flow
            max(
                (state.validator_balances[index] + finality_rewards[index] +
                 crosslinks_rewards[index] - finality_penalties[index] -
                 crosslinks_penalties[index]),
                0,
            ),
        )

    return state
Beispiel #16
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
Beispiel #17
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]
Beispiel #18
0
def get_genesis_beacon_state(*,
                             genesis_validator_deposits: Sequence[Deposit],
                             genesis_time: Timestamp,
                             latest_eth1_data: Eth1Data,
                             genesis_slot: SlotNumber,
                             genesis_epoch: EpochNumber,
                             genesis_fork_version: int,
                             genesis_start_shard: ShardNumber,
                             shard_count: int,
                             seed_lookahead: int,
                             latest_block_roots_length: int,
                             latest_index_roots_length: int,
                             epoch_length: int,
                             max_deposit_amount: Gwei,
                             latest_penalized_exit_length: int,
                             latest_randao_mixes_length: int,
                             entry_exit_delay: int) -> BeaconState:
    state = BeaconState(
        # Misc
        slot=genesis_slot,
        genesis_time=genesis_time,
        fork=Fork(
            previous_version=genesis_fork_version,
            current_version=genesis_fork_version,
            epoch=genesis_epoch,
        ),

        # Validator registry
        validator_registry=(),
        validator_balances=(),
        validator_registry_update_epoch=genesis_epoch,

        # Randomness and committees
        latest_randao_mixes=(ZERO_HASH32,) * latest_randao_mixes_length,
        previous_epoch_start_shard=genesis_start_shard,
        current_epoch_start_shard=genesis_start_shard,
        previous_calculation_epoch=genesis_epoch,
        current_calculation_epoch=genesis_epoch,
        previous_epoch_seed=ZERO_HASH32,
        current_epoch_seed=ZERO_HASH32,

        # Finality
        previous_justified_epoch=genesis_epoch,
        justified_epoch=genesis_epoch,
        justification_bitfield=0,
        finalized_epoch=genesis_epoch,

        # Recent state
        latest_crosslinks=(
            (CrosslinkRecord(epoch=genesis_epoch, shard_block_root=ZERO_HASH32),) * shard_count
        ),
        latest_block_roots=(ZERO_HASH32,) * latest_block_roots_length,
        latest_index_roots=(ZERO_HASH32,) * latest_index_roots_length,
        latest_penalized_balances=(Gwei(0),) * latest_penalized_exit_length,
        latest_attestations=(),
        batched_block_roots=(),

        # Ethereum 1.0 chain data
        latest_eth1_data=latest_eth1_data,
        eth1_data_votes=(),
        deposit_index=len(genesis_validator_deposits),
    )

    # Process initial deposits
    for deposit in genesis_validator_deposits:
        state = process_deposit(
            state=state,
            pubkey=deposit.deposit_data.deposit_input.pubkey,
            amount=deposit.deposit_data.amount,
            proof_of_possession=deposit.deposit_data.deposit_input.proof_of_possession,
            withdrawal_credentials=deposit.deposit_data.deposit_input.withdrawal_credentials,
            epoch_length=epoch_length,
        )

    # Process initial activations
    for validator_index, _ in enumerate(state.validator_registry):
        validator_index = ValidatorIndex(validator_index)
        is_enough_effective_balance = get_effective_balance(
            state.validator_balances,
            validator_index,
            max_deposit_amount,
        ) >= max_deposit_amount
        if is_enough_effective_balance:
            state = activate_validator(
                state=state,
                index=validator_index,
                is_genesis=True,
                genesis_epoch=genesis_epoch,
                epoch_length=epoch_length,
                entry_exit_delay=entry_exit_delay,
            )

    # TODO: chanege to hash_tree_root
    active_validator_indices = get_active_validator_indices(
        state.validator_registry,
        genesis_epoch,
    )
    genesis_active_index_root = hash_eth2(
        b''.join(
            [
                index.to_bytes(32, 'big')
                for index in active_validator_indices
            ]
        )
    )
    latest_index_roots = (genesis_active_index_root,) * latest_index_roots_length
    state = state.copy(
        latest_index_roots=latest_index_roots,
    )

    current_epoch_seed = generate_seed(
        state=state,
        epoch=genesis_epoch,
        epoch_length=epoch_length,
        seed_lookahead=seed_lookahead,
        entry_exit_delay=entry_exit_delay,
        latest_index_roots_length=latest_index_roots_length,
        latest_randao_mixes_length=latest_randao_mixes_length,
    )
    state = state.copy(
        current_epoch_seed=current_epoch_seed,
    )

    return state
Beispiel #19
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