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

Withdrawal queue -> exit queue #850

Merged
merged 34 commits into from
Apr 14, 2019
Merged
Changes from 1 commit
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
1aaa003
Withdrawal queue -> exit queue
vbuterin Mar 28, 2019
deb0e32
Fixes to make Justin happy
vbuterin Mar 28, 2019
aa4bbcc
Bugfix
hwwhww Mar 28, 2019
9c4e034
Merge branch 'dev' into vbuterin-patch-13
hwwhww Mar 29, 2019
a2dae9a
Fix after merging
hwwhww Mar 29, 2019
15498f2
Fixed exit epoch conditional
vbuterin Mar 31, 2019
2529cb1
Update 0_beacon-chain.md
JustinDrake Apr 3, 2019
169579c
Update 0_beacon-chain.md
JustinDrake Apr 6, 2019
7f0a93f
Update 0_beacon-chain.md
JustinDrake Apr 6, 2019
63412d9
Update 0_beacon-chain.md
JustinDrake Apr 6, 2019
5ea5746
Fix `get_genesis_beacon_state` and minor refactoring
hwwhww Apr 6, 2019
8958cf8
Merge branch 'dev' into vbuterin-patch-13
hwwhww Apr 6, 2019
ebba3f5
Fix typo
hwwhww Apr 6, 2019
00872e0
Updated tests
hwwhww Apr 6, 2019
47464f2
Update 0_beacon-chain.md
JustinDrake Apr 6, 2019
4630b13
Fix/Remove pointless assertion
hwwhww Apr 7, 2019
846e2d6
Remove `force_registry_change_at_next_epoch`
hwwhww Apr 7, 2019
cc2d005
Merge branch 'dev' into vbuterin-patch-13
vbuterin Apr 13, 2019
f7c5b0a
set activation_eligibility_epoch during process_deposit
djrtwo Apr 13, 2019
3700440
add exit queue test
djrtwo Apr 13, 2019
bade9ff
enhance exit queue test
djrtwo Apr 13, 2019
f85e7ac
Added churn limit logic
vbuterin Apr 14, 2019
0d64483
Update 0_beacon-chain.md
JustinDrake Apr 14, 2019
d01fb80
Update 0_beacon-chain.md
JustinDrake Apr 14, 2019
15bb967
Update 0_beacon-chain.md
JustinDrake Apr 14, 2019
7705ecf
Update 0_beacon-chain.md
JustinDrake Apr 14, 2019
da4a143
fix test
djrtwo Apr 14, 2019
229af3d
Update 0_beacon-chain.md
JustinDrake Apr 14, 2019
0b77012
Update 0_beacon-chain.md
JustinDrake Apr 14, 2019
06807cf
fix tests and off by one error
djrtwo Apr 14, 2019
704ea7c
Merge branch 'vbuterin-patch-13' of github.com:ethereum/eth2.0-specs …
djrtwo Apr 14, 2019
0908ffa
Update 0_beacon-chain.md
JustinDrake Apr 14, 2019
875b2ba
Update 0_beacon-chain.md
JustinDrake Apr 14, 2019
3394368
Update 0_beacon-chain.md
JustinDrake Apr 14, 2019
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
181 changes: 55 additions & 126 deletions specs/core/0_beacon-chain.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,7 @@
- [Routines for updating validator status](#routines-for-updating-validator-status)
- [`activate_validator`](#activate_validator)
- [`initiate_validator_exit`](#initiate_validator_exit)
- [`exit_validator`](#exit_validator)
- [`slash_validator`](#slash_validator)
- [`prepare_validator_for_withdrawal`](#prepare_validator_for_withdrawal)
- [Ethereum 1.0 deposit contract](#ethereum-10-deposit-contract)
- [Deposit arguments](#deposit-arguments)
- [Withdrawal credentials](#withdrawal-credentials)
Expand All @@ -121,8 +119,8 @@
- [Justification and finalization](#justification-and-finalization)
- [Crosslinks](#crosslinks-1)
- [Apply rewards](#apply-rewards)
- [Ejections](#ejections)
- [Validator registry and shuffling seed data](#validator-registry-and-shuffling-seed-data)
- [Balance-driven status transitions](#balance-driven-status-transitions)
- [Validator registry and start shard](#validator-registry-and-start-shard)
- [Slashings and exit queue](#slashings-and-exit-queue)
- [Final updates](#final-updates)
- [Per-slot processing](#per-slot-processing)
Expand Down Expand Up @@ -182,7 +180,6 @@ Code snippets appearing in `this style` are to be interpreted as Python code.
| - | - |
| `SHARD_COUNT` | `2**10` (= 1,024) |
| `TARGET_COMMITTEE_SIZE` | `2**7` (= 128) |
| `MAX_BALANCE_CHURN_QUOTIENT` | `2**5` (= 32) |
| `MAX_SLASHABLE_ATTESTATION_PARTICIPANTS` | `2**12` (= 4,096) |
| `MAX_EXIT_DEQUEUES_PER_EPOCH` | `2**2` (= 4) |
| `SHUFFLE_ROUND_COUNT` | 90 |
Expand Down Expand Up @@ -418,14 +415,14 @@ The types are defined topologically to aid in facilitating an executable version
'pubkey': 'bytes48',
# Withdrawal credentials
'withdrawal_credentials': 'bytes32',
# Epoch when became eligible for activation
'activation_eligibility_epoch': 'uint64',
vbuterin marked this conversation as resolved.
Show resolved Hide resolved
# Epoch when validator activated
'activation_epoch': 'uint64',
# Epoch when validator exited
'exit_epoch': 'uint64',
# Epoch when validator is eligible to withdraw
'withdrawable_epoch': 'uint64',
# Did the validator initiate an exit
'initiated_exit': 'bool',
vbuterin marked this conversation as resolved.
Show resolved Hide resolved
# Was the validator slashed
'slashed': 'bool',
# Rounded balance
Expand Down Expand Up @@ -596,6 +593,10 @@ The types are defined topologically to aid in facilitating an executable version
# Randomness and committees
'latest_randao_mixes': ['bytes32', LATEST_RANDAO_MIXES_LENGTH],
'latest_start_shard': 'uint64',

# Exit queue
'exit_epoch': 'uint64',
'exit_queue_filled': 'uint64'

# Finality
'previous_epoch_attestations': [PendingAttestation],
Expand Down Expand Up @@ -1352,22 +1353,20 @@ def initiate_validator_exit(state: BeaconState, index: ValidatorIndex) -> None:
Note that this function mutates ``state``.
"""
validator = state.validator_registry[index]
validator.initiated_exit = True
```

#### `exit_validator`

```python
def exit_validator(state: BeaconState, index: ValidatorIndex) -> None:
"""
Exit the validator with the given ``index``.
Note that this function mutates ``state``.
"""
validator = state.validator_registry[index]

# Update validator exit epoch if not previously exited
# Operation is a no-op if validator is already in the queue
if validator.exit_epoch == FAR_FUTURE_EPOCH:
validator.exit_epoch = get_delayed_activation_exit_epoch(get_current_epoch(state))
# Update exit queue counters
if state.exit_epoch < get_delayed_activation_exit_epoch(get_current_epoch(state)):
state.exit_epoch = get_delayed_activation_exit_epoch(get_current_epoch(state))
if state.exit_queue_filled >= MAX_EXIT_DEQUEUES_PER_EPOCH:
state.exit_epoch += 1
state.exit_queue_filled = 0
# Set validator exit epoch and withdrawable epoch
if validator.exit_epoch > state.exit_epoch:
validator.exit_epoch = state.exit_epoch
JustinDrake marked this conversation as resolved.
Show resolved Hide resolved
validator.withdrawable_epoch = validator.exit_epoch + MIN_VALIDATOR_WITHDRAWABILITY_DELAY
# Extend queue
state.exit_queue_filled += 1
```

#### `slash_validator`
Expand All @@ -1379,7 +1378,7 @@ def slash_validator(state: BeaconState, index: ValidatorIndex) -> None:
Note that this function mutates ``state``.
"""
validator = state.validator_registry[index]
exit_validator(state, index)
initiate_validator_exit(state, index)
state.latest_slashed_balances[get_current_epoch(state) % LATEST_SLASHED_EXIT_LENGTH] += get_effective_balance(state, index)

whistleblower_index = get_beacon_proposer_index(state, state.slot)
Expand All @@ -1390,19 +1389,6 @@ def slash_validator(state: BeaconState, index: ValidatorIndex) -> None:
validator.withdrawable_epoch = get_current_epoch(state) + LATEST_SLASHED_EXIT_LENGTH
```

#### `prepare_validator_for_withdrawal`

```python
def prepare_validator_for_withdrawal(state: BeaconState, index: ValidatorIndex) -> None:
"""
Set the validator with the given ``index`` as withdrawable
``MIN_VALIDATOR_WITHDRAWABILITY_DELAY`` after the current epoch.
Note that this function mutates ``state``.
"""
validator = state.validator_registry[index]
validator.withdrawable_epoch = get_current_epoch(state) + MIN_VALIDATOR_WITHDRAWABILITY_DELAY
```

## Ethereum 1.0 deposit contract

The initial deployment phases of Ethereum 2.0 are implemented without consensus changes to Ethereum 1.0. A deposit contract at address `DEPOSIT_CONTRACT_ADDRESS` is added to Ethereum 1.0 for deposits of ETH to the beacon chain. Validator balances will be withdrawable to the shards in phase 2, i.e. when the EVM2.0 is deployed and the shards have state.
Expand Down Expand Up @@ -1512,6 +1498,10 @@ def get_genesis_beacon_state(genesis_validator_deposits: List[Deposit],
# Randomness and committees
latest_randao_mixes=Vector([ZERO_HASH for _ in range(LATEST_RANDAO_MIXES_LENGTH)]),
latest_start_shard=GENESIS_START_SHARD,

# Exit queue
exit_epoch=GENESIS_EPOCH,
exit_queue_filled=0,

# Finality
previous_epoch_attestations=[],
Expand Down Expand Up @@ -1690,16 +1680,16 @@ def get_previous_total_balance(state: BeaconState) -> Gwei:
```

```python
def get_attesting_indices(state: BeaconState, attestations: List[PendingAttestation]) -> List[ValidatorIndex]:
def get_unslashed_attesting_indices(state: BeaconState, attestations: List[PendingAttestation]) -> List[ValidatorIndex]:
output = set()
for a in attestations:
output = output.union(get_attestation_participants(state, a.data, a.aggregation_bitfield))
return sorted(list(output))
return sorted(filter(lambda index: not state.validator_registry[index].is_slashed, list(output)))
```

```python
def get_attesting_balance(state: BeaconState, attestations: List[PendingAttestation]) -> Gwei:
return get_total_balance(state, get_attesting_indices(state, attestations))
return get_total_balance(state, get_unslashed_attesting_indices(state, attestations))
```

```python
Expand Down Expand Up @@ -1747,7 +1737,7 @@ def get_winning_root_and_participants(state: BeaconState, shard: Shard) -> Tuple
# lexicographically higher hash
winning_root = max(all_roots, key=lambda r: (get_attesting_balance(state, get_attestations_for(r)), r))

return winning_root, get_attesting_indices(state, get_attestations_for(winning_root))
return winning_root, get_unslashed_attesting_indices(state, get_attestations_for(winning_root))
```

```python
Expand Down Expand Up @@ -1904,7 +1894,7 @@ def get_justification_and_finalization_deltas(state: BeaconState) -> Tuple[List[
for index in eligible_validators:
JustinDrake marked this conversation as resolved.
Show resolved Hide resolved
base_reward = get_base_reward(state, index)
# Expected FFG source
if index in get_attesting_indices(state, state.previous_epoch_attestations):
if index in get_unslashed_attesting_indices(state, state.previous_epoch_attestations):
rewards[index] += base_reward * total_attesting_balance // total_balance
# Inclusion speed bonus
rewards[index] += (
Expand All @@ -1914,17 +1904,17 @@ def get_justification_and_finalization_deltas(state: BeaconState) -> Tuple[List[
else:
penalties[index] += base_reward
# Expected FFG target
if index in get_attesting_indices(state, boundary_attestations):
if index in get_unslashed_attesting_indices(state, boundary_attestations):
rewards[index] += base_reward * boundary_attesting_balance // total_balance
else:
penalties[index] += get_inactivity_penalty(state, index, epochs_since_finality)
# Expected head
if index in get_attesting_indices(state, matching_head_attestations):
if index in get_unslashed_attesting_indices(state, matching_head_attestations):
rewards[index] += base_reward * matching_head_balance // total_balance
else:
penalties[index] += base_reward
# Proposer bonus
if index in get_attesting_indices(state, state.previous_epoch_attestations):
if index in get_unslashed_attesting_indices(state, state.previous_epoch_attestations):
proposer_index = get_beacon_proposer_index(state, inclusion_slot(state, index))
rewards[proposer_index] += base_reward // ATTESTATION_INCLUSION_REWARD_QUOTIENT
# Take away max rewards if we're not finalizing
Expand Down Expand Up @@ -1973,80 +1963,43 @@ def apply_rewards(state: BeaconState) -> None:
)
```

#### Ejections
#### Balance-driven status transitions

Run `process_ejections(state)`.
Run `process_balance_driven_status_transitions(state)`.

```python
def process_ejections(state: BeaconState) -> None:
"""
Iterate through the validator registry
and eject active validators with balance below ``EJECTION_BALANCE``.
and deposit or eject active validators with sufficiently high or low balances
"""
for index in get_active_validator_indices(state.validator_registry, get_current_epoch(state)):
if get_balance(state, index) < EJECTION_BALANCE:
for index, validator in enumeratE(state.validator_registry):
vbuterin marked this conversation as resolved.
Show resolved Hide resolved
if validator.activation_eligibility_epoch == FAR_FUTURE_EPOCH and balance >= MAX_DEPOSIT_AMOUNT:
state.activation_eligibility_epoch = get_current_epoch(state)
if is_active(validator, get_current_epoch(state)) and get_balance(state, index) < EJECTION_BALANCE:
initiate_validator_exit(state, index)
```

#### Validator registry and shuffling seed data

```python
def update_validator_registry(state: BeaconState) -> None:
"""
Update validator registry.
Note that this function mutates ``state``.
"""
current_epoch = get_current_epoch(state)
# The active validators
active_validator_indices = get_active_validator_indices(state.validator_registry, current_epoch)
# The total effective balance of active validators
total_balance = get_total_balance(state, active_validator_indices)

# The maximum balance churn in Gwei (for deposits and exits separately)
max_balance_churn = max(
MAX_DEPOSIT_AMOUNT,
total_balance // (2 * MAX_BALANCE_CHURN_QUOTIENT)
)

# Activate validators within the allowable balance churn
balance_churn = 0
for index, validator in enumerate(state.validator_registry):
if validator.activation_epoch == FAR_FUTURE_EPOCH and get_balance(state, 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:
break

# Activate validator
activate_validator(state, index, is_genesis=False)

# Exit validators within the allowable balance churn
if current_epoch < state.validator_registry_update_epoch + LATEST_SLASHED_EXIT_LENGTH:
balance_churn = (
state.latest_slashed_balances[state.validator_registry_update_epoch % LATEST_SLASHED_EXIT_LENGTH] -
state.latest_slashed_balances[current_epoch % LATEST_SLASHED_EXIT_LENGTH]
)

for index, validator in enumerate(state.validator_registry):
if validator.exit_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:
break

# Exit validator
exit_validator(state, index)

state.validator_registry_update_epoch = current_epoch
```
#### Validator registry and start shard

Run the following function:

```python
def update_registry(state: BeaconState) -> None:
# Check if we should update, and if so, update
if state.finalized_epoch > state.validator_registry_update_epoch:
update_validator_registry(state)
# Validator indices that could be activated
indices_for_activation = sorted(
filter(
lambda index: state.validator_registry[index].activation_epoch == FAR_FUTURE_EPOCH
get_active_validator_indices(state.validator_registry, current_epoch),
),
key=lambda index: state.validator_registry[index].activation_eligibility_epoch
)
for index in indices_for_activation[:MAX_EXIT_DEQUEUES_PER_EPOCH]:
activate_validator(state, index, is_genesis=False)

state.validator_registry_update_epoch = current_epoch
state.latest_start_shard = (
state.latest_start_shard +
get_current_epoch_committee_count(state)
Expand All @@ -2057,7 +2010,7 @@ def update_registry(state: BeaconState) -> None:

#### Slashings and exit queue

Run `process_slashings(state)` and `process_exit_queue(state)`:
Run `process_slashings(state)`:

```python
def process_slashings(state: BeaconState) -> None:
Expand All @@ -2083,30 +2036,6 @@ def process_slashings(state: BeaconState) -> None:
decrease_balance(state, index, penalty)
```

```python
def process_exit_queue(state: BeaconState) -> None:
"""
Process the exit queue.
Note that this function mutates ``state``.
"""
def eligible(index):
validator = state.validator_registry[index]
# Filter out dequeued validators
if validator.withdrawable_epoch != FAR_FUTURE_EPOCH:
return False
# Dequeue if the minimum amount of time has passed
else:
return get_current_epoch(state) >= validator.exit_epoch + MIN_VALIDATOR_WITHDRAWABILITY_DELAY

eligible_indices = filter(eligible, list(range(len(state.validator_registry))))
# Sort in order of exit epoch, and validators that exit within the same epoch exit in order of validator index
sorted_indices = sorted(eligible_indices, key=lambda index: state.validator_registry[index].exit_epoch)
for dequeues, index in enumerate(sorted_indices):
if dequeues >= MAX_EXIT_DEQUEUES_PER_EPOCH:
break
prepare_validator_for_withdrawal(state, index)
```

#### Final updates

Run the following function:
Expand Down