Merge pull request #2198 from ethereum/hf1-config
update penalty config values for hf1
This commit is contained in:
commit
e35b850181
|
@ -2,6 +2,16 @@
|
|||
|
||||
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
|
||||
# ---------------------------------------------------------------
|
||||
# 2**10 (=1,024)
|
||||
|
|
|
@ -2,6 +2,16 @@
|
|||
|
||||
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
|
||||
# ---------------------------------------------------------------
|
||||
# [customized]
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
- [Participation rewards](#participation-rewards)
|
||||
- [Misc](#misc)
|
||||
- [Configuration](#configuration)
|
||||
- [Updated penalty values](#updated-penalty-values)
|
||||
- [Misc](#misc-1)
|
||||
- [Time parameters](#time-parameters)
|
||||
- [Domain types](#domain-types)
|
||||
|
@ -34,6 +35,8 @@
|
|||
- [`get_unslashed_participating_indices`](#get_unslashed_participating_indices)
|
||||
- [`get_flag_deltas`](#get_flag_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)
|
||||
- [New `process_attestation`](#new-process_attestation)
|
||||
- [New `process_deposit`](#new-process_deposit)
|
||||
|
@ -41,6 +44,7 @@
|
|||
- [Epoch processing](#epoch-processing)
|
||||
- [New `process_justification_and_finalization`](#new-process_justification_and_finalization)
|
||||
- [New `process_rewards_and_penalties`](#new-process_rewards_and_penalties)
|
||||
- [New `process_slashings`](#new-process_slashings)
|
||||
- [Sync committee updates](#sync-committee-updates)
|
||||
- [Participation flags updates](#participation-flags-updates)
|
||||
|
||||
|
@ -49,11 +53,13 @@
|
|||
|
||||
## 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
|
||||
* 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
|
||||
* 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
|
||||
|
||||
## Custom types
|
||||
|
@ -97,6 +103,18 @@ The reward fractions add up to 7/8, leaving the remaining 1/8 for proposer rewar
|
|||
|
||||
## 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
|
||||
|
||||
| Name | Value |
|
||||
|
@ -328,7 +346,8 @@ def get_flag_deltas(state: BeaconState,
|
|||
|
||||
#### 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
|
||||
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)
|
||||
if index not in matching_target_attesting_indices:
|
||||
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))]
|
||||
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
|
||||
|
||||
```python
|
||||
|
@ -576,6 +630,24 @@ def process_rewards_and_penalties(state: BeaconState) -> None:
|
|||
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
|
||||
|
||||
```python
|
||||
|
|
|
@ -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.keys import pubkey_to_privkey
|
||||
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):
|
||||
slashed_validator = state.validators[slashed_index]
|
||||
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
|
||||
|
||||
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
|
||||
if proposer_index != slashed_index:
|
||||
# slashed validator lost initial slash penalty
|
||||
|
|
|
@ -4,6 +4,7 @@ from eth2spec.test.context import (
|
|||
from eth2spec.test.helpers.attestations import sign_indexed_attestation
|
||||
from eth2spec.test.helpers.attester_slashings import get_valid_attester_slashing, \
|
||||
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 (
|
||||
get_balance,
|
||||
next_epoch_via_block,
|
||||
|
@ -70,7 +71,7 @@ def run_attester_slashing_processing(spec, state, attester_slashing, valid=True)
|
|||
expected_balance = (
|
||||
pre_proposer_balance
|
||||
+ 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
|
||||
|
|
|
@ -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 (
|
||||
run_epoch_processing_with, run_epoch_processing_to
|
||||
)
|
||||
|
@ -23,12 +23,19 @@ def slash_validators(spec, state, indices, out_epochs):
|
|||
] = 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
|
||||
@spec_state_test
|
||||
def test_max_penalties(spec, state):
|
||||
# Slashed count to ensure that enough validators are slashed to induce maximum penalties
|
||||
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!
|
||||
len(state.validators)
|
||||
)
|
||||
|
@ -40,7 +47,7 @@ def test_max_penalties(spec, state):
|
|||
total_balance = spec.get_total_active_balance(state)
|
||||
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)
|
||||
|
||||
|
@ -50,7 +57,30 @@ def test_max_penalties(spec, state):
|
|||
|
||||
@with_all_phases
|
||||
@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
|
||||
state.balances[0] = state.validators[0].effective_balance = spec.EJECTION_BALANCE
|
||||
# All the other validators get the maximum.
|
||||
|
@ -74,11 +104,13 @@ def test_small_penalty(spec, state):
|
|||
|
||||
expected_penalty = (
|
||||
state.validators[0].effective_balance // spec.EFFECTIVE_BALANCE_INCREMENT
|
||||
* (3 * total_penalties)
|
||||
* (get_slashing_multiplier(spec) * total_penalties)
|
||||
// total_balance
|
||||
* 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
|
||||
|
@ -96,7 +128,7 @@ def test_scaled_penalties(spec, state):
|
|||
state.slashings[5] = base + (incr * 6)
|
||||
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
|
||||
|
||||
|
@ -134,7 +166,7 @@ def test_scaled_penalties(spec, state):
|
|||
v = state.validators[i]
|
||||
expected_penalty = (
|
||||
v.effective_balance // spec.EFFECTIVE_BALANCE_INCREMENT
|
||||
* (spec.PROPORTIONAL_SLASHING_MULTIPLIER * total_penalties)
|
||||
* (get_slashing_multiplier(spec) * total_penalties)
|
||||
// (total_balance)
|
||||
* spec.EFFECTIVE_BALANCE_INCREMENT
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue