From a4722faf121d4db04bf79db84c6d93d2a2d09da5 Mon Sep 17 00:00:00 2001 From: Justin Date: Tue, 4 Dec 2018 19:49:26 +0000 Subject: [PATCH] Handle activations and exits separately for balance churn (#230) This change is to avoid deposits from fully consuming the allowable balance churn, preventing exits from being processed. And vice versa with deposits/exits swapped. A bunch of cleanups and bug fixes were made along the way. --- specs/core/0_beacon-chain.md | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index c91d7b110..3a1a66ea5 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1446,38 +1446,52 @@ def get_changed_validators(validators: List[ValidatorRecord], """ # The active validators active_validator_indices = get_active_validator_indices(validators) - # The total balance of active validators + # The total effective balance of active validators total_balance = sum([get_effective_balance(v) for i, v in enumerate(validators) if i in active_validator_indices]) - # The maximum total Gwei that can be deposited and withdrawn - max_allowable_change = max( - 2 * MAX_DEPOSIT * GWEI_PER_ETH, - total_balance // MAX_BALANCE_CHURN_QUOTIENT + + # The maximum balance churn in Gwei (for deposits and exits separately) + max_balance_churn = max( + MAX_DEPOSIT * GWEI_PER_ETH, + total_balance // (2 * MAX_BALANCE_CHURN_QUOTIENT) ) - # Go through the list start to end, depositing and withdrawing as many as possible - total_changed = 0 + + # Activate validators within the allowable balance churn + balance_churn = 0 for i in range(len(validators)): if validators[i].status == PENDING_ACTIVATION and validators[i].balance >= MAX_DEPOSIT: + # Check the balance churn would be within the allowance + balance_churn += get_effective_balance(validators[i]) + if balance_churn > max_balance_churn: + break + + # Activate validator validators[i].status = ACTIVE validators[i].latest_status_change_slot = current_slot - total_changed += get_effective_balance(validators[i]) validator_registry_delta_chain_tip = get_new_validator_registry_delta_chain_tip( validator_registry_delta_chain_tip=validator_registry_delta_chain_tip, index=i, pubkey=validators[i].pubkey, flag=ACTIVATION, ) + + # Exit validators within the allowable balance churn + balance_churn = 0 + for i in range(len(validators)): if validators[i].status == ACTIVE_PENDING_EXIT: + # Check the balance churn would be within the allowance + balance_churn += get_effective_balance(validators[i]) + if balance_churn > max_balance_churn: + break + + # Exit validator validators[i].status = EXITED_WITHOUT_PENALTY validators[i].latest_status_change_slot = current_slot - total_changed += get_effective_balance(validators[i]) validator_registry_delta_chain_tip = get_new_validator_registry_delta_chain_tip( validator_registry_delta_chain_tip=validator_registry_delta_chain_tip, index=i, pubkey=validators[i].pubkey, flag=EXIT, ) - if total_changed >= max_allowable_change: - break # Calculate the total ETH that has been penalized in the last ~2-3 withdrawal periods period_index = current_slot // COLLECTIVE_PENALTY_CALCULATION_PERIOD