Skip to content

Commit

Permalink
Merge pull request #3882 from mkalinin/correlation-penalty-fix
Browse files Browse the repository at this point in the history
EIP-7251: Update correlation penalty computation
  • Loading branch information
ralexstokes authored Sep 5, 2024
2 parents 0740189 + 4051ea8 commit 6c3868c
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 17 deletions.
25 changes: 24 additions & 1 deletion specs/electra/beacon-chain.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
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
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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


Expand Down

0 comments on commit 6c3868c

Please sign in to comment.