mirror of
https://github.com/status-im/eth2.0-specs.git
synced 2025-02-21 06:48:12 +00:00
Merge pull request #2698 from ethereum/merge-penalties
update penalty params for Merge
This commit is contained in:
commit
77fe450f21
@ -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
|
||||
# 3
|
||||
PROPORTIONAL_SLASHING_MULTIPLIER_MERGE: 3
|
||||
|
||||
# Execution
|
||||
# ---------------------------------------------------------------
|
||||
# 2**30 (= 1,073,741,824)
|
||||
|
@ -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
|
||||
# 3
|
||||
PROPORTIONAL_SLASHING_MULTIPLIER_MERGE: 3
|
||||
|
||||
# Execution
|
||||
# ---------------------------------------------------------------
|
||||
# 2**30 (= 1,073,741,824)
|
||||
|
@ -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)
|
||||
@ -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 -->
|
||||
@ -42,7 +50,10 @@
|
||||
|
||||
## Introduction
|
||||
|
||||
This patch adds transaction execution to the beacon chain as part of the Merge fork.
|
||||
This upgrade adds transaction execution to the beacon chain as part of the Merge fork.
|
||||
|
||||
Additionally, this upgrade introduces the following minor changes:
|
||||
* Penalty parameter updates to their planned maximally punitive values
|
||||
|
||||
## Custom types
|
||||
|
||||
@ -66,6 +77,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
|
||||
@ -223,6 +248,64 @@ 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]
|
||||
# [Modified in Merge]
|
||||
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
|
||||
slashing_penalty = validator.effective_balance // MIN_SLASHING_PENALTY_QUOTIENT_MERGE # [Modified in Merge]
|
||||
decrease_balance(state, slashed_index, slashing_penalty)
|
||||
|
||||
# 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
|
||||
@ -262,9 +345,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:
|
||||
@ -287,7 +370,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:
|
||||
@ -322,6 +405,28 @@ 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, # [Modified in 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.
|
||||
|
@ -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
|
||||
@ -9,7 +9,9 @@ from eth2spec.test.helpers.sync_committee import (
|
||||
|
||||
|
||||
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
|
||||
|
@ -2,7 +2,7 @@ from random import Random
|
||||
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,
|
||||
)
|
||||
@ -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.
|
||||
@ -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 (
|
||||
@ -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
|
||||
|
||||
|
||||
|
@ -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
|
||||
)
|
||||
@ -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
|
||||
|
@ -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
|
||||
|
||||
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user