Merge pull request #3882 from mkalinin/correlation-penalty-fix

EIP-7251: Update correlation penalty computation
This commit is contained in:
Alex Stokes 2024-09-05 13:58:42 -06:00 committed by GitHub
commit 6c3868c872
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 48 additions and 17 deletions

View File

@ -71,6 +71,7 @@
- [Epoch processing](#epoch-processing)
- [Modified `process_epoch`](#modified-process_epoch)
- [Modified `process_registry_updates`](#modified-process_registry_updates)
- [Modified `process_slashings`](#modified-process_slashings)
- [New `process_pending_balance_deposits`](#new-process_pending_balance_deposits)
- [New `process_pending_consolidations`](#new-process_pending_consolidations)
- [Modified `process_effective_balance_updates`](#modified-process_effective_balance_updates)
@ -813,7 +814,7 @@ def process_epoch(state: BeaconState) -> None:
process_inactivity_updates(state)
process_rewards_and_penalties(state)
process_registry_updates(state) # [Modified in Electra:EIP7251]
process_slashings(state)
process_slashings(state) # [Modified in Electra:EIP7251]
process_eth1_data_reset(state)
process_pending_balance_deposits(state) # [New in Electra:EIP7251]
process_pending_consolidations(state) # [New in Electra:EIP7251]
@ -850,6 +851,28 @@ def process_registry_updates(state: BeaconState) -> None:
validator.activation_epoch = activation_epoch
```
#### Modified `process_slashings`
*Note*: The function `process_slashings` is modified to use a new algorithm to compute correlation penalty.
```python
def process_slashings(state: BeaconState) -> None:
epoch = get_current_epoch(state)
total_balance = get_total_active_balance(state)
adjusted_total_slashing_balance = min(
sum(state.slashings) * PROPORTIONAL_SLASHING_MULTIPLIER_BELLATRIX,
total_balance
)
increment = EFFECTIVE_BALANCE_INCREMENT # Factored out from total balance to avoid uint64 overflow
penalty_per_effective_balance_increment = adjusted_total_slashing_balance // (total_balance // increment)
for index, validator in enumerate(state.validators):
if validator.slashed and epoch + EPOCHS_PER_SLASHINGS_VECTOR // 2 == validator.withdrawable_epoch:
effective_balance_increments = validator.effective_balance // increment
# [Modified in Electra:EIP7251]
penalty = penalty_per_effective_balance_increment * effective_balance_increments
decrease_balance(state, ValidatorIndex(index), penalty)
```
#### New `process_pending_balance_deposits`
```python

View File

@ -3,7 +3,11 @@ from eth2spec.test.context import spec_state_test, with_all_phases
from eth2spec.test.helpers.epoch_processing import (
run_epoch_processing_with, run_epoch_processing_to
)
from eth2spec.test.helpers.forks import is_post_altair, is_post_bellatrix
from eth2spec.test.helpers.forks import (
is_post_altair,
is_post_bellatrix,
is_post_electra,
)
from eth2spec.test.helpers.random import randomize_state
from eth2spec.test.helpers.state import has_active_balance_differential
from eth2spec.test.helpers.voluntary_exits import get_unslashed_exited_validators
@ -40,6 +44,18 @@ def get_slashing_multiplier(spec):
return spec.PROPORTIONAL_SLASHING_MULTIPLIER
def _compute_expected_correlation_penalty(spec, effective_balance, total_slashed_balance, total_balance):
if is_post_electra(spec):
return ((get_slashing_multiplier(spec) * total_slashed_balance)
// (total_balance // spec.EFFECTIVE_BALANCE_INCREMENT)
* (effective_balance // spec.EFFECTIVE_BALANCE_INCREMENT))
else:
return (effective_balance // spec.EFFECTIVE_BALANCE_INCREMENT
* (get_slashing_multiplier(spec) * total_slashed_balance)
// total_balance
* spec.EFFECTIVE_BALANCE_INCREMENT)
def _setup_process_slashings_test(spec, state, not_slashable_set=set()):
# Slashed count to ensure that enough validators are slashed to induce maximum penalties
slashed_count = min(
@ -99,7 +115,8 @@ def test_minimal_penalty(spec, state):
#
# Just the bare minimum for this one validator
state.balances[0] = state.validators[0].effective_balance = spec.config.EJECTION_BALANCE
state.balances[0] = state.validators[0].effective_balance = (
spec.config.EJECTION_BALANCE + spec.EFFECTIVE_BALANCE_INCREMENT)
# All the other validators get the maximum.
for i in range(1, len(state.validators)):
state.validators[i].effective_balance = state.balances[i] = spec.MAX_EFFECTIVE_BALANCE
@ -119,15 +136,10 @@ def test_minimal_penalty(spec, state):
spec.process_slashings(state)
yield 'post', state
expected_penalty = (
state.validators[0].effective_balance // spec.EFFECTIVE_BALANCE_INCREMENT
* (get_slashing_multiplier(spec) * total_penalties)
// total_balance
* spec.EFFECTIVE_BALANCE_INCREMENT
)
expected_penalty = _compute_expected_correlation_penalty(
spec, state.validators[0].effective_balance, total_penalties, total_balance)
assert expected_penalty == 0
assert state.balances[0] == pre_slash_balances[0]
assert state.balances[0] == pre_slash_balances[0] - expected_penalty
@with_all_phases
@ -181,12 +193,8 @@ def test_scaled_penalties(spec, state):
for i in slashed_indices:
v = state.validators[i]
expected_penalty = (
v.effective_balance // spec.EFFECTIVE_BALANCE_INCREMENT
* (get_slashing_multiplier(spec) * total_penalties)
// (total_balance)
* spec.EFFECTIVE_BALANCE_INCREMENT
)
expected_penalty = _compute_expected_correlation_penalty(
spec, v.effective_balance, total_penalties, total_balance)
assert state.balances[i] == pre_slash_balances[i] - expected_penalty