diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 184811b52..84e9e4230 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -59,8 +59,6 @@ - [`is_active_validator`](#is_active_validator) - [`is_slashable_validator`](#is_slashable_validator) - [`get_active_validator_indices`](#get_active_validator_indices) - - [`get_balance`](#get_balance) - - [`set_balance`](#set_balance) - [`increase_balance`](#increase_balance) - [`decrease_balance`](#decrease_balance) - [`get_permuted_index`](#get_permuted_index) @@ -178,7 +176,7 @@ These configurations are updated for releases, but may be out of sync during `de | `MAX_INDICES_PER_ATTESTATION` | `2**12` (= 4,096) | | `MIN_PER_EPOCH_CHURN_LIMIT` | `2**2` (= 4) | | `CHURN_LIMIT_QUOTIENT` | `2**16` (= 65,536) | -| `BASE_REWARDS_PER_EPOCH` | `4` | +| `BASE_REWARDS_PER_EPOCH` | `5` | | `SHUFFLE_ROUND_COUNT` | 90 | * For the safety of crosslinks `TARGET_COMMITTEE_SIZE` exceeds [the recommended minimum committee size of 111](https://vitalik.ca/files/Ithaca201807_Sharding.pdf); with sufficient active validators (at least `SLOTS_PER_EPOCH * TARGET_COMMITTEE_SIZE`), the shuffling algorithm ensures committee sizes of at least `TARGET_COMMITTEE_SIZE`. (Unbiasable randomness with a Verifiable Delay Function (VDF) will improve committee robustness and lower the safe minimum committee size.) @@ -410,7 +408,7 @@ The types are defined topologically to aid in facilitating an executable version # Was the validator slashed 'slashed': 'bool', # Rounded balance - 'high_balance': 'uint64' + 'effective_balance': 'uint64', } ``` @@ -733,29 +731,19 @@ def get_active_validator_indices(state: BeaconState, epoch: Epoch) -> List[Valid return [i for i, v in enumerate(state.validator_registry) if is_active_validator(v, epoch)] ``` -### `get_balance` +### `get_next_epoch_effective_balance` ```python -def get_balance(state: BeaconState, index: ValidatorIndex) -> Gwei: +def get_next_epoch_effective_balance(state: BeaconState, index: ValidatorIndex) -> None: """ - Return the balance for a validator with the given ``index``. - """ - return state.balances[index] -``` - -### `set_balance` - -```python -def set_balance(state: BeaconState, index: ValidatorIndex, balance: Gwei) -> None: - """ - Set the balance for a validator with the given ``index`` in both ``BeaconState`` - and validator's rounded balance ``high_balance``. + Get validator effective balance for the next epoch """ + balance = min(state.balances[index], MAX_DEPOSIT_AMOUNT) validator = state.validator_registry[index] HALF_INCREMENT = HIGH_BALANCE_INCREMENT // 2 - if validator.high_balance > balance or validator.high_balance + 3 * HALF_INCREMENT < balance: - validator.high_balance = balance - balance % HIGH_BALANCE_INCREMENT - state.balances[index] = balance + if validator.effective_balance > balance or validator.effective_balance + 3 * HALF_INCREMENT < balance: + return balance - balance % HIGH_BALANCE_INCREMENT + return validator.effective_balance ``` ### `increase_balance` @@ -763,9 +751,9 @@ def set_balance(state: BeaconState, index: ValidatorIndex, balance: Gwei) -> Non ```python def increase_balance(state: BeaconState, index: ValidatorIndex, delta: Gwei) -> None: """ - Increase the balance for a validator with the given ``index`` by ``delta``. + Increase validator balance by ``delta``. """ - set_balance(state, index, get_balance(state, index) + delta) + state.balances[index] += delta ``` ### `decrease_balance` @@ -773,11 +761,9 @@ def increase_balance(state: BeaconState, index: ValidatorIndex, delta: Gwei) -> ```python def decrease_balance(state: BeaconState, index: ValidatorIndex, delta: Gwei) -> None: """ - Decrease the balance for a validator with the given ``index`` by ``delta``. - Set to ``0`` when underflow. + Decrease validator balance by ``delta`` with underflow protection. """ - current_balance = get_balance(state, index) - set_balance(state, index, current_balance - delta if current_balance >= delta else 0) + state.balances[index] = state.balances[index] - delta if state.balances[index] >= delta else 0 ``` ### `get_permuted_index` @@ -969,18 +955,17 @@ def generate_seed(state: BeaconState, ### `get_beacon_proposer_index` ```python -def get_beacon_proposer_index(state: BeaconState) -> ValidatorIndex: +def get_beacon_proposer_index(state: BeaconState, slot: Slot=None) -> ValidatorIndex: """ - Return the beacon proposer index at ``state.slot``. + Return the beacon proposer index at ``slot``. """ current_epoch = get_current_epoch(state) - - first_committee, _ = get_crosslink_committees_at_slot(state, state.slot)[0] + first_committee, _ = get_crosslink_committees_at_slot(state, slot if slot != None else state.slot)[0] i = 0 while True: candidate = first_committee[(current_epoch + i) % len(first_committee)] random_byte = hash(generate_seed(state, current_epoch) + int_to_bytes8(i // 32))[i % 32] - if get_effective_balance(state, candidate) * 256 > MAX_DEPOSIT_AMOUNT * random_byte: + if get_effective_balance(state, candidate, current_epoch) * 256 > MAX_DEPOSIT_AMOUNT * random_byte: return candidate i += 1 ``` @@ -1031,21 +1016,21 @@ def bytes_to_int(data: bytes) -> int: ### `get_effective_balance` ```python -def get_effective_balance(state: BeaconState, index: ValidatorIndex) -> Gwei: +def get_effective_balance(state: BeaconState, index: ValidatorIndex, epoch: Epoch) -> Gwei: """ Return the effective balance (also known as "balance at stake") for a validator with the given ``index``. """ - return min(get_balance(state, index), MAX_DEPOSIT_AMOUNT) + return state.validator_registry[index].effective_balance if epoch == get_current_epoch(state) else get_next_epoch_effective_balance(state, index) ``` ### `get_total_balance` ```python -def get_total_balance(state: BeaconState, validators: List[ValidatorIndex]) -> Gwei: +def get_total_balance(state: BeaconState, validators: List[ValidatorIndex], epoch: Epoch) -> Gwei: """ Return the combined effective balance of an array of ``validators``. """ - return sum([get_effective_balance(state, i) for i in validators]) + return sum([get_effective_balance(state, i, epoch) for i in validators]) ``` ### `get_fork_version` @@ -1290,11 +1275,12 @@ def slash_validator(state: BeaconState, slashed_index: ValidatorIndex, whistlebl Slash the validator with index ``slashed_index``. Note that this function mutates ``state``. """ + current_epoch = get_current_epoch(state) initiate_validator_exit(state, slashed_index) state.validator_registry[slashed_index].slashed = True - state.validator_registry[slashed_index].withdrawable_epoch = get_current_epoch(state) + LATEST_SLASHED_EXIT_LENGTH - slashed_balance = get_effective_balance(state, slashed_index) - state.latest_slashed_balances[get_current_epoch(state) % LATEST_SLASHED_EXIT_LENGTH] += slashed_balance + state.validator_registry[slashed_index].withdrawable_epoch = current_epoch + LATEST_SLASHED_EXIT_LENGTH + slashed_balance = get_effective_balance(state, slashed_index, current_epoch) + state.latest_slashed_balances[current_epoch % LATEST_SLASHED_EXIT_LENGTH] += slashed_balance proposer_index = get_beacon_proposer_index(state) if whistleblower_index is None: @@ -1447,8 +1433,8 @@ def get_genesis_beacon_state(genesis_validator_deposits: List[Deposit], process_deposit(state, deposit) # Process genesis activations - for index in range(len(state.validator_registry)): - if get_effective_balance(state, index) >= MAX_DEPOSIT_AMOUNT: + for index, validator in enumerate(state.validator_registry): + if validator.effective_balance >= MAX_DEPOSIT_AMOUNT: activate_validator(state, index) genesis_active_index_root = hash_tree_root(get_active_validator_indices(state, GENESIS_EPOCH)) @@ -1520,7 +1506,7 @@ def lmd_ghost(store: Store, start_state: BeaconState, start_block: BeaconBlock) # made for optimized implementations that precompute and save data def get_vote_count(block: BeaconBlock) -> int: return sum( - start_state.validator_registry[validator_index].high_balance + start_state.validator_registry[validator_index].effective_balance for validator_index, target in attestation_targets if get_ancestor(store, target, block.slot) == block ) @@ -1581,38 +1567,27 @@ The steps below happen when `state.slot > GENESIS_SLOT and (state.slot + 1) % SL We define epoch transition helper functions: ```python -def get_previous_epoch_total_balance(state: BeaconState) -> Gwei: - return get_total_balance(state, get_active_validator_indices(state, get_previous_epoch(state))) +def get_total_active_balance(state: BeaconState, epoch: Epoch) -> Gwei: + return get_total_balance(state, get_active_validator_indices(state, epoch), epoch) ``` -Note: The balance computed by `get_previous_epoch_total_balance` may be different to the actual total balance during the previous epoch transition. Due to the bounds on per-epoch validator churn and per-epoch rewards/penalties, the maximum balance difference is low and only marginally affects consensus safety. - ```python -def get_current_epoch_total_balance(state: BeaconState) -> Gwei: - return get_total_balance(state, get_active_validator_indices(state, get_current_epoch(state))) +def get_matching_source_attestations(state: BeaconState, epoch: Epoch) -> List[PendingAttestation]: + return state.current_epoch_attestations if epoch == get_current_epoch(state) else state.previous_epoch_attestations ``` - ```python -def get_current_epoch_matching_target_attestations(state: BeaconState) -> List[PendingAttestation]: +def get_matching_target_attestations(state: BeaconState, epoch: Epoch) -> List[PendingAttestation]: return [ - a for a in state.current_epoch_attestations - if a.data.target_root == get_block_root(state, get_epoch_start_slot(get_current_epoch(state))) + a for a in get_matching_source_attestations(state, epoch) + if a.data.target_root == get_block_root(state, get_epoch_start_slot(epoch)) ] ``` ```python -def get_previous_epoch_matching_target_attestations(state: BeaconState) -> List[PendingAttestation]: +def get_matching_head_attestations(state: BeaconState, epoch: Epoch) -> List[PendingAttestation]: return [ - a for a in state.previous_epoch_attestations - if a.data.target_root == get_block_root(state, get_epoch_start_slot(get_previous_epoch(state))) - ] -``` - -```python -def get_previous_epoch_matching_head_attestations(state: BeaconState) -> List[PendingAttestation]: - return [ - a for a in state.previous_epoch_attestations + a for a in get_matching_source_attestations(state, epoch) if a.data.beacon_block_root == get_block_root(state, a.data.slot) ] ``` @@ -1626,8 +1601,8 @@ def get_unslashed_attesting_indices(state: BeaconState, attestations: List[Pendi ``` ```python -def get_attesting_balance(state: BeaconState, attestations: List[PendingAttestation]) -> Gwei: - return get_total_balance(state, get_unslashed_attesting_indices(state, attestations)) +def get_attesting_balance(state: BeaconState, attestations: List[PendingAttestation], epoch: Epoch) -> Gwei: + return get_total_balance(state, get_unslashed_attesting_indices(state, attestations), epoch) ``` ```python @@ -1641,8 +1616,8 @@ def get_crosslink_from_attestation_data(state: BeaconState, data: AttestationDat ```python def get_winning_crosslink_and_attesting_indices(state: BeaconState, epoch: Epoch, shard: Shard) -> Tuple[Crosslink, List[ValidatorIndex]]: - pending_attestations = state.current_epoch_attestations if epoch == get_current_epoch(state) else state.previous_epoch_attestations - shard_attestations = [a for a in pending_attestations if a.data.shard == shard] + attestations = get_matching_source_attestations(state, epoch) + shard_attestations = [a for a in attestations if a.data.shard == shard] shard_crosslinks = [get_crosslink_from_attestation_data(state, a.data) for a in shard_attestations] candidate_crosslinks = [ c for c in shard_crosslinks @@ -1655,7 +1630,7 @@ def get_winning_crosslink_and_attesting_indices(state: BeaconState, epoch: Epoch return [a for a in shard_attestations if get_crosslink_from_attestation_data(state, a.data) == crosslink] # Winning crosslink has the crosslink data root with the most balance voting for it (ties broken lexicographically) winning_crosslink = max(candidate_crosslinks, key=lambda crosslink: ( - get_attesting_balance(state, get_attestations_for(crosslink)), crosslink.crosslink_data_root + get_attesting_balance(state, get_attestations_for(crosslink), epoch), crosslink.crosslink_data_root )) return winning_crosslink, get_unslashed_attesting_indices(state, get_attestations_for(winning_crosslink)) @@ -1684,13 +1659,15 @@ def process_justification_and_finalization(state: BeaconState) -> None: state.previous_justified_epoch = state.current_justified_epoch state.previous_justified_root = state.current_justified_root state.justification_bitfield = (state.justification_bitfield << 1) % 2**64 - previous_epoch_matching_target_balance = get_attesting_balance(state, get_previous_epoch_matching_target_attestations(state)) - if previous_epoch_matching_target_balance * 3 >= get_previous_epoch_total_balance(state) * 2: + epoch = get_previous_epoch(state) + previous_epoch_matching_target_balance = get_attesting_balance(state, get_matching_target_attestations(state, epoch), epoch) + if previous_epoch_matching_target_balance * 3 >= get_total_active_balance(state, epoch) * 2: state.current_justified_epoch = get_previous_epoch(state) state.current_justified_root = get_block_root(state, get_epoch_start_slot(state.current_justified_epoch)) state.justification_bitfield |= (1 << 1) - current_epoch_matching_target_balance = get_attesting_balance(state, get_current_epoch_matching_target_attestations(state)) - if current_epoch_matching_target_balance * 3 >= get_current_epoch_total_balance(state) * 2: + epoch = get_current_epoch(state) + current_epoch_matching_target_balance = get_attesting_balance(state, get_matching_target_attestations(state, epoch), epoch) + if current_epoch_matching_target_balance * 3 >= get_total_active_balance(state, epoch) * 2: state.current_justified_epoch = get_current_epoch(state) state.current_justified_root = get_block_root(state, get_epoch_start_slot(state.current_justified_epoch)) state.justification_bitfield |= (1 << 0) @@ -1726,9 +1703,10 @@ def process_crosslinks(state: BeaconState) -> None: previous_epoch = get_previous_epoch(state) next_epoch = get_current_epoch(state) + 1 for slot in range(get_epoch_start_slot(previous_epoch), get_epoch_start_slot(next_epoch)): + epoch = slot_to_epoch(slot) for crosslink_committee, shard in get_crosslink_committees_at_slot(state, slot): - winning_crosslink, attesting_indices = get_winning_crosslink_and_attesting_indices(state, slot_to_epoch(slot), shard) - if 3 * get_total_balance(state, attesting_indices) >= 2 * get_total_balance(state, crosslink_committee): + winning_crosslink, attesting_indices = get_winning_crosslink_and_attesting_indices(state, epoch, shard) + if 3 * get_total_balance(state, attesting_indices, epoch) >= 2 * get_total_balance(state, crosslink_committee, epoch): state.current_crosslinks[shard] = winning_crosslink ``` @@ -1737,52 +1715,53 @@ def process_crosslinks(state: BeaconState) -> None: First, we define additional helpers: ```python -def get_base_reward(state: BeaconState, total_balance: Gwei, index: ValidatorIndex) -> Gwei: +def get_base_reward(state: BeaconState, index: ValidatorIndex, epoch: Epoch) -> Gwei: + total_balance = get_total_active_balance(state, epoch) if total_balance == 0: return 0 adjusted_quotient = integer_squareroot(total_balance) // BASE_REWARD_QUOTIENT - return get_effective_balance(state, index) // adjusted_quotient // BASE_REWARDS_PER_EPOCH + return get_effective_balance(state, index, epoch) // adjusted_quotient // BASE_REWARDS_PER_EPOCH ``` ```python -def get_justification_and_finalization_deltas(state: BeaconState) -> Tuple[List[Gwei], List[Gwei]]: - previous_epoch = get_previous_epoch(state) - eligible_validators = [ +def get_attestation_deltas(state: BeaconState) -> Tuple[List[Gwei], List[Gwei]]: + epoch = get_previous_epoch(state) + eligible_validator_indices = [ index for index, validator in enumerate(state.validator_registry) - if ( - is_active_validator(validator, previous_epoch) or - (validator.slashed and previous_epoch < validator.withdrawable_epoch) - ) + if is_active_validator(validator, epoch) or (validator.slashed and epoch < validator.withdrawable_epoch) ] rewards = [0 for index in range(len(state.validator_registry))] penalties = [0 for index in range(len(state.validator_registry))] - for index in eligible_validators: - base_reward = get_base_reward(state, get_previous_epoch_total_balance(state), index) + for index in eligible_validator_indices: + base_reward = get_base_reward(state, index, epoch) - # Micro-incentives for matching FFG source, matching FFG target, and matching head + # Micro-incentives for attestations matching FFG source, FFG target, and head for attestations in ( - state.previous_epoch_attestations, # Matching FFG source - get_previous_epoch_matching_target_attestations(state), # Matching FFG target - get_previous_epoch_matching_head_attestations(state), # Matching head + get_matching_source_attestations(state, epoch), + get_matching_target_attestations(state, epoch), + get_matching_source_attestations(state, epoch), ): if index in get_unslashed_attesting_indices(state, attestations): - rewards[index] += base_reward * get_attesting_balance(state, attestations) // get_previous_epoch_total_balance(state) + rewards[index] += base_reward * get_attesting_balance(state, attestations, epoch) // get_total_active_balance(state, epoch) else: penalties[index] += base_reward - # Inclusion delay micro-penalty - if index in get_unslashed_attesting_indices(state, state.previous_epoch_attestations): - earliest_attestation = get_earliest_attestation(state, state.previous_epoch_attestations, index) + if index in get_unslashed_attesting_indices(state, get_matching_source_attestations(state, epoch)): + earliest_attestation = get_earliest_attestation(state, get_matching_source_attestations(state, epoch), index) + # Proposer micro-rewards + proposer_index = get_beacon_proposer_index(state, earliest_attestation.inclusion_slot) + rewards[proposer_index] += base_reward // PROPOSER_REWARD_QUOTIENT + # Inclusion delay micro-rewards inclusion_delay = earliest_attestation.inclusion_slot - earliest_attestation.data.slot - penalties[index] += base_reward * (inclusion_delay - MIN_ATTESTATION_INCLUSION_DELAY) // (SLOTS_PER_EPOCH - MIN_ATTESTATION_INCLUSION_DELAY) + rewards[index] += base_reward * MIN_ATTESTATION_INCLUSION_DELAY // inclusion_delay # Inactivity penalty - epochs_since_finality = previous_epoch - state.finalized_epoch - if epochs_since_finality > MIN_EPOCHS_TO_INACTIVITY_PENALTY: + finality_delay = epoch - state.finalized_epoch + if finality_delay > MIN_EPOCHS_TO_INACTIVITY_PENALTY: penalties[index] += BASE_REWARDS_PER_EPOCH * base_reward - if index not in get_unslashed_attesting_indices(state, get_previous_epoch_matching_target_attestations(state)): - penalties[index] += get_effective_balance(state, index) * epochs_since_finality // INACTIVITY_PENALTY_QUOTIENT + if index not in get_unslashed_attesting_indices(state, get_matching_target_attestations(state, epoch)): + penalties[index] += get_effective_balance(state, index, epoch) * finality_delay // INACTIVITY_PENALTY_QUOTIENT return [rewards, penalties] ``` @@ -1792,12 +1771,13 @@ def get_crosslink_deltas(state: BeaconState) -> Tuple[List[Gwei], List[Gwei]]: rewards = [0 for index in range(len(state.validator_registry))] penalties = [0 for index in range(len(state.validator_registry))] for slot in range(get_epoch_start_slot(get_previous_epoch(state)), get_epoch_start_slot(get_current_epoch(state))): + epoch = slot_to_epoch(slot) for crosslink_committee, shard in get_crosslink_committees_at_slot(state, slot): - winning_crosslink, attesting_indices = get_winning_crosslink_and_attesting_indices(state, slot_to_epoch(slot), shard) - attesting_balance = get_total_balance(state, attesting_indices) - committee_balance = get_total_balance(state, crosslink_committee) + winning_crosslink, attesting_indices = get_winning_crosslink_and_attesting_indices(state, epoch, shard) + attesting_balance = get_total_balance(state, attesting_indices, epoch) + committee_balance = get_total_balance(state, crosslink_committee, epoch) for index in crosslink_committee: - base_reward = get_base_reward(state, get_previous_epoch_total_balance(state), index) + base_reward = get_base_reward(state, index, epoch) if index in attesting_indices: rewards[index] += base_reward * attesting_balance // committee_balance else: @@ -1812,7 +1792,7 @@ def process_rewards_and_penalties(state: BeaconState) -> None: if get_current_epoch(state) == GENESIS_EPOCH: return - rewards1, penalties1 = get_justification_and_finalization_deltas(state) + rewards1, penalties1 = get_attestation_deltas(state) rewards2, penalties2 = get_crosslink_deltas(state) for i in range(len(state.validator_registry)): increase_balance(state, i, rewards1[i] + rewards2[i]) @@ -1827,11 +1807,10 @@ Run the following function: 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: + if validator.activation_eligibility_epoch == FAR_FUTURE_EPOCH and validator.effective_balance >= MAX_DEPOSIT_AMOUNT: validator.activation_eligibility_epoch = get_current_epoch(state) - if is_active_validator(validator, get_current_epoch(state)) and balance < EJECTION_BALANCE: + if is_active_validator(validator, get_current_epoch(state)) and validator.effective_balance < EJECTION_BALANCE: initiate_validator_exit(state, index) # Process activations @@ -1852,7 +1831,7 @@ Run the following function: def process_slashings(state: BeaconState) -> None: 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) + total_balance = get_total_balance(state, active_validator_indices, current_epoch) # Compute `total_penalties` total_at_start = state.latest_slashed_balances[(current_epoch + 1) % LATEST_SLASHED_EXIT_LENGTH] @@ -1862,8 +1841,8 @@ def process_slashings(state: BeaconState) -> None: for index, validator in enumerate(state.validator_registry): if validator.slashed and current_epoch == validator.withdrawable_epoch - LATEST_SLASHED_EXIT_LENGTH // 2: penalty = max( - get_effective_balance(state, index) * min(total_penalties * 3, total_balance) // total_balance, - get_effective_balance(state, index) // MIN_PENALTY_QUOTIENT + get_effective_balance(state, index, current_epoch) * min(total_penalties * 3, total_balance) // total_balance, + get_effective_balance(state, index, current_epoch) // MIN_PENALTY_QUOTIENT ) decrease_balance(state, index, penalty) ``` @@ -1879,6 +1858,9 @@ def process_final_updates(state: BeaconState) -> None: # Reset eth1 data votes if state.slot % SLOTS_PER_ETH1_VOTING_PERIOD == 0: state.eth1_data_votes = [] + # Update effective balances + for index, validator in enumerate(state.validator_registry): + validator.effective_balance = get_next_epoch_effective_balance(state, index) # Update start shard state.latest_start_shard = (state.latest_start_shard + get_shard_delta(state, current_epoch)) % SHARD_COUNT # Set active index root @@ -2079,18 +2061,6 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None: state.previous_epoch_attestations.append(pending_attestation) ``` -Run `process_proposer_attestation_rewards(state)`. - -```python -def process_proposer_attestation_rewards(state: BeaconState) -> None: - proposer_index = get_beacon_proposer_index(state) - for pending_attestations in (state.previous_epoch_attestations, state.current_epoch_attestations): - for index in get_unslashed_attesting_indices(state, pending_attestations): - if get_earliest_attestation(state, pending_attestations, index).inclusion_slot == state.slot: - base_reward = get_base_reward(state, get_current_epoch_total_balance(state), index) - increase_balance(state, proposer_index, base_reward // PROPOSER_REWARD_QUOTIENT) -``` - ##### Deposits Verify that `len(block.body.deposits) == min(MAX_DEPOSITS, state.latest_eth1_data.deposit_count - state.deposit_index)`. @@ -2153,13 +2123,11 @@ def process_deposit(state: BeaconState, deposit: Deposit) -> None: exit_epoch=FAR_FUTURE_EPOCH, withdrawable_epoch=FAR_FUTURE_EPOCH, slashed=False, - high_balance=0 + effective_balance=amount - amount % HIGH_BALANCE_INCREMENT, ) - # Note: In phase 2 registry indices that have been withdrawn for a long time will be recycled. state.validator_registry.append(validator) - state.balances.append(0) - set_balance(state, len(state.validator_registry) - 1, amount) + state.balances.append(amount) else: # Increase balance by deposit amount index = validator_pubkeys.index(pubkey) @@ -2212,8 +2180,8 @@ def process_transfer(state: BeaconState, transfer: Transfer) -> None: Process ``Transfer`` operation. Note that this function mutates ``state``. """ - # Verify the amount and fee aren't individually too big (for anti-overflow purposes) - assert get_balance(state, transfer.sender) >= max(transfer.amount, transfer.fee) + # Verify the amount and fee are not individually too big (for anti-overflow purposes) + assert state.balances[transfer.sender] >= max(transfer.amount, transfer.fee) # A transfer is valid in only one slot assert state.slot == transfer.slot # Only withdrawn or not-yet-deposited accounts can transfer @@ -2238,8 +2206,8 @@ def process_transfer(state: BeaconState, transfer: Transfer) -> None: increase_balance(state, transfer.recipient, transfer.amount) increase_balance(state, get_beacon_proposer_index(state), transfer.fee) # Verify balances are not dust - assert not (0 < get_balance(state, transfer.sender) < MIN_DEPOSIT_AMOUNT) - assert not (0 < get_balance(state, transfer.recipient) < MIN_DEPOSIT_AMOUNT) + assert not (0 < state.balances[transfer.sender] < MIN_DEPOSIT_AMOUNT) + assert not (0 < state.balances[transfer.recipient] < MIN_DEPOSIT_AMOUNT) ``` #### State root verification diff --git a/specs/light_client/sync_protocol.md b/specs/light_client/sync_protocol.md index 900b2e64f..7b8388583 100644 --- a/specs/light_client/sync_protocol.md +++ b/specs/light_client/sync_protocol.md @@ -180,8 +180,8 @@ def verify_block_validity_proof(proof: BlockValidityProof, validator_memory: Val assert proof.shard_parent_block.beacon_chain_root == hash_tree_root(proof.header) committee = compute_committee(proof.header, validator_memory) # Verify that we have >=50% support - support_balance = sum([v.high_balance for i, v in enumerate(committee) if get_bitfield_bit(proof.shard_bitfield, i) is True]) - total_balance = sum([v.high_balance for i, v in enumerate(committee)]) + support_balance = sum([v.effective_balance for i, v in enumerate(committee) if get_bitfield_bit(proof.shard_bitfield, i) is True]) + total_balance = sum([v.effective_balance for i, v in enumerate(committee)]) assert support_balance * 2 > total_balance # Verify shard attestations group_public_key = bls_aggregate_pubkeys([ diff --git a/test_libs/pyspec/eth2spec/phase0/state_transition.py b/test_libs/pyspec/eth2spec/phase0/state_transition.py index 38ecd2a02..1bef358d4 100644 --- a/test_libs/pyspec/eth2spec/phase0/state_transition.py +++ b/test_libs/pyspec/eth2spec/phase0/state_transition.py @@ -11,7 +11,6 @@ from .spec import ( BeaconState, BeaconBlock, Slot, - process_proposer_attestation_rewards, ) @@ -52,7 +51,6 @@ def process_operations(state: BeaconState, block: BeaconBlock) -> None: spec.MAX_ATTESTATIONS, spec.process_attestation, ) - process_proposer_attestation_rewards(state) assert len(block.body.deposits) == expected_deposit_count(state) process_operation_type( diff --git a/test_libs/pyspec/tests/block_processing/test_process_attester_slashing.py b/test_libs/pyspec/tests/block_processing/test_process_attester_slashing.py index 84c19145a..bcaf6fb7a 100644 --- a/test_libs/pyspec/tests/block_processing/test_process_attester_slashing.py +++ b/test_libs/pyspec/tests/block_processing/test_process_attester_slashing.py @@ -3,11 +3,11 @@ import pytest import eth2spec.phase0.spec as spec from eth2spec.phase0.spec import ( - get_balance, get_beacon_proposer_index, process_attester_slashing, ) from tests.helpers import ( + get_balance, get_valid_attester_slashing, next_epoch, ) diff --git a/test_libs/pyspec/tests/block_processing/test_process_deposit.py b/test_libs/pyspec/tests/block_processing/test_process_deposit.py index 4031e650d..4fb8b3a1e 100644 --- a/test_libs/pyspec/tests/block_processing/test_process_deposit.py +++ b/test_libs/pyspec/tests/block_processing/test_process_deposit.py @@ -4,11 +4,11 @@ import pytest import eth2spec.phase0.spec as spec from eth2spec.phase0.spec import ( - get_balance, ZERO_HASH, process_deposit, ) from tests.helpers import ( + get_balance, build_deposit, privkeys, pubkeys, diff --git a/test_libs/pyspec/tests/block_processing/test_process_proposer_slashing.py b/test_libs/pyspec/tests/block_processing/test_process_proposer_slashing.py index 6d5f3045d..475221036 100644 --- a/test_libs/pyspec/tests/block_processing/test_process_proposer_slashing.py +++ b/test_libs/pyspec/tests/block_processing/test_process_proposer_slashing.py @@ -3,11 +3,11 @@ import pytest import eth2spec.phase0.spec as spec from eth2spec.phase0.spec import ( - get_balance, get_current_epoch, process_proposer_slashing, ) from tests.helpers import ( + get_balance, get_valid_proposer_slashing, ) diff --git a/test_libs/pyspec/tests/helpers.py b/test_libs/pyspec/tests/helpers.py index 44d2dcb4d..616f3b797 100644 --- a/test_libs/pyspec/tests/helpers.py +++ b/test_libs/pyspec/tests/helpers.py @@ -51,6 +51,8 @@ privkeys = [i + 1 for i in range(1000)] pubkeys = [bls.privtopub(privkey) for privkey in privkeys] pubkey_to_privkey = {pubkey: privkey for privkey, pubkey in zip(privkeys, pubkeys)} +def get_balance(state, index): + return state.balances[index] def set_bitfield_bit(bitfield, i): """ diff --git a/test_libs/pyspec/tests/test_sanity.py b/test_libs/pyspec/tests/test_sanity.py index 29333a7ad..508b07905 100644 --- a/test_libs/pyspec/tests/test_sanity.py +++ b/test_libs/pyspec/tests/test_sanity.py @@ -16,7 +16,6 @@ from eth2spec.phase0.spec import ( VoluntaryExit, # functions get_active_validator_indices, - get_balance, get_beacon_proposer_index, get_block_root, get_current_epoch, @@ -24,7 +23,6 @@ from eth2spec.phase0.spec import ( get_state_root, advance_slot, cache_state, - set_balance, slot_to_epoch, verify_merkle_branch, hash, @@ -38,6 +36,7 @@ from eth2spec.utils.merkle_minimal import ( get_merkle_root, ) from .helpers import ( + get_balance, build_deposit_data, build_empty_block_for_next_slot, fill_aggregate_attestation, @@ -53,7 +52,6 @@ from .helpers import ( # mark entire file as 'sanity' pytestmark = pytest.mark.sanity - def check_finality(state, prev_state, current_justified_changed, @@ -304,6 +302,7 @@ def test_deposit_top_up(state): def test_attestation(state): + state.slot = spec.SLOTS_PER_EPOCH test_state = deepcopy(state) attestation = get_valid_attestation(state) @@ -318,7 +317,6 @@ def test_attestation(state): assert len(test_state.current_epoch_attestations) == len(state.current_epoch_attestations) + 1 proposer_index = get_beacon_proposer_index(test_state) - assert test_state.balances[proposer_index] > state.balances[proposer_index] # # Epoch transition should move to previous_epoch_attestations @@ -443,7 +441,7 @@ def test_balance_driven_status_transitions(state): assert pre_state.validator_registry[validator_index].exit_epoch == spec.FAR_FUTURE_EPOCH # set validator balance to below ejection threshold - set_balance(pre_state, validator_index, spec.EJECTION_BALANCE - 1) + pre_state.validator_registry[validator_index].effective_balance = spec.EJECTION_BALANCE - 1 post_state = deepcopy(pre_state) #