Merge pull request #658 from ethereum/vbuterin-patch-3
Turned slashed and initiated_exit into booleans
This commit is contained in:
commit
d27132cb0a
|
@ -18,7 +18,6 @@
|
||||||
- [Time parameters](#time-parameters)
|
- [Time parameters](#time-parameters)
|
||||||
- [State list lengths](#state-list-lengths)
|
- [State list lengths](#state-list-lengths)
|
||||||
- [Reward and penalty quotients](#reward-and-penalty-quotients)
|
- [Reward and penalty quotients](#reward-and-penalty-quotients)
|
||||||
- [Status flags](#status-flags)
|
|
||||||
- [Max transactions per block](#max-transactions-per-block)
|
- [Max transactions per block](#max-transactions-per-block)
|
||||||
- [Signature domains](#signature-domains)
|
- [Signature domains](#signature-domains)
|
||||||
- [Data structures](#data-structures)
|
- [Data structures](#data-structures)
|
||||||
|
@ -90,7 +89,7 @@
|
||||||
- [`is_double_vote`](#is_double_vote)
|
- [`is_double_vote`](#is_double_vote)
|
||||||
- [`is_surround_vote`](#is_surround_vote)
|
- [`is_surround_vote`](#is_surround_vote)
|
||||||
- [`integer_squareroot`](#integer_squareroot)
|
- [`integer_squareroot`](#integer_squareroot)
|
||||||
- [`get_entry_exit_effect_epoch`](#get_entry_exit_effect_epoch)
|
- [`get_delayed_activation_exit_epoch`](#get_delayed_activation_exit_epoch)
|
||||||
- [`bls_verify`](#bls_verify)
|
- [`bls_verify`](#bls_verify)
|
||||||
- [`bls_verify_multiple`](#bls_verify_multiple)
|
- [`bls_verify_multiple`](#bls_verify_multiple)
|
||||||
- [`bls_aggregate_pubkeys`](#bls_aggregate_pubkeys)
|
- [`bls_aggregate_pubkeys`](#bls_aggregate_pubkeys)
|
||||||
|
@ -256,11 +255,6 @@ Code snippets appearing in `this style` are to be interpreted as Python code.
|
||||||
* The `BASE_REWARD_QUOTIENT` parameter dictates the per-epoch reward. It corresponds to ~2.54% annual interest assuming 10 million participating ETH in every epoch.
|
* The `BASE_REWARD_QUOTIENT` parameter dictates the per-epoch reward. It corresponds to ~2.54% annual interest assuming 10 million participating ETH in every epoch.
|
||||||
* The `INACTIVITY_PENALTY_QUOTIENT` equals `INVERSE_SQRT_E_DROP_TIME**2` where `INVERSE_SQRT_E_DROP_TIME := 2**12 epochs` (~18 days) is the time it takes the inactivity penalty to reduce the balance of non-participating [validators](#dfn-validator) to about `1/sqrt(e) ~= 60.6%`. Indeed, the balance retained by offline [validators](#dfn-validator) after `n` epochs is about `(1-1/INACTIVITY_PENALTY_QUOTIENT)**(n**2/2)` so after `INVERSE_SQRT_E_DROP_TIME` epochs it is roughly `(1-1/INACTIVITY_PENALTY_QUOTIENT)**(INACTIVITY_PENALTY_QUOTIENT/2) ~= 1/sqrt(e)`.
|
* The `INACTIVITY_PENALTY_QUOTIENT` equals `INVERSE_SQRT_E_DROP_TIME**2` where `INVERSE_SQRT_E_DROP_TIME := 2**12 epochs` (~18 days) is the time it takes the inactivity penalty to reduce the balance of non-participating [validators](#dfn-validator) to about `1/sqrt(e) ~= 60.6%`. Indeed, the balance retained by offline [validators](#dfn-validator) after `n` epochs is about `(1-1/INACTIVITY_PENALTY_QUOTIENT)**(n**2/2)` so after `INVERSE_SQRT_E_DROP_TIME` epochs it is roughly `(1-1/INACTIVITY_PENALTY_QUOTIENT)**(INACTIVITY_PENALTY_QUOTIENT/2) ~= 1/sqrt(e)`.
|
||||||
|
|
||||||
### Status flags
|
|
||||||
|
|
||||||
| Name | Value |
|
|
||||||
| - | - |
|
|
||||||
| `INITIATED_EXIT` | `2**0` (= 1) |
|
|
||||||
|
|
||||||
### Max transactions per block
|
### Max transactions per block
|
||||||
|
|
||||||
|
@ -571,10 +565,10 @@ The following data structures are defined as [SimpleSerialize (SSZ)](https://git
|
||||||
'exit_epoch': 'uint64',
|
'exit_epoch': 'uint64',
|
||||||
# Epoch when validator is eligible to withdraw
|
# Epoch when validator is eligible to withdraw
|
||||||
'withdrawable_epoch': 'uint64',
|
'withdrawable_epoch': 'uint64',
|
||||||
# Epoch when validator was slashed
|
# Did the validator initiate an exit
|
||||||
'slashed_epoch': 'uint64',
|
'initiated_exit': 'bool',
|
||||||
# Status flags
|
# Was the validator slashed
|
||||||
'status_flags': 'uint64',
|
'slashed': 'bool',
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -1207,13 +1201,12 @@ def integer_squareroot(n: int) -> int:
|
||||||
return x
|
return x
|
||||||
```
|
```
|
||||||
|
|
||||||
### `get_entry_exit_effect_epoch`
|
### `get_delayed_activation_exit_epoch`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def get_entry_exit_effect_epoch(epoch: Epoch) -> Epoch:
|
def get_delayed_activation_exit_epoch(epoch: Epoch) -> Epoch:
|
||||||
"""
|
"""
|
||||||
An entry or exit triggered in the ``epoch`` given by the input takes effect at
|
Return the epoch at which an activation or exit triggered in ``epoch`` takes effect.
|
||||||
the epoch given by the output.
|
|
||||||
"""
|
"""
|
||||||
return epoch + 1 + ACTIVATION_EXIT_DELAY
|
return epoch + 1 + ACTIVATION_EXIT_DELAY
|
||||||
```
|
```
|
||||||
|
@ -1266,8 +1259,8 @@ def process_deposit(state: BeaconState, deposit: Deposit) -> None:
|
||||||
activation_epoch=FAR_FUTURE_EPOCH,
|
activation_epoch=FAR_FUTURE_EPOCH,
|
||||||
exit_epoch=FAR_FUTURE_EPOCH,
|
exit_epoch=FAR_FUTURE_EPOCH,
|
||||||
withdrawable_epoch=FAR_FUTURE_EPOCH,
|
withdrawable_epoch=FAR_FUTURE_EPOCH,
|
||||||
slashed_epoch=FAR_FUTURE_EPOCH,
|
initiated_exit=False,
|
||||||
status_flags=0,
|
slashed=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Note: In phase 2 registry indices that have been withdrawn for a long time will be recycled.
|
# Note: In phase 2 registry indices that have been withdrawn for a long time will be recycled.
|
||||||
|
@ -1295,7 +1288,7 @@ def activate_validator(state: BeaconState, index: ValidatorIndex, is_genesis: bo
|
||||||
"""
|
"""
|
||||||
validator = state.validator_registry[index]
|
validator = state.validator_registry[index]
|
||||||
|
|
||||||
validator.activation_epoch = GENESIS_EPOCH if is_genesis else get_entry_exit_effect_epoch(get_current_epoch(state))
|
validator.activation_epoch = GENESIS_EPOCH if is_genesis else get_delayed_activation_exit_epoch(get_current_epoch(state))
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `initiate_validator_exit`
|
#### `initiate_validator_exit`
|
||||||
|
@ -1307,7 +1300,7 @@ def initiate_validator_exit(state: BeaconState, index: ValidatorIndex) -> None:
|
||||||
Note that this function mutates ``state``.
|
Note that this function mutates ``state``.
|
||||||
"""
|
"""
|
||||||
validator = state.validator_registry[index]
|
validator = state.validator_registry[index]
|
||||||
validator.status_flags |= INITIATED_EXIT
|
validator.initiated_exit = True
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `exit_validator`
|
#### `exit_validator`
|
||||||
|
@ -1321,10 +1314,10 @@ def exit_validator(state: BeaconState, index: ValidatorIndex) -> None:
|
||||||
validator = state.validator_registry[index]
|
validator = state.validator_registry[index]
|
||||||
|
|
||||||
# The following updates only occur if not previous exited
|
# The following updates only occur if not previous exited
|
||||||
if validator.exit_epoch <= get_entry_exit_effect_epoch(get_current_epoch(state)):
|
if validator.exit_epoch <= get_delayed_activation_exit_epoch(get_current_epoch(state)):
|
||||||
return
|
return
|
||||||
|
|
||||||
validator.exit_epoch = get_entry_exit_effect_epoch(get_current_epoch(state))
|
validator.exit_epoch = get_delayed_activation_exit_epoch(get_current_epoch(state))
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `slash_validator`
|
#### `slash_validator`
|
||||||
|
@ -1344,7 +1337,7 @@ def slash_validator(state: BeaconState, index: ValidatorIndex) -> None:
|
||||||
whistleblower_reward = get_effective_balance(state, index) // WHISTLEBLOWER_REWARD_QUOTIENT
|
whistleblower_reward = get_effective_balance(state, index) // WHISTLEBLOWER_REWARD_QUOTIENT
|
||||||
state.validator_balances[whistleblower_index] += whistleblower_reward
|
state.validator_balances[whistleblower_index] += whistleblower_reward
|
||||||
state.validator_balances[index] -= whistleblower_reward
|
state.validator_balances[index] -= whistleblower_reward
|
||||||
validator.slashed_epoch = get_current_epoch(state)
|
validator.slashed = True
|
||||||
validator.withdrawable_epoch = get_current_epoch(state) + LATEST_SLASHED_EXIT_LENGTH
|
validator.withdrawable_epoch = get_current_epoch(state) + LATEST_SLASHED_EXIT_LENGTH
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -1637,7 +1630,7 @@ For each `proposer_slashing` in `block.body.proposer_slashings`:
|
||||||
* Verify that `proposer_slashing.proposal_1.slot == proposer_slashing.proposal_2.slot`.
|
* Verify that `proposer_slashing.proposal_1.slot == proposer_slashing.proposal_2.slot`.
|
||||||
* Verify that `proposer_slashing.proposal_1.shard == proposer_slashing.proposal_2.shard`.
|
* Verify that `proposer_slashing.proposal_1.shard == proposer_slashing.proposal_2.shard`.
|
||||||
* Verify that `proposer_slashing.proposal_1.block_root != proposer_slashing.proposal_2.block_root`.
|
* Verify that `proposer_slashing.proposal_1.block_root != proposer_slashing.proposal_2.block_root`.
|
||||||
* Verify that `proposer.slashed_epoch > get_current_epoch(state)`.
|
* Verify that `proposer.slashed == False`.
|
||||||
* Verify that `bls_verify(pubkey=proposer.pubkey, message_hash=signed_root(proposer_slashing.proposal_1, "signature"), signature=proposer_slashing.proposal_1.signature, domain=get_domain(state.fork, slot_to_epoch(proposer_slashing.proposal_1.slot), DOMAIN_PROPOSAL))`.
|
* Verify that `bls_verify(pubkey=proposer.pubkey, message_hash=signed_root(proposer_slashing.proposal_1, "signature"), signature=proposer_slashing.proposal_1.signature, domain=get_domain(state.fork, slot_to_epoch(proposer_slashing.proposal_1.slot), DOMAIN_PROPOSAL))`.
|
||||||
* Verify that `bls_verify(pubkey=proposer.pubkey, message_hash=signed_root(proposer_slashing.proposal_2, "signature"), signature=proposer_slashing.proposal_2.signature, domain=get_domain(state.fork, slot_to_epoch(proposer_slashing.proposal_2.slot), DOMAIN_PROPOSAL))`.
|
* Verify that `bls_verify(pubkey=proposer.pubkey, message_hash=signed_root(proposer_slashing.proposal_2, "signature"), signature=proposer_slashing.proposal_2.signature, domain=get_domain(state.fork, slot_to_epoch(proposer_slashing.proposal_2.slot), DOMAIN_PROPOSAL))`.
|
||||||
* Run `slash_validator(state, proposer_slashing.proposer_index)`.
|
* Run `slash_validator(state, proposer_slashing.proposer_index)`.
|
||||||
|
@ -1654,7 +1647,7 @@ For each `attester_slashing` in `block.body.attester_slashings`:
|
||||||
* Verify that `is_double_vote(slashable_attestation_1.data, slashable_attestation_2.data)` or `is_surround_vote(slashable_attestation_1.data, slashable_attestation_2.data)`.
|
* Verify that `is_double_vote(slashable_attestation_1.data, slashable_attestation_2.data)` or `is_surround_vote(slashable_attestation_1.data, slashable_attestation_2.data)`.
|
||||||
* Verify that `verify_slashable_attestation(state, slashable_attestation_1)`.
|
* Verify that `verify_slashable_attestation(state, slashable_attestation_1)`.
|
||||||
* Verify that `verify_slashable_attestation(state, slashable_attestation_2)`.
|
* Verify that `verify_slashable_attestation(state, slashable_attestation_2)`.
|
||||||
* Let `slashable_indices = [index for index in slashable_attestation_1.validator_indices if index in slashable_attestation_2.validator_indices and state.validator_registry[index].slashed_epoch > get_current_epoch(state)]`.
|
* Let `slashable_indices = [index for index in slashable_attestation_1.validator_indices if index in slashable_attestation_2.validator_indices and state.validator_registry[index].slashed == False]`.
|
||||||
* Verify that `len(slashable_indices) >= 1`.
|
* Verify that `len(slashable_indices) >= 1`.
|
||||||
* Run `slash_validator(state, index)` for each `index` in `slashable_indices`.
|
* Run `slash_validator(state, index)` for each `index` in `slashable_indices`.
|
||||||
|
|
||||||
|
@ -1745,7 +1738,7 @@ Verify that `len(block.body.voluntary_exits) <= MAX_VOLUNTARY_EXITS`.
|
||||||
For each `exit` in `block.body.voluntary_exits`:
|
For each `exit` in `block.body.voluntary_exits`:
|
||||||
|
|
||||||
* Let `validator = state.validator_registry[exit.validator_index]`.
|
* Let `validator = state.validator_registry[exit.validator_index]`.
|
||||||
* Verify that `validator.exit_epoch > get_entry_exit_effect_epoch(get_current_epoch(state))`.
|
* Verify that `validator.exit_epoch > get_delayed_activation_exit_epoch(get_current_epoch(state))`.
|
||||||
* Verify that `get_current_epoch(state) >= exit.epoch`.
|
* Verify that `get_current_epoch(state) >= exit.epoch`.
|
||||||
* Verify that `bls_verify(pubkey=validator.pubkey, message_hash=signed_root(exit, "signature"), signature=exit.signature, domain=get_domain(state.fork, exit.epoch, DOMAIN_EXIT))`.
|
* Verify that `bls_verify(pubkey=validator.pubkey, message_hash=signed_root(exit, "signature"), signature=exit.signature, domain=get_domain(state.fork, exit.epoch, DOMAIN_EXIT))`.
|
||||||
* Run `initiate_validator_exit(state, exit.validator_index)`.
|
* Run `initiate_validator_exit(state, exit.validator_index)`.
|
||||||
|
@ -1888,7 +1881,7 @@ Case 2: `epochs_since_finality > 4`:
|
||||||
* Any [active validator](#dfn-active-validator) `index` not in `previous_epoch_attester_indices`, loses `inactivity_penalty(state, index, epochs_since_finality)`.
|
* Any [active validator](#dfn-active-validator) `index` not in `previous_epoch_attester_indices`, loses `inactivity_penalty(state, index, epochs_since_finality)`.
|
||||||
* Any [active validator](#dfn-active-validator) `index` not in `previous_epoch_boundary_attester_indices`, loses `inactivity_penalty(state, index, epochs_since_finality)`.
|
* Any [active validator](#dfn-active-validator) `index` not in `previous_epoch_boundary_attester_indices`, loses `inactivity_penalty(state, index, epochs_since_finality)`.
|
||||||
* Any [active validator](#dfn-active-validator) `index` not in `previous_epoch_head_attester_indices`, loses `base_reward(state, index)`.
|
* Any [active validator](#dfn-active-validator) `index` not in `previous_epoch_head_attester_indices`, loses `base_reward(state, index)`.
|
||||||
* Any [active validator](#dfn-active-validator) `index` with `validator.slashed_epoch <= current_epoch`, loses `2 * inactivity_penalty(state, index, epochs_since_finality) + base_reward(state, index)`.
|
* Any [active validator](#dfn-active-validator) `index` with `validator.slashed == True`, loses `2 * inactivity_penalty(state, index, epochs_since_finality) + base_reward(state, index)`.
|
||||||
* Any [validator](#dfn-validator) `index` in `previous_epoch_attester_indices` loses `base_reward(state, index) - base_reward(state, index) * MIN_ATTESTATION_INCLUSION_DELAY // inclusion_distance(state, index)`
|
* Any [validator](#dfn-validator) `index` in `previous_epoch_attester_indices` loses `base_reward(state, index) - base_reward(state, index) * MIN_ATTESTATION_INCLUSION_DELAY // inclusion_distance(state, index)`
|
||||||
|
|
||||||
##### Attestation inclusion
|
##### Attestation inclusion
|
||||||
|
@ -1955,7 +1948,7 @@ def update_validator_registry(state: BeaconState) -> None:
|
||||||
# Activate validators within the allowable balance churn
|
# Activate validators within the allowable balance churn
|
||||||
balance_churn = 0
|
balance_churn = 0
|
||||||
for index, validator in enumerate(state.validator_registry):
|
for index, validator in enumerate(state.validator_registry):
|
||||||
if validator.activation_epoch > get_entry_exit_effect_epoch(current_epoch) and state.validator_balances[index] >= MAX_DEPOSIT_AMOUNT:
|
if validator.activation_epoch == FAR_FUTURE_EPOCH and state.validator_balances[index] >= MAX_DEPOSIT_AMOUNT:
|
||||||
# Check the balance churn would be within the allowance
|
# Check the balance churn would be within the allowance
|
||||||
balance_churn += get_effective_balance(state, index)
|
balance_churn += get_effective_balance(state, index)
|
||||||
if balance_churn > max_balance_churn:
|
if balance_churn > max_balance_churn:
|
||||||
|
@ -1967,7 +1960,7 @@ def update_validator_registry(state: BeaconState) -> None:
|
||||||
# Exit validators within the allowable balance churn
|
# Exit validators within the allowable balance churn
|
||||||
balance_churn = 0
|
balance_churn = 0
|
||||||
for index, validator in enumerate(state.validator_registry):
|
for index, validator in enumerate(state.validator_registry):
|
||||||
if validator.exit_epoch > get_entry_exit_effect_epoch(current_epoch) and validator.status_flags & INITIATED_EXIT:
|
if validator.activation_epoch == FAR_FUTURE_EPOCH and validator.initiated_exit:
|
||||||
# Check the balance churn would be within the allowance
|
# Check the balance churn would be within the allowance
|
||||||
balance_churn += get_effective_balance(state, index)
|
balance_churn += get_effective_balance(state, index)
|
||||||
if balance_churn > max_balance_churn:
|
if balance_churn > max_balance_churn:
|
||||||
|
@ -2008,7 +2001,7 @@ def process_slashings(state: BeaconState) -> None:
|
||||||
total_balance = sum(get_effective_balance(state, i) for i in active_validator_indices)
|
total_balance = sum(get_effective_balance(state, i) for i in active_validator_indices)
|
||||||
|
|
||||||
for index, validator in enumerate(state.validator_registry):
|
for index, validator in enumerate(state.validator_registry):
|
||||||
if current_epoch == validator.slashed_epoch + LATEST_SLASHED_EXIT_LENGTH // 2:
|
if validator.slashed and current_epoch == validator.withdrawable_epoch - LATEST_SLASHED_EXIT_LENGTH // 2:
|
||||||
epoch_index = current_epoch % LATEST_SLASHED_EXIT_LENGTH
|
epoch_index = current_epoch % LATEST_SLASHED_EXIT_LENGTH
|
||||||
total_at_start = state.latest_slashed_balances[(epoch_index + 1) % LATEST_SLASHED_EXIT_LENGTH]
|
total_at_start = state.latest_slashed_balances[(epoch_index + 1) % LATEST_SLASHED_EXIT_LENGTH]
|
||||||
total_at_end = state.latest_slashed_balances[epoch_index]
|
total_at_end = state.latest_slashed_balances[epoch_index]
|
||||||
|
@ -2029,7 +2022,7 @@ def process_exit_queue(state: BeaconState) -> None:
|
||||||
def eligible(index):
|
def eligible(index):
|
||||||
validator = state.validator_registry[index]
|
validator = state.validator_registry[index]
|
||||||
# Filter out dequeued validators
|
# Filter out dequeued validators
|
||||||
if validator.withdrawable_epoch < FAR_FUTURE_EPOCH:
|
if validator.withdrawable_epoch != FAR_FUTURE_EPOCH:
|
||||||
return False
|
return False
|
||||||
# Dequeue if the minimum amount of time has passed
|
# Dequeue if the minimum amount of time has passed
|
||||||
else:
|
else:
|
||||||
|
|
Loading…
Reference in New Issue