Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Turned slashed and initiated_exit into booleans #658

Merged
merged 4 commits into from
Feb 22, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 23 additions & 30 deletions specs/core/0_beacon-chain.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
- [Time parameters](#time-parameters)
- [State list lengths](#state-list-lengths)
- [Reward and penalty quotients](#reward-and-penalty-quotients)
- [Status flags](#status-flags)
- [Max transactions per block](#max-transactions-per-block)
- [Signature domains](#signature-domains)
- [Data structures](#data-structures)
Expand Down Expand Up @@ -90,7 +89,7 @@
- [`is_double_vote`](#is_double_vote)
- [`is_surround_vote`](#is_surround_vote)
- [`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_multiple`](#bls_verify_multiple)
- [`bls_aggregate_pubkeys`](#bls_aggregate_pubkeys)
Expand Down Expand Up @@ -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 `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

Expand Down Expand Up @@ -571,10 +565,10 @@ The following data structures are defined as [SimpleSerialize (SSZ)](https://git
'exit_epoch': 'uint64',
# Epoch when validator is eligible to withdraw
'withdrawable_epoch': 'uint64',
# Epoch when validator was slashed
'slashed_epoch': 'uint64',
# Status flags
'status_flags': 'uint64',
# Did the validator initiate an exit
'initiated_exit': 'bool',
# Was the validator slashed
'slashed': 'bool',
}
```

Expand Down Expand Up @@ -1214,13 +1208,12 @@ def integer_squareroot(n: int) -> int:
return x
```

### `get_entry_exit_effect_epoch`
### `get_delayed_activation_exit_epoch`

```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
the epoch given by the output.
Return the epoch at which an activation or exit triggered in ``epoch`` takes effect.
"""
return epoch + 1 + ACTIVATION_EXIT_DELAY
```
Expand Down Expand Up @@ -1273,8 +1266,8 @@ def process_deposit(state: BeaconState, deposit: Deposit) -> None:
activation_epoch=FAR_FUTURE_EPOCH,
exit_epoch=FAR_FUTURE_EPOCH,
withdrawable_epoch=FAR_FUTURE_EPOCH,
slashed_epoch=FAR_FUTURE_EPOCH,
status_flags=0,
initiated_exit=False,
slashed=False,
)

# Note: In phase 2 registry indices that have been withdrawn for a long time will be recycled.
Expand Down Expand Up @@ -1302,7 +1295,7 @@ def activate_validator(state: BeaconState, index: ValidatorIndex, is_genesis: bo
"""
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`
Expand All @@ -1314,7 +1307,7 @@ def initiate_validator_exit(state: BeaconState, index: ValidatorIndex) -> None:
Note that this function mutates ``state``.
"""
validator = state.validator_registry[index]
validator.status_flags |= INITIATED_EXIT
validator.initiated_exit = True
```

#### `exit_validator`
Expand All @@ -1328,10 +1321,10 @@ def exit_validator(state: BeaconState, index: ValidatorIndex) -> None:
validator = state.validator_registry[index]

# 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

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`
Expand All @@ -1351,7 +1344,7 @@ def slash_validator(state: BeaconState, index: ValidatorIndex) -> None:
whistleblower_reward = get_effective_balance(state, index) // WHISTLEBLOWER_REWARD_QUOTIENT
state.validator_balances[whistleblower_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
```

Expand Down Expand Up @@ -1644,7 +1637,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.shard == proposer_slashing.proposal_2.shard`.
* 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_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)`.
Expand All @@ -1661,7 +1654,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 `verify_slashable_attestation(state, slashable_attestation_1)`.
* 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`.
* Run `slash_validator(state, index)` for each `index` in `slashable_indices`.

Expand Down Expand Up @@ -1752,7 +1745,7 @@ Verify that `len(block.body.voluntary_exits) <= MAX_VOLUNTARY_EXITS`.
For each `exit` in `block.body.voluntary_exits`:

* 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 `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)`.
Expand Down Expand Up @@ -1895,7 +1888,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_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` 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)`

##### Attestation inclusion
Expand Down Expand Up @@ -1962,7 +1955,7 @@ def update_validator_registry(state: BeaconState) -> None:
# Activate validators within the allowable balance churn
balance_churn = 0
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
balance_churn += get_effective_balance(state, index)
if balance_churn > max_balance_churn:
Expand All @@ -1974,7 +1967,7 @@ def update_validator_registry(state: BeaconState) -> None:
# Exit validators within the allowable balance churn
balance_churn = 0
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
balance_churn += get_effective_balance(state, index)
if balance_churn > max_balance_churn:
Expand Down Expand Up @@ -2015,7 +2008,7 @@ def process_slashings(state: BeaconState) -> None:
total_balance = sum(get_effective_balance(state, i) for i in active_validator_indices)

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
total_at_start = state.latest_slashed_balances[(epoch_index + 1) % LATEST_SLASHED_EXIT_LENGTH]
total_at_end = state.latest_slashed_balances[epoch_index]
Expand All @@ -2036,7 +2029,7 @@ def process_exit_queue(state: BeaconState) -> None:
def eligible(index):
validator = state.validator_registry[index]
# Filter out dequeued validators
if validator.withdrawable_epoch < FAR_FUTURE_EPOCH:
if validator.withdrawable_epoch != FAR_FUTURE_EPOCH:
return False
# Dequeue if the minimum amount of time has passed
else:
Expand Down