Skip to content

Commit

Permalink
update penalty params for Merge
Browse files Browse the repository at this point in the history
  • Loading branch information
djrtwo committed Oct 29, 2021
1 parent 2fc0564 commit 78040ac
Show file tree
Hide file tree
Showing 7 changed files with 145 additions and 15 deletions.
9 changes: 9 additions & 0 deletions presets/mainnet/merge.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# Mainnet preset - The Merge

# Updated penalty values
# ---------------------------------------------------------------
# 2**24 (= 16,777,216)
INACTIVITY_PENALTY_QUOTIENT_MERGE: 16777216
# 2**5 (= 32)
MIN_SLASHING_PENALTY_QUOTIENT_MERGE: 32
# 2
PROPORTIONAL_SLASHING_MULTIPLIER_MERGE: 3

# Execution
# ---------------------------------------------------------------
# 2**30 (= 1,073,741,824)
Expand Down
9 changes: 9 additions & 0 deletions presets/minimal/merge.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# Minimal preset - The Merge

# Updated penalty values
# ---------------------------------------------------------------
# 2**24 (= 16,777,216)
INACTIVITY_PENALTY_QUOTIENT_MERGE: 16777216
# 2**5 (= 32)
MIN_SLASHING_PENALTY_QUOTIENT_MERGE: 32
# 2
PROPORTIONAL_SLASHING_MULTIPLIER_MERGE: 3

# Execution
# ---------------------------------------------------------------
# 2**30 (= 1,073,741,824)
Expand Down
109 changes: 103 additions & 6 deletions specs/merge/beacon-chain.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
- [Custom types](#custom-types)
- [Constants](#constants)
- [Execution](#execution)
- [Preset](#preset)
- [Updated penalty values](#updated-penalty-values)
- [Configuration](#configuration)
- [Transition settings](#transition-settings)
- [Containers](#containers)
Expand All @@ -28,13 +30,19 @@
- [`is_execution_enabled`](#is_execution_enabled)
- [Misc](#misc)
- [`compute_timestamp_at_slot`](#compute_timestamp_at_slot)
- [Beacon state accessors](#beacon-state-accessors)
- [Modified `get_inactivity_penalty_deltas`](#modified-get_inactivity_penalty_deltas)
- [Beacon state mutators](#beacon-state-mutators)
- [Modified `slash_validator`](#modified-slash_validator)
- [Beacon chain state transition function](#beacon-chain-state-transition-function)
- [Execution engine](#execution-engine)
- [`execute_payload`](#execute_payload)
- [Block processing](#block-processing)
- [Execution payload processing](#execution-payload-processing)
- [`is_valid_gas_limit`](#is_valid_gas_limit)
- [`process_execution_payload`](#process_execution_payload)
- [Execution payload](#execution-payload)
- [`is_valid_gas_limit`](#is_valid_gas_limit)
- [`process_execution_payload`](#process_execution_payload)
- [Epoch processing](#epoch-processing)
- [Slashings](#slashings)
- [Testing](#testing)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->
Expand Down Expand Up @@ -66,6 +74,20 @@ This patch adds transaction execution to the beacon chain as part of the Merge f
| `MIN_GAS_LIMIT` | `uint64(5000)` (= 5,000) |
| `MAX_EXTRA_DATA_BYTES` | `2**5` (= 32) |

## Preset

### Updated penalty values

The Merge updates a few configuration values to move penalty parameters to their final, maximum security values.

*Note*: The spec does *not* override previous configuration values but instead creates new values and replaces usage throughout.

| Name | Value |
| - | - |
| `INACTIVITY_PENALTY_QUOTIENT_MERGE` | `uint64(2**24)` (= 16,777,216) |
| `MIN_SLASHING_PENALTY_QUOTIENT_MERGE` | `uint64(2**5)` (= 32) |
| `PROPORTIONAL_SLASHING_MULTIPLIER_MERGE` | `uint64(3)` |

## Configuration

### Transition settings
Expand Down Expand Up @@ -223,6 +245,62 @@ def compute_timestamp_at_slot(state: BeaconState, slot: Slot) -> uint64:
return uint64(state.genesis_time + slots_since_genesis * SECONDS_PER_SLOT)
```

### Beacon state accessors

#### Modified `get_inactivity_penalty_deltas`

*Note*: The function `get_inactivity_penalty_deltas` is modified to use `INACTIVITY_PENALTY_QUOTIENT_MERGE`.

```python
def get_inactivity_penalty_deltas(state: BeaconState) -> Tuple[Sequence[Gwei], Sequence[Gwei]]:
"""
Return the inactivity penalty deltas by considering timely target participation flags and inactivity scores.
"""
rewards = [Gwei(0) for _ in range(len(state.validators))]
penalties = [Gwei(0) for _ in range(len(state.validators))]
previous_epoch = get_previous_epoch(state)
matching_target_indices = get_unslashed_participating_indices(state, TIMELY_TARGET_FLAG_INDEX, previous_epoch)
for index in get_eligible_validator_indices(state):
if index not in matching_target_indices:
penalty_numerator = state.validators[index].effective_balance * state.inactivity_scores[index]
penalty_denominator = INACTIVITY_SCORE_BIAS * INACTIVITY_PENALTY_QUOTIENT_MERGE
penalties[index] += Gwei(penalty_numerator // penalty_denominator)
return rewards, penalties
```

### Beacon state mutators

#### Modified `slash_validator`

*Note*: The function `slash_validator` is modified to use `MIN_SLASHING_PENALTY_QUOTIENT_MERGE`.

```python
def slash_validator(state: BeaconState,
slashed_index: ValidatorIndex,
whistleblower_index: ValidatorIndex=None) -> None:
"""
Slash the validator with index ``slashed_index``.
"""
epoch = get_current_epoch(state)
initiate_validator_exit(state, slashed_index)
validator = state.validators[slashed_index]
validator.slashed = True
validator.withdrawable_epoch = max(validator.withdrawable_epoch, Epoch(epoch + EPOCHS_PER_SLASHINGS_VECTOR))
state.slashings[epoch % EPOCHS_PER_SLASHINGS_VECTOR] += validator.effective_balance
decrease_balance(state, slashed_index, validator.effective_balance // MIN_SLASHING_PENALTY_QUOTIENT_MERGE)

# Apply proposer and whistleblower rewards
proposer_index = get_beacon_proposer_index(state)
if whistleblower_index is None:
whistleblower_index = proposer_index
whistleblower_reward = Gwei(validator.effective_balance // WHISTLEBLOWER_REWARD_QUOTIENT)
proposer_reward = Gwei(whistleblower_reward * PROPOSER_WEIGHT // WEIGHT_DENOMINATOR)
increase_balance(state, proposer_index, proposer_reward)
increase_balance(state, whistleblower_index, Gwei(whistleblower_reward - proposer_reward))
```



## Beacon chain state transition function

### Execution engine
Expand Down Expand Up @@ -262,9 +340,9 @@ def process_block(state: BeaconState, block: BeaconBlock) -> None:
process_sync_aggregate(state, block.body.sync_aggregate)
```

### Execution payload processing
#### Execution payload

#### `is_valid_gas_limit`
##### `is_valid_gas_limit`

```python
def is_valid_gas_limit(payload: ExecutionPayload, parent: ExecutionPayloadHeader) -> bool:
Expand All @@ -287,7 +365,7 @@ def is_valid_gas_limit(payload: ExecutionPayload, parent: ExecutionPayloadHeader
return True
```

#### `process_execution_payload`
##### `process_execution_payload`

```python
def process_execution_payload(state: BeaconState, payload: ExecutionPayload, execution_engine: ExecutionEngine) -> None:
Expand Down Expand Up @@ -322,6 +400,25 @@ def process_execution_payload(state: BeaconState, payload: ExecutionPayload, exe
)
```

### Epoch processing

#### Slashings

*Note*: The function `process_slashings` is modified to use `PROPORTIONAL_SLASHING_MULTIPLIER_MERGE`.

```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_MERGE, total_balance)
for index, validator in enumerate(state.validators):
if validator.slashed and epoch + EPOCHS_PER_SLASHINGS_VECTOR // 2 == validator.withdrawable_epoch:
increment = EFFECTIVE_BALANCE_INCREMENT # Factored out from penalty numerator to avoid uint64 overflow
penalty_numerator = validator.effective_balance // increment * adjusted_total_slashing_balance
penalty = penalty_numerator // total_balance * increment
decrease_balance(state, ValidatorIndex(index), penalty)
```

## Testing

*Note*: The function `initialize_beacon_state_from_eth1` is modified for pure Merge testing only.
Expand Down
6 changes: 4 additions & 2 deletions tests/core/pyspec/eth2spec/test/helpers/proposer_slashings.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from eth2spec.test.context import is_post_altair
from eth2spec.test.context import is_post_altair, is_post_merge
from eth2spec.test.helpers.block_header import sign_block_header
from eth2spec.test.helpers.keys import pubkey_to_privkey
from eth2spec.test.helpers.state import get_balance
Expand All @@ -9,7 +9,9 @@


def get_min_slashing_penalty_quotient(spec):
if is_post_altair(spec):
if is_post_merge(spec):
return spec.MIN_SLASHING_PENALTY_QUOTIENT_MERGE
elif is_post_altair(spec):
return spec.MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR
else:
return spec.MIN_SLASHING_PENALTY_QUOTIENT
Expand Down
15 changes: 12 additions & 3 deletions tests/core/pyspec/eth2spec/test/helpers/rewards.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from lru import LRU

from eth2spec.phase0.mainnet import VALIDATOR_REGISTRY_LIMIT # equal everywhere, fine to import
from eth2spec.test.context import is_post_altair
from eth2spec.test.context import is_post_altair, is_post_merge
from eth2spec.test.helpers.state import (
next_epoch,
)
Expand All @@ -21,6 +21,15 @@ class Deltas(Container):
penalties: List[uint64, VALIDATOR_REGISTRY_LIMIT]


def get_inactivity_penalty_quotient(spec):
if is_post_merge(spec):
return spec.INACTIVITY_PENALTY_QUOTIENT_MERGE
elif is_post_altair(spec):
return spec.INACTIVITY_PENALTY_QUOTIENT_ALTAIR
else:
return spec.INACTIVITY_PENALTY_QUOTIENT


def has_enough_for_reward(spec, state, index):
"""
Check if base_reward will be non-zero.
Expand All @@ -45,7 +54,7 @@ def has_enough_for_leak_penalty(spec, state, index):
if is_post_altair(spec):
return (
state.validators[index].effective_balance * state.inactivity_scores[index]
> spec.config.INACTIVITY_SCORE_BIAS * spec.INACTIVITY_PENALTY_QUOTIENT_ALTAIR
> spec.config.INACTIVITY_SCORE_BIAS * get_inactivity_penalty_quotient(spec)
)
else:
return (
Expand Down Expand Up @@ -266,7 +275,7 @@ def run_get_inactivity_penalty_deltas(spec, state):
else:
# copied from spec:
penalty_numerator = state.validators[index].effective_balance * state.inactivity_scores[index]
penalty_denominator = spec.config.INACTIVITY_SCORE_BIAS * spec.INACTIVITY_PENALTY_QUOTIENT_ALTAIR
penalty_denominator = spec.config.INACTIVITY_SCORE_BIAS * get_inactivity_penalty_quotient(spec)
assert penalties[index] == penalty_numerator // penalty_denominator


Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from random import Random
from eth2spec.test.context import spec_state_test, with_all_phases, is_post_altair
from eth2spec.test.context import spec_state_test, with_all_phases, is_post_altair, is_post_merge
from eth2spec.test.helpers.epoch_processing import (
run_epoch_processing_with, run_epoch_processing_to
)
Expand Down Expand Up @@ -31,7 +31,9 @@ def slash_validators(spec, state, indices, out_epochs):


def get_slashing_multiplier(spec):
if is_post_altair(spec):
if is_post_merge(spec):
return spec.PROPORTIONAL_SLASHING_MULTIPLIER_MERGE
elif is_post_altair(spec):
return spec.PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR
else:
return spec.PROPORTIONAL_SLASHING_MULTIPLIER
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from eth2spec.test.context import (
spec_state_test,
with_all_phases,
is_post_altair,
is_post_altair, is_post_merge,
)
from eth2spec.test.helpers.constants import MAX_UINT_64

Expand Down Expand Up @@ -52,7 +52,9 @@ def test_hysteresis_quotient(spec, state):
@spec_state_test
def test_incentives(spec, state):
# Ensure no ETH is minted in slash_validator
if is_post_altair(spec):
if is_post_merge(spec):
assert spec.MIN_SLASHING_PENALTY_QUOTIENT_MERGE <= spec.WHISTLEBLOWER_REWARD_QUOTIENT
elif is_post_altair(spec):
assert spec.MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR <= spec.WHISTLEBLOWER_REWARD_QUOTIENT
else:
assert spec.MIN_SLASHING_PENALTY_QUOTIENT <= spec.WHISTLEBLOWER_REWARD_QUOTIENT
Expand Down

0 comments on commit 78040ac

Please sign in to comment.