Merge pull request #2198 from ethereum/hf1-config

update penalty config values for hf1
This commit is contained in:
Danny Ryan 2021-02-22 18:26:43 -06:00 committed by GitHub
commit e35b850181
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 146 additions and 13 deletions

View File

@ -2,6 +2,16 @@
CONFIG_NAME: "mainnet" CONFIG_NAME: "mainnet"
# Updated penalty values
# ---------------------------------------------------------------
# 3 * 2**24) (= 50,331,648)
HF1_INACTIVITY_PENALTY_QUOTIENT: 50331648
# 2**6 (= 64)
HF1_MIN_SLASHING_PENALTY_QUOTIENT: 64
# 2
HF1_PROPORTIONAL_SLASHING_MULTIPLIER: 2
# Misc # Misc
# --------------------------------------------------------------- # ---------------------------------------------------------------
# 2**10 (=1,024) # 2**10 (=1,024)

View File

@ -2,6 +2,16 @@
CONFIG_NAME: "minimal" CONFIG_NAME: "minimal"
# Updated penalty values
# ---------------------------------------------------------------
# 3 * 2**24) (= 50,331,648)
HF1_INACTIVITY_PENALTY_QUOTIENT: 50331648
# 2**6 (= 64)
HF1_MIN_SLASHING_PENALTY_QUOTIENT: 64
# 2
HF1_PROPORTIONAL_SLASHING_MULTIPLIER: 2
# Misc # Misc
# --------------------------------------------------------------- # ---------------------------------------------------------------
# [customized] # [customized]

View File

@ -13,6 +13,7 @@
- [Participation rewards](#participation-rewards) - [Participation rewards](#participation-rewards)
- [Misc](#misc) - [Misc](#misc)
- [Configuration](#configuration) - [Configuration](#configuration)
- [Updated penalty values](#updated-penalty-values)
- [Misc](#misc-1) - [Misc](#misc-1)
- [Time parameters](#time-parameters) - [Time parameters](#time-parameters)
- [Domain types](#domain-types) - [Domain types](#domain-types)
@ -34,6 +35,8 @@
- [`get_unslashed_participating_indices`](#get_unslashed_participating_indices) - [`get_unslashed_participating_indices`](#get_unslashed_participating_indices)
- [`get_flag_deltas`](#get_flag_deltas) - [`get_flag_deltas`](#get_flag_deltas)
- [New `get_inactivity_penalty_deltas`](#new-get_inactivity_penalty_deltas) - [New `get_inactivity_penalty_deltas`](#new-get_inactivity_penalty_deltas)
- [Beacon state mutators](#beacon-state-mutators)
- [New `slash_validator`](#new-slash_validator)
- [Block processing](#block-processing) - [Block processing](#block-processing)
- [New `process_attestation`](#new-process_attestation) - [New `process_attestation`](#new-process_attestation)
- [New `process_deposit`](#new-process_deposit) - [New `process_deposit`](#new-process_deposit)
@ -41,6 +44,7 @@
- [Epoch processing](#epoch-processing) - [Epoch processing](#epoch-processing)
- [New `process_justification_and_finalization`](#new-process_justification_and_finalization) - [New `process_justification_and_finalization`](#new-process_justification_and_finalization)
- [New `process_rewards_and_penalties`](#new-process_rewards_and_penalties) - [New `process_rewards_and_penalties`](#new-process_rewards_and_penalties)
- [New `process_slashings`](#new-process_slashings)
- [Sync committee updates](#sync-committee-updates) - [Sync committee updates](#sync-committee-updates)
- [Participation flags updates](#participation-flags-updates) - [Participation flags updates](#participation-flags-updates)
@ -49,11 +53,13 @@
## Introduction ## Introduction
This is a patch implementing the first hard fork to the beacon chain, tentatively named HF1 pending a permanent name. It has three main features: This is a patch implementing the first hard fork to the beacon chain, tentatively named HF1 pending a permanent name.
It has four main features:
* Light client support via sync committees * Light client support via sync committees
* Incentive accounting reforms, reducing spec complexity * Incentive accounting reforms, reducing spec complexity
and [TODO] reducing the cost of processing chains that have very little or zero participation for a long span of epochs and [TODO] reducing the cost of processing chains that have very little or zero participation for a long span of epochs
* Update penalty configuration values, moving them toward their planned maximally punitive configuration
* Fork choice rule changes to address weaknesses recently discovered in the existing fork choice * Fork choice rule changes to address weaknesses recently discovered in the existing fork choice
## Custom types ## Custom types
@ -97,6 +103,18 @@ The reward fractions add up to 7/8, leaving the remaining 1/8 for proposer rewar
## Configuration ## Configuration
### Updated penalty values
This patch updates a few configuration values to move penalty constants toward their final, maxmium security values.
*Note*: The spec does *not* override previous configuration values but instead creates new values and replaces usage throughout.
| Name | Value |
| - | - |
| `HF1_INACTIVITY_PENALTY_QUOTIENT` | `uint64(3 * 2**24)` (= 50,331,648) |
| `HF1_MIN_SLASHING_PENALTY_QUOTIENT` | `uint64(2**6)` (=64) |
| `HF1_PROPORTIONAL_SLASHING_MULTIPLIER` | `uint64(2)` |
### Misc ### Misc
| Name | Value | | Name | Value |
@ -328,7 +346,8 @@ def get_flag_deltas(state: BeaconState,
#### New `get_inactivity_penalty_deltas` #### New `get_inactivity_penalty_deltas`
*Note*: The function `get_inactivity_penalty_deltas` is modified in the selection of matching target indices and the removal of `BASE_REWARDS_PER_EPOCH`. *Note*: The function `get_inactivity_penalty_deltas` is modified in the selection of matching target indices
and the removal of `BASE_REWARDS_PER_EPOCH`.
```python ```python
def get_inactivity_penalty_deltas(state: BeaconState) -> Tuple[Sequence[Gwei], Sequence[Gwei]]: def get_inactivity_penalty_deltas(state: BeaconState) -> Tuple[Sequence[Gwei], Sequence[Gwei]]:
@ -348,12 +367,47 @@ def get_inactivity_penalty_deltas(state: BeaconState) -> Tuple[Sequence[Gwei], S
penalties[index] += Gwei(get_base_reward(state, index) * reward_numerator_sum // REWARD_DENOMINATOR) penalties[index] += Gwei(get_base_reward(state, index) * reward_numerator_sum // REWARD_DENOMINATOR)
if index not in matching_target_attesting_indices: if index not in matching_target_attesting_indices:
effective_balance = state.validators[index].effective_balance effective_balance = state.validators[index].effective_balance
penalties[index] += Gwei(effective_balance * get_finality_delay(state) // INACTIVITY_PENALTY_QUOTIENT) penalties[index] += Gwei(
effective_balance * get_finality_delay(state)
// HF1_INACTIVITY_PENALTY_QUOTIENT
)
rewards = [Gwei(0) for _ in range(len(state.validators))] rewards = [Gwei(0) for _ in range(len(state.validators))]
return rewards, penalties return rewards, penalties
``` ```
### Beacon state mutators
#### New `slash_validator`
*Note*: The function `slash_validator` is modified
with the substitution of `MIN_SLASHING_PENALTY_QUOTIENT` with `HF1_MIN_SLASHING_PENALTY_QUOTIENT`.
```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 // HF1_MIN_SLASHING_PENALTY_QUOTIENT)
# 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_REWARD_QUOTIENT)
increase_balance(state, proposer_index, proposer_reward)
increase_balance(state, whistleblower_index, Gwei(whistleblower_reward - proposer_reward))
```
### Block processing ### Block processing
```python ```python
@ -576,6 +630,24 @@ def process_rewards_and_penalties(state: BeaconState) -> None:
decrease_balance(state, ValidatorIndex(index), penalties[index]) decrease_balance(state, ValidatorIndex(index), penalties[index])
``` ```
#### New `process_slashings`
*Note*: The function `process_slashings` is modified
with the substitution of `PROPORTIONAL_SLASHING_MULTIPLIER` with `HF1_PROPORTIONAL_SLASHING_MULTIPLIER`.
```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) * HF1_PROPORTIONAL_SLASHING_MULTIPLIER, 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)
```
#### Sync committee updates #### Sync committee updates
```python ```python

View File

@ -1,8 +1,16 @@
from eth2spec.test.context import is_post_lightclient_patch
from eth2spec.test.helpers.block_header import sign_block_header from eth2spec.test.helpers.block_header import sign_block_header
from eth2spec.test.helpers.keys import pubkey_to_privkey from eth2spec.test.helpers.keys import pubkey_to_privkey
from eth2spec.test.helpers.state import get_balance from eth2spec.test.helpers.state import get_balance
def get_min_slashing_penalty_quotient(spec):
if is_post_lightclient_patch(spec):
return spec.HF1_MIN_SLASHING_PENALTY_QUOTIENT
else:
return spec.MIN_SLASHING_PENALTY_QUOTIENT
def check_proposer_slashing_effect(spec, pre_state, state, slashed_index): def check_proposer_slashing_effect(spec, pre_state, state, slashed_index):
slashed_validator = state.validators[slashed_index] slashed_validator = state.validators[slashed_index]
assert slashed_validator.slashed assert slashed_validator.slashed
@ -10,7 +18,7 @@ def check_proposer_slashing_effect(spec, pre_state, state, slashed_index):
assert slashed_validator.withdrawable_epoch < spec.FAR_FUTURE_EPOCH assert slashed_validator.withdrawable_epoch < spec.FAR_FUTURE_EPOCH
proposer_index = spec.get_beacon_proposer_index(state) proposer_index = spec.get_beacon_proposer_index(state)
slash_penalty = state.validators[slashed_index].effective_balance // spec.MIN_SLASHING_PENALTY_QUOTIENT slash_penalty = state.validators[slashed_index].effective_balance // get_min_slashing_penalty_quotient(spec)
whistleblower_reward = state.validators[slashed_index].effective_balance // spec.WHISTLEBLOWER_REWARD_QUOTIENT whistleblower_reward = state.validators[slashed_index].effective_balance // spec.WHISTLEBLOWER_REWARD_QUOTIENT
if proposer_index != slashed_index: if proposer_index != slashed_index:
# slashed validator lost initial slash penalty # slashed validator lost initial slash penalty

View File

@ -4,6 +4,7 @@ from eth2spec.test.context import (
from eth2spec.test.helpers.attestations import sign_indexed_attestation from eth2spec.test.helpers.attestations import sign_indexed_attestation
from eth2spec.test.helpers.attester_slashings import get_valid_attester_slashing, \ from eth2spec.test.helpers.attester_slashings import get_valid_attester_slashing, \
get_indexed_attestation_participants, get_attestation_2_data, get_attestation_1_data get_indexed_attestation_participants, get_attestation_2_data, get_attestation_1_data
from eth2spec.test.helpers.proposer_slashings import get_min_slashing_penalty_quotient
from eth2spec.test.helpers.state import ( from eth2spec.test.helpers.state import (
get_balance, get_balance,
next_epoch_via_block, next_epoch_via_block,
@ -70,7 +71,7 @@ def run_attester_slashing_processing(spec, state, attester_slashing, valid=True)
expected_balance = ( expected_balance = (
pre_proposer_balance pre_proposer_balance
+ total_proposer_rewards + total_proposer_rewards
- pre_slashings[proposer_index] // spec.MIN_SLASHING_PENALTY_QUOTIENT - pre_slashings[proposer_index] // get_min_slashing_penalty_quotient(spec)
) )
assert get_balance(state, proposer_index) == expected_balance assert get_balance(state, proposer_index) == expected_balance

View File

@ -1,4 +1,4 @@
from eth2spec.test.context import spec_state_test, with_all_phases from eth2spec.test.context import spec_state_test, with_all_phases, is_post_lightclient_patch
from eth2spec.test.helpers.epoch_processing import ( from eth2spec.test.helpers.epoch_processing import (
run_epoch_processing_with, run_epoch_processing_to run_epoch_processing_with, run_epoch_processing_to
) )
@ -23,12 +23,19 @@ def slash_validators(spec, state, indices, out_epochs):
] = total_slashed_balance ] = total_slashed_balance
def get_slashing_multiplier(spec):
if is_post_lightclient_patch(spec):
return spec.HF1_PROPORTIONAL_SLASHING_MULTIPLIER
else:
return spec.PROPORTIONAL_SLASHING_MULTIPLIER
@with_all_phases @with_all_phases
@spec_state_test @spec_state_test
def test_max_penalties(spec, state): def test_max_penalties(spec, state):
# Slashed count to ensure that enough validators are slashed to induce maximum penalties # Slashed count to ensure that enough validators are slashed to induce maximum penalties
slashed_count = min( slashed_count = min(
(len(state.validators) // spec.PROPORTIONAL_SLASHING_MULTIPLIER) + 1, (len(state.validators) // get_slashing_multiplier(spec)) + 1,
# Can't slash more than validator count! # Can't slash more than validator count!
len(state.validators) len(state.validators)
) )
@ -40,7 +47,7 @@ def test_max_penalties(spec, state):
total_balance = spec.get_total_active_balance(state) total_balance = spec.get_total_active_balance(state)
total_penalties = sum(state.slashings) total_penalties = sum(state.slashings)
assert total_balance // spec.PROPORTIONAL_SLASHING_MULTIPLIER <= total_penalties assert total_balance // get_slashing_multiplier(spec) <= total_penalties
yield from run_process_slashings(spec, state) yield from run_process_slashings(spec, state)
@ -50,7 +57,30 @@ def test_max_penalties(spec, state):
@with_all_phases @with_all_phases
@spec_state_test @spec_state_test
def test_small_penalty(spec, state): def test_low_penalty(spec, state):
# Slashed count is one tenth of validator set
slashed_count = (len(state.validators) // 10) + 1
out_epoch = spec.get_current_epoch(state) + (spec.EPOCHS_PER_SLASHINGS_VECTOR // 2)
slashed_indices = list(range(slashed_count))
slash_validators(spec, state, slashed_indices, [out_epoch] * slashed_count)
pre_state = state.copy()
yield from run_process_slashings(spec, state)
for i in slashed_indices:
assert 0 < state.balances[i] < pre_state.balances[i]
@with_all_phases
@spec_state_test
def test_minimal_penalty(spec, state):
#
# When very few slashings, the resulting slashing penalty gets rounded down
# to zero so the result of `process_slashings` is null
#
# Just the bare minimum for this one validator # Just the bare minimum for this one validator
state.balances[0] = state.validators[0].effective_balance = spec.EJECTION_BALANCE state.balances[0] = state.validators[0].effective_balance = spec.EJECTION_BALANCE
# All the other validators get the maximum. # All the other validators get the maximum.
@ -74,11 +104,13 @@ def test_small_penalty(spec, state):
expected_penalty = ( expected_penalty = (
state.validators[0].effective_balance // spec.EFFECTIVE_BALANCE_INCREMENT state.validators[0].effective_balance // spec.EFFECTIVE_BALANCE_INCREMENT
* (3 * total_penalties) * (get_slashing_multiplier(spec) * total_penalties)
// total_balance // total_balance
* spec.EFFECTIVE_BALANCE_INCREMENT * spec.EFFECTIVE_BALANCE_INCREMENT
) )
assert state.balances[0] == pre_slash_balances[0] - expected_penalty
assert expected_penalty == 0
assert state.balances[0] == pre_slash_balances[0]
@with_all_phases @with_all_phases
@ -96,7 +128,7 @@ def test_scaled_penalties(spec, state):
state.slashings[5] = base + (incr * 6) state.slashings[5] = base + (incr * 6)
state.slashings[spec.EPOCHS_PER_SLASHINGS_VECTOR - 1] = base + (incr * 7) state.slashings[spec.EPOCHS_PER_SLASHINGS_VECTOR - 1] = base + (incr * 7)
slashed_count = len(state.validators) // (spec.PROPORTIONAL_SLASHING_MULTIPLIER + 1) slashed_count = len(state.validators) // (get_slashing_multiplier(spec) + 1)
assert slashed_count > 10 assert slashed_count > 10
@ -134,7 +166,7 @@ def test_scaled_penalties(spec, state):
v = state.validators[i] v = state.validators[i]
expected_penalty = ( expected_penalty = (
v.effective_balance // spec.EFFECTIVE_BALANCE_INCREMENT v.effective_balance // spec.EFFECTIVE_BALANCE_INCREMENT
* (spec.PROPORTIONAL_SLASHING_MULTIPLIER * total_penalties) * (get_slashing_multiplier(spec) * total_penalties)
// (total_balance) // (total_balance)
* spec.EFFECTIVE_BALANCE_INCREMENT * spec.EFFECTIVE_BALANCE_INCREMENT
) )