diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index c4892a56a..14a387467 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -112,14 +112,10 @@ - [State caching](#state-caching) - [Per-epoch processing](#per-epoch-processing) - [Helper functions](#helper-functions-1) - - [Justification](#justification) + - [Justification and finalization](#justification-and-finalization) - [Crosslinks](#crosslinks) - [Rewards and penalties](#rewards-and-penalties) - - [Justification and finalization](#justification-and-finalization) - - [Crosslinks](#crosslinks-1) - - [Apply rewards](#apply-rewards) - - [Balance-driven status transitions](#balance-driven-status-transitions) - - [Activation queue and start shard](#activation-queue-and-start-shard) + - [Registry updates](#registry-updates) - [Slashings](#slashings) - [Final updates](#final-updates) - [Per-slot processing](#per-slot-processing) @@ -1667,16 +1663,17 @@ def get_earliest_attestation(state: BeaconState, attestations: List[PendingAttes ], key=lambda a: a.inclusion_slot) ``` -#### Justification +#### Justification and finalization Run the following function: ```python -def update_justification_and_finalization(state: BeaconState) -> None: +def process_justification_and_finalization(state: BeaconState) -> None: if get_current_epoch(state) <= GENESIS_EPOCH + 1: return - antepenultimate_justified_epoch = state.previous_justified_epoch + old_previous_justified_epoch = state.previous_justified_epoch + old_current_justified_epoch = state.current_justified_epoch # Process justifications state.previous_justified_epoch = state.current_justified_epoch @@ -1697,20 +1694,20 @@ def update_justification_and_finalization(state: BeaconState) -> None: bitfield = state.justification_bitfield current_epoch = get_current_epoch(state) # The 2nd/3rd/4th most recent epochs are justified, the 2nd using the 4th as source - if (bitfield >> 1) % 8 == 0b111 and antepenultimate_justified_epoch == current_epoch - 3: - state.finalized_epoch = antepenultimate_justified_epoch + if (bitfield >> 1) % 8 == 0b111 and old_previous_justified_epoch == current_epoch - 3: + state.finalized_epoch = old_previous_justified_epoch state.finalized_root = get_block_root(state, get_epoch_start_slot(state.finalized_epoch)) # The 2nd/3rd most recent epochs are justified, the 2nd using the 3rd as source - if (bitfield >> 1) % 4 == 0b11 and antepenultimate_justified_epoch == current_epoch - 2: - state.finalized_epoch = antepenultimate_justified_epoch + if (bitfield >> 1) % 4 == 0b11 and old_previous_justified_epoch == current_epoch - 2: + state.finalized_epoch = old_previous_justified_epoch state.finalized_root = get_block_root(state, get_epoch_start_slot(state.finalized_epoch)) # The 1st/2nd/3rd most recent epochs are justified, the 1st using the 3rd as source - if (bitfield >> 0) % 8 == 0b111 and state.previous_justified_epoch == current_epoch - 2: - state.finalized_epoch = state.previous_justified_epoch + if (bitfield >> 0) % 8 == 0b111 and old_current_justified_epoch == current_epoch - 2: + state.finalized_epoch = old_current_justified_epoch state.finalized_root = get_block_root(state, get_epoch_start_slot(state.finalized_epoch)) # The 1st/2nd most recent epochs are justified, the 1st using the 2nd as source - if (bitfield >> 0) % 4 == 0b11 and state.previous_justified_epoch == current_epoch - 1: - state.finalized_epoch = state.previous_justified_epoch + if (bitfield >> 0) % 4 == 0b11 and old_current_justified_epoch == current_epoch - 1: + state.finalized_epoch = old_current_justified_epoch state.finalized_root = get_block_root(state, get_epoch_start_slot(state.finalized_epoch)) ``` @@ -1732,7 +1729,7 @@ def process_crosslinks(state: BeaconState) -> None: #### Rewards and penalties -First, we define some additional helpers: +First, we define additional helpers: ```python def get_base_reward_from_total_balance(state: BeaconState, total_balance: Gwei, index: ValidatorIndex) -> Gwei: @@ -1757,10 +1754,6 @@ def get_inactivity_penalty(state: BeaconState, index: ValidatorIndex, epochs_sin return get_base_reward(state, index) + extra_penalty ``` -Note: When applying penalties in the following balance recalculations, implementers should make sure the `uint64` does not underflow. - -##### Justification and finalization - ```python def get_justification_and_finalization_deltas(state: BeaconState) -> Tuple[List[Gwei], List[Gwei]]: current_epoch = get_current_epoch(state) @@ -1809,8 +1802,6 @@ def get_justification_and_finalization_deltas(state: BeaconState) -> Tuple[List[ return [rewards, penalties] ``` -##### Crosslinks - ```python def get_crosslink_deltas(state: BeaconState) -> Tuple[List[Gwei], List[Gwei]]: rewards = [0 for index in range(len(state.validator_registry))] @@ -1828,12 +1819,10 @@ def get_crosslink_deltas(state: BeaconState) -> Tuple[List[Gwei], List[Gwei]]: return [rewards, penalties] ``` -#### Apply rewards - -Run the following: +Run the following function: ```python -def apply_rewards(state: BeaconState) -> None: +def process_rewards_and_penalties(state: BeaconState) -> None: if get_current_epoch(state) == GENESIS_EPOCH: return @@ -1844,16 +1833,13 @@ def apply_rewards(state: BeaconState) -> None: decrease_balance(state, i, penalties1[i] + penalties2[i]) ``` -#### Balance-driven status transitions +#### Registry updates -Run `process_balance_driven_status_transitions(state)`. +Run the following function: ```python -def process_balance_driven_status_transitions(state: BeaconState) -> None: - """ - Iterate through the validator registry - and deposit or eject active validators with sufficiently high or low balances - """ +def process_registry_updates(state: BeaconState) -> None: + # Process activation eligibility and ejections for index, validator in enumerate(state.validator_registry): balance = get_balance(state, index) if validator.activation_eligibility_epoch == FAR_FUTURE_EPOCH and balance >= MAX_DEPOSIT_AMOUNT: @@ -1861,39 +1847,23 @@ def process_balance_driven_status_transitions(state: BeaconState) -> None: if is_active_validator(validator, get_current_epoch(state)) and balance < EJECTION_BALANCE: initiate_validator_exit(state, index) -``` -#### Activation queue and start shard - -Run the following function: - -```python -def update_registry(state: BeaconState) -> None: + # Process activations activation_queue = sorted([ index for index, validator in enumerate(state.validator_registry) if validator.activation_eligibility_epoch != FAR_FUTURE_EPOCH and validator.activation_epoch >= get_delayed_activation_exit_epoch(state.finalized_epoch) ], key=lambda index: state.validator_registry[index].activation_eligibility_epoch) - for index in activation_queue[:get_churn_limit(state)]: activate_validator(state, index) - - state.latest_start_shard = ( - state.latest_start_shard + - get_shard_delta(state, get_current_epoch(state)) - ) % SHARD_COUNT ``` #### Slashings -Run `process_slashings(state)`: +Run the following function: ```python def process_slashings(state: BeaconState) -> None: - """ - Process the slashings. - Note that this function mutates ``state``. - """ current_epoch = get_current_epoch(state) active_validator_indices = get_active_validator_indices(state, current_epoch) total_balance = get_total_balance(state, active_validator_indices) @@ -1917,12 +1887,14 @@ def process_slashings(state: BeaconState) -> None: Run the following function: ```python -def finish_epoch_update(state: BeaconState) -> None: +def process_final_updates(state: BeaconState) -> None: current_epoch = get_current_epoch(state) next_epoch = current_epoch + 1 # Reset eth1 data votes if state.slot % SLOTS_PER_ETH1_VOTING_PERIOD == 0: state.eth1_data_votes = [] + # Update start shard + state.latest_start_shard = (state.latest_start_shard + get_shard_delta(state, current_epoch)) % SHARD_COUNT # Set active index root index_root_position = (next_epoch + ACTIVATION_EXIT_DELAY) % LATEST_ACTIVE_INDEX_ROOTS_LENGTH state.latest_active_index_roots[index_root_position] = hash_tree_root( @@ -2135,7 +2107,7 @@ def process_proposer_attestation_rewards(state: BeaconState) -> None: ##### Deposits -Verify that `len(block.body.deposits) == min(MAX_DEPOSITS, latest_eth1_data.deposit_count - state.deposit_index)`. +Verify that `len(block.body.deposits) == min(MAX_DEPOSITS, state.latest_eth1_data.deposit_count - state.deposit_index)`. For each `deposit` in `block.body.deposits`, run the following function: diff --git a/test_libs/pyspec/eth2spec/phase0/state_transition.py b/test_libs/pyspec/eth2spec/phase0/state_transition.py index f43e2791b..38ecd2a02 100644 --- a/test_libs/pyspec/eth2spec/phase0/state_transition.py +++ b/test_libs/pyspec/eth2spec/phase0/state_transition.py @@ -91,13 +91,12 @@ def process_block(state: BeaconState, def process_epoch_transition(state: BeaconState) -> None: - spec.update_justification_and_finalization(state) + spec.process_justification_and_finalization(state) spec.process_crosslinks(state) - spec.apply_rewards(state) - spec.process_balance_driven_status_transitions(state) - spec.update_registry(state) + spec.process_rewards_and_penalties(state) + spec.process_registry_updates(state) spec.process_slashings(state) - spec.finish_epoch_update(state) + spec.process_final_updates(state) def state_transition_to(state: BeaconState, up_to: Slot) -> BeaconState: