From a02aac43c290b82d0d647e7a54e439257fdab1bf Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Tue, 18 Feb 2020 12:36:20 -0600 Subject: [PATCH 1/3] adjust hysteresis to avoid initial over-deposit incentive --- specs/phase0/beacon-chain.md | 7 +++++-- .../test_process_final_updates.py | 19 +++++++++++-------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/specs/phase0/beacon-chain.md b/specs/phase0/beacon-chain.md index acf098663..2e6c64be5 100644 --- a/specs/phase0/beacon-chain.md +++ b/specs/phase0/beacon-chain.md @@ -1402,8 +1402,11 @@ def process_final_updates(state: BeaconState) -> None: # Update effective balances with hysteresis for index, validator in enumerate(state.validators): balance = state.balances[index] - HALF_INCREMENT = EFFECTIVE_BALANCE_INCREMENT // 2 - if balance < validator.effective_balance or validator.effective_balance + 3 * HALF_INCREMENT < balance: + QUARTER_INCREMENT = EFFECTIVE_BALANCE_INCREMENT // 4 + if ( + balance + QUARTER_INCREMENT < validator.effective_balance + or validator.effective_balance + 7 * QUARTER_INCREMENT < balance + ): validator.effective_balance = min(balance - balance % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE) # Reset slashings state.slashings[next_epoch % EPOCHS_PER_SLASHINGS_VECTOR] = Gwei(0) diff --git a/tests/core/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_final_updates.py b/tests/core/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_final_updates.py index 58882a44f..b0d05427a 100644 --- a/tests/core/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_final_updates.py +++ b/tests/core/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_final_updates.py @@ -51,19 +51,22 @@ def test_effective_balance_hysteresis(spec, state): max = spec.MAX_EFFECTIVE_BALANCE min = spec.EJECTION_BALANCE inc = spec.EFFECTIVE_BALANCE_INCREMENT - half_inc = inc // 2 + quar_inc = inc // 4 cases = [ (max, max, max, "as-is"), - (max, max - 1, max - inc, "round down, step lower"), + (max, max - 1, max, "round up"), (max, max + 1, max, "round down"), + (max, max - quar_inc, max, "lower balance, but not low enough"), + (max, max - quar_inc, max, "lower balance, step down"), + (max, max + (3 * quar_inc) + 1, max, "already at max, as is"), (max, max - inc, max - inc, "exactly 1 step lower"), - (max, max - inc - 1, max - (2 * inc), "just 1 over 1 step lower"), + (max, max - inc - 1, max - (2 * inc), "past 1 step lower, double step"), (max, max - inc + 1, max - inc, "close to 1 step lower"), - (min, min + (half_inc * 3), min, "bigger balance, but not high enough"), - (min, min + (half_inc * 3) + 1, min + inc, "bigger balance, high enough, but small step"), - (min, min + (half_inc * 4) - 1, min + inc, "bigger balance, high enough, close to double step"), - (min, min + (half_inc * 4), min + (2 * inc), "exact two step balance increment"), - (min, min + (half_inc * 4) + 1, min + (2 * inc), "over two steps, round down"), + (min, min + (quar_inc * 7), min, "bigger balance, but not high enough"), + (min, min + (quar_inc * 7) + 1, min + inc, "bigger balance, high enough, but small step"), + (min, min + (quar_inc * 8) - 1, min + inc, "bigger balance, high enough, close to double step"), + (min, min + (quar_inc * 8), min + (2 * inc), "exact two step balance increment"), + (min, min + (quar_inc * 8) + 1, min + (2 * inc), "over two steps, round down"), ] current_epoch = spec.get_current_epoch(state) for i, (pre_eff, bal, _, _) in enumerate(cases): From 0122081d05cea01dbe70ceec383a8fc75b414f3c Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Mon, 2 Mar 2020 15:55:01 -0700 Subject: [PATCH 2/3] hysteresis to -0.25/+1.25 --- specs/phase0/beacon-chain.md | 2 +- .../phase_0/epoch_processing/test_process_final_updates.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/specs/phase0/beacon-chain.md b/specs/phase0/beacon-chain.md index 2e6c64be5..aa573ff16 100644 --- a/specs/phase0/beacon-chain.md +++ b/specs/phase0/beacon-chain.md @@ -1405,7 +1405,7 @@ def process_final_updates(state: BeaconState) -> None: QUARTER_INCREMENT = EFFECTIVE_BALANCE_INCREMENT // 4 if ( balance + QUARTER_INCREMENT < validator.effective_balance - or validator.effective_balance + 7 * QUARTER_INCREMENT < balance + or validator.effective_balance + 5 * QUARTER_INCREMENT < balance ): validator.effective_balance = min(balance - balance % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE) # Reset slashings diff --git a/tests/core/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_final_updates.py b/tests/core/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_final_updates.py index b0d05427a..36dae8fb7 100644 --- a/tests/core/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_final_updates.py +++ b/tests/core/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_final_updates.py @@ -62,8 +62,8 @@ def test_effective_balance_hysteresis(spec, state): (max, max - inc, max - inc, "exactly 1 step lower"), (max, max - inc - 1, max - (2 * inc), "past 1 step lower, double step"), (max, max - inc + 1, max - inc, "close to 1 step lower"), - (min, min + (quar_inc * 7), min, "bigger balance, but not high enough"), - (min, min + (quar_inc * 7) + 1, min + inc, "bigger balance, high enough, but small step"), + (min, min + (quar_inc * 5), min, "bigger balance, but not high enough"), + (min, min + (quar_inc * 5) + 1, min + inc, "bigger balance, high enough, but small step"), (min, min + (quar_inc * 8) - 1, min + inc, "bigger balance, high enough, close to double step"), (min, min + (quar_inc * 8), min + (2 * inc), "exact two step balance increment"), (min, min + (quar_inc * 8) + 1, min + (2 * inc), "over two steps, round down"), From 33e768083679999d4ec4b289c9a15b37c7f101dd Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Tue, 3 Mar 2020 10:58:47 -0700 Subject: [PATCH 3/3] make hysteresis calculations configurable --- configs/mainnet.yaml | 6 ++++++ configs/minimal.yaml | 7 +++++++ specs/phase0/beacon-chain.md | 12 ++++++++--- .../test_process_final_updates.py | 21 +++++++++++-------- 4 files changed, 34 insertions(+), 12 deletions(-) diff --git a/configs/mainnet.yaml b/configs/mainnet.yaml index 74f062d9b..46977f087 100644 --- a/configs/mainnet.yaml +++ b/configs/mainnet.yaml @@ -21,6 +21,12 @@ SHUFFLE_ROUND_COUNT: 90 MIN_GENESIS_ACTIVE_VALIDATOR_COUNT: 16384 # Jan 3, 2020 MIN_GENESIS_TIME: 1578009600 +# 4 +HYSTERESIS_QUOTIENT: 4 +# 1 (minus 0.25) +HYSTERESIS_DOWNWARD_MULTIPLIER: 1 +# 5 (plus 1.25) +HYSTERESIS_UPWARD_MULTIPLIER: 5 # Fork Choice diff --git a/configs/minimal.yaml b/configs/minimal.yaml index 42c63e301..202da8237 100644 --- a/configs/minimal.yaml +++ b/configs/minimal.yaml @@ -20,6 +20,13 @@ SHUFFLE_ROUND_COUNT: 10 MIN_GENESIS_ACTIVE_VALIDATOR_COUNT: 64 # Jan 3, 2020 MIN_GENESIS_TIME: 1578009600 +# 4 +HYSTERESIS_QUOTIENT: 4 +# 1 (minus 0.25) +HYSTERESIS_DOWNWARD_MULTIPLIER: 1 +# 5 (plus 1.25) +HYSTERESIS_UPWARD_MULTIPLIER: 5 + # Fork Choice diff --git a/specs/phase0/beacon-chain.md b/specs/phase0/beacon-chain.md index aa573ff16..c7a76d066 100644 --- a/specs/phase0/beacon-chain.md +++ b/specs/phase0/beacon-chain.md @@ -183,6 +183,10 @@ The following values are (non-configurable) constants used throughout the specif | `SHUFFLE_ROUND_COUNT` | `90` | | `MIN_GENESIS_ACTIVE_VALIDATOR_COUNT` | `2**14` (= 16,384) | | `MIN_GENESIS_TIME` | `1578009600` (Jan 3, 2020) | +| `HYSTERESIS_QUOTIENT` | `4` | +| `HYSTERESIS_DOWNWARD_MULTIPLIER` | `1` | +| `HYSTERESIS_UPWARD_MULTIPLIER` | `5` | + - For the safety of committees, `TARGET_COMMITTEE_SIZE` exceeds [the recommended minimum committee size of 111](http://web.archive.org/web/20190504131341/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.) @@ -1402,10 +1406,12 @@ def process_final_updates(state: BeaconState) -> None: # Update effective balances with hysteresis for index, validator in enumerate(state.validators): balance = state.balances[index] - QUARTER_INCREMENT = EFFECTIVE_BALANCE_INCREMENT // 4 + HYSTERESIS_INCREMENT = EFFECTIVE_BALANCE_INCREMENT // HYSTERESIS_QUOTIENT + DOWNWARD_THRESHOLD = HYSTERESIS_INCREMENT * HYSTERESIS_DOWNWARD_MULTIPLIER + UPWARD_THRESHOLD = HYSTERESIS_INCREMENT * HYSTERESIS_UPWARD_MULTIPLIER if ( - balance + QUARTER_INCREMENT < validator.effective_balance - or validator.effective_balance + 5 * QUARTER_INCREMENT < balance + balance + DOWNWARD_THRESHOLD < validator.effective_balance + or validator.effective_balance + UPWARD_THRESHOLD < balance ): validator.effective_balance = min(balance - balance % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE) # Reset slashings diff --git a/tests/core/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_final_updates.py b/tests/core/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_final_updates.py index 36dae8fb7..d959ce16e 100644 --- a/tests/core/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_final_updates.py +++ b/tests/core/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_final_updates.py @@ -51,22 +51,25 @@ def test_effective_balance_hysteresis(spec, state): max = spec.MAX_EFFECTIVE_BALANCE min = spec.EJECTION_BALANCE inc = spec.EFFECTIVE_BALANCE_INCREMENT - quar_inc = inc // 4 + div = spec.HYSTERESIS_QUOTIENT + hys_inc = inc // div + down = spec.HYSTERESIS_DOWNWARD_MULTIPLIER + up = spec.HYSTERESIS_UPWARD_MULTIPLIER cases = [ (max, max, max, "as-is"), (max, max - 1, max, "round up"), (max, max + 1, max, "round down"), - (max, max - quar_inc, max, "lower balance, but not low enough"), - (max, max - quar_inc, max, "lower balance, step down"), - (max, max + (3 * quar_inc) + 1, max, "already at max, as is"), + (max, max - down * hys_inc, max, "lower balance, but not low enough"), + (max, max - down * hys_inc - 1, max - inc, "lower balance, step down"), + (max, max + (up * hys_inc) + 1, max, "already at max, as is"), (max, max - inc, max - inc, "exactly 1 step lower"), (max, max - inc - 1, max - (2 * inc), "past 1 step lower, double step"), (max, max - inc + 1, max - inc, "close to 1 step lower"), - (min, min + (quar_inc * 5), min, "bigger balance, but not high enough"), - (min, min + (quar_inc * 5) + 1, min + inc, "bigger balance, high enough, but small step"), - (min, min + (quar_inc * 8) - 1, min + inc, "bigger balance, high enough, close to double step"), - (min, min + (quar_inc * 8), min + (2 * inc), "exact two step balance increment"), - (min, min + (quar_inc * 8) + 1, min + (2 * inc), "over two steps, round down"), + (min, min + (hys_inc * up), min, "bigger balance, but not high enough"), + (min, min + (hys_inc * up) + 1, min + inc, "bigger balance, high enough, but small step"), + (min, min + (hys_inc * div * 2) - 1, min + inc, "bigger balance, high enough, close to double step"), + (min, min + (hys_inc * div * 2), min + (2 * inc), "exact two step balance increment"), + (min, min + (hys_inc * div * 2) + 1, min + (2 * inc), "over two steps, round down"), ] current_epoch = spec.get_current_epoch(state) for i, (pre_eff, bal, _, _) in enumerate(cases):