working through future shuffling notes

This commit is contained in:
Danny Ryan 2019-01-29 16:29:51 -08:00
parent 56c6322054
commit a164ad9504
No known key found for this signature in database
GPG Key ID: 2765A792E42CE07A
2 changed files with 87 additions and 8 deletions

View File

@ -800,6 +800,17 @@ def get_current_epoch_committee_count(state: BeaconState) -> int:
return get_epoch_committee_count(len(current_active_validators)) return get_epoch_committee_count(len(current_active_validators))
``` ```
### `get_next_epoch_committee_count`
```python
def get_next_epoch_committee_count(state: BeaconState) -> int:
next_active_validators = get_active_validator_indices(
state.validator_registry,
get_current_epoch(state) + 1,
)
return get_epoch_committee_count(len(next_active_validators))
```
### `get_crosslink_committees_at_slot` ### `get_crosslink_committees_at_slot`
```python ```python
@ -807,24 +818,33 @@ def get_crosslink_committees_at_slot(state: BeaconState,
slot: SlotNumber) -> List[Tuple[List[ValidatorIndex], ShardNumber]]: slot: SlotNumber) -> List[Tuple[List[ValidatorIndex], ShardNumber]]:
""" """
Returns the list of ``(committee, shard)`` tuples for the ``slot``. Returns the list of ``(committee, shard)`` tuples for the ``slot``.
Note: Crosslink committees for a ``slot`` in the next epoch are only valid
if a validator registry change occurs at the end of the current epoch.
""" """
epoch = slot_to_epoch(slot) epoch = slot_to_epoch(slot)
current_epoch = get_current_epoch(state) current_epoch = get_current_epoch(state)
previous_epoch = current_epoch - 1 if current_epoch > GENESIS_EPOCH else current_epoch previous_epoch = current_epoch - 1 if current_epoch > GENESIS_EPOCH else current_epoch
next_epoch = current_epoch + 1 next_epoch = current_epoch + 1
assert previous_epoch <= epoch < next_epoch assert previous_epoch <= epoch <= next_epoch
if epoch < current_epoch: if epoch == previous_epoch:
committees_per_epoch = get_previous_epoch_committee_count(state) committees_per_epoch = get_previous_epoch_committee_count(state)
seed = state.previous_epoch_seed seed = state.previous_epoch_seed
shuffling_epoch = state.previous_calculation_epoch shuffling_epoch = state.previous_calculation_epoch
shuffling_start_shard = state.previous_epoch_start_shard shuffling_start_shard = state.previous_epoch_start_shard
else: elif epoch == current_epoch:
committees_per_epoch = get_current_epoch_committee_count(state) committees_per_epoch = get_current_epoch_committee_count(state)
seed = state.current_epoch_seed seed = state.current_epoch_seed
shuffling_epoch = state.current_calculation_epoch shuffling_epoch = state.current_calculation_epoch
shuffling_start_shard = state.current_epoch_start_shard shuffling_start_shard = state.current_epoch_start_shard
elif epoch == next_epoch:
current_committees_per_epoch = get_current_epoch_committee_count(state)
committees_per_epoch = get_next_epoch_committee_count(state)
seed = state.current_epoch_seed
shuffling_epoch = generate_seed(state, next_epoch)
shuffling_start_shard = (state.current_epoch_start_shard + current_committees_per_epoch) % SHARD_COUNT
shuffling = get_shuffling( shuffling = get_shuffling(
seed, seed,
@ -881,7 +901,7 @@ def get_active_index_root(state: BeaconState,
""" """
Returns the index root at a recent ``epoch``. Returns the index root at a recent ``epoch``.
""" """
assert get_current_epoch(state) - LATEST_INDEX_ROOTS_LENGTH < epoch <= get_current_epoch(state) assert get_current_epoch(state) - LATEST_INDEX_ROOTS_LENGTH < epoch <= get_current_epoch(state) + ENTRY_EXIT_DELAY
return state.latest_index_roots[epoch % LATEST_INDEX_ROOTS_LENGTH] return state.latest_index_roots[epoch % LATEST_INDEX_ROOTS_LENGTH]
``` ```
@ -900,6 +920,17 @@ def generate_seed(state: BeaconState,
) )
``` ```
### `get_beacon_proposer_from_committee`
```python
def get_beacon_proposer_index(committee: List[ValidatorIndex],
slot: SlotNumber) -> ValidatorIndex:
"""
Returns the beacon proposer index of the ``committee`` at the ``slot``.
"""
return first_committee[slot % len(committee)]
```
### `get_beacon_proposer_index` ### `get_beacon_proposer_index`
```python ```python
@ -909,7 +940,8 @@ def get_beacon_proposer_index(state: BeaconState,
Returns the beacon proposer index for the ``slot``. Returns the beacon proposer index for the ``slot``.
""" """
first_committee, _ = get_crosslink_committees_at_slot(state, slot)[0] first_committee, _ = get_crosslink_committees_at_slot(state, slot)[0]
return first_committee[slot % len(first_committee)] return get_beacon_proposer_from_committee(first_committee, slot)
``` ```
### `merkle_root` ### `merkle_root`
@ -1458,7 +1490,10 @@ def get_initial_beacon_state(initial_validator_deposits: List[Deposit],
if get_effective_balance(state, validator_index) >= MAX_DEPOSIT_AMOUNT: if get_effective_balance(state, validator_index) >= MAX_DEPOSIT_AMOUNT:
activate_validator(state, validator_index, True) activate_validator(state, validator_index, True)
state.latest_index_roots[GENESIS_EPOCH % LATEST_INDEX_ROOTS_LENGTH] = hash_tree_root(get_active_validator_indices(state, GENESIS_EPOCH)) for epoch in range(GENESIS_EPOCH, GENESIS_EPOCH + ENTRY_EXIT_DELAY):
state.latest_index_roots[epoch % LATEST_INDEX_ROOTS_LENGTH] = hash_tree_root(
get_active_validator_indices(state, epoch)
)
state.current_epoch_seed = generate_seed(state, GENESIS_EPOCH) state.current_epoch_seed = generate_seed(state, GENESIS_EPOCH)
return state return state
@ -1869,7 +1904,7 @@ First, update the following:
* Set `state.previous_calculation_epoch = state.current_calculation_epoch`. * Set `state.previous_calculation_epoch = state.current_calculation_epoch`.
* Set `state.previous_epoch_start_shard = state.current_epoch_start_shard`. * Set `state.previous_epoch_start_shard = state.current_epoch_start_shard`.
* Set `state.previous_epoch_seed = state.current_epoch_seed`. * Set `state.previous_epoch_seed = state.current_epoch_seed`.
* Set `state.latest_index_roots[next_epoch % LATEST_INDEX_ROOTS_LENGTH] = hash_tree_root(get_active_validator_indices(state, next_epoch))`. * Set `state.latest_index_roots[current_epoch + ENTRY_EXIT_DELAY % LATEST_INDEX_ROOTS_LENGTH] = hash_tree_root(get_active_validator_indices(state, current_epoch + ENTRY_EXIT_DELAY))`.
If the following are satisfied: If the following are satisfied:
@ -1932,7 +1967,7 @@ and perform the following updates:
If a validator registry update does _not_ happen do the following: If a validator registry update does _not_ happen do the following:
* Let `epochs_since_last_registry_update = current_epoch - state.validator_registry_update_epoch`. * Let `epochs_since_last_registry_update = current_epoch - state.validator_registry_update_epoch`.
* If `epochs_since_last_registry_update` is an exact power of 2: * If `epochs_since_last_registry_update > 1` and `epochs_since_last_registry_update` is an exact power of 2:
* Set `state.current_calculation_epoch = next_epoch`. * Set `state.current_calculation_epoch = next_epoch`.
* Set `state.current_epoch_seed = generate_seed(state, state.current_calculation_epoch)` * Set `state.current_epoch_seed = generate_seed(state, state.current_calculation_epoch)`
* _Note_ that `state.current_epoch_start_shard` is left unchanged. * _Note_ that `state.current_epoch_start_shard` is left unchanged.

View File

@ -327,6 +327,50 @@ signed_attestation_data = bls_sign(
) )
``` ```
## Responsibility lookahead
It is useful for a validator to have some amount of "lookahead" on the validator's upcoming responsibilities of proposing and attesting dictated by the shuffling and slot.
The beacon chain shufflings are designed to given a minimum of 1 epoch lookahead.
There are three possibilities for the shuffling at the next epoch:
1. The shuffling remains the same (i.e. the validator is in the same shard committee).
2. The shuffling changes due to a "validator registry change".
3. The shuffling changes due to `epochs_since_last_registry_update` being an exact power of 2 greater than 1.
(2) and (3) result in the same validator shuffling but with (potentially) different associated shards for each committee.o
A validator should always plan for each as a possibility unless the validator
can concretely eliminate one or two. Planning for a future shuffling involves noting
at which slot one might have to attest and propose and also which shard
one should begin syncing.
### Shuffling remains the same
Validator remains in the same crosslink committee for the same shard and same slot position (`slot + EPOCH_LENGTH`) and might be called upon as as proposer depending upon the committee position and slot in the next epoch. Validator can safely check using `get_beacon_proposer_index` for the slot in question at the start of the next epoch.
In phase 1, the validator would continue syncing the committee's associated shard in case the shuffling remains the same.
### Shuffling change due to validator registry
A validator registry change occurs when a new block has been finalied and all expected shards have been crosslinked. _This can only occur_ when `epochs_since_last_registry_update > 1`.
A validator can use `get_crosslink_committees_at_slot` for slots in the next epoch to find the expected new crosslink committee in the event of a validator registry change at the end of the current epoch.
In phase 1, if the validator is uncertain as to whether a validator registry change will occur at the end of the current epoch, the validator should opportunistically begin to sync the potential new shard for the next epoch to be prepared in the event of a registry change. Re-checking `get_crosslink_committees_at_slot` at the start of the next epoch will affirm or deny whether the committee did in fact update.
### Shuffling change due to power of 2 since last change
In the event that a validator registry change does not occur at the end of the current epoch and `epochs_since_last_registry_update > 1` and `epochs_since_last_registry_update` is an exact power of two, a reshuffling occurs but the shards remain the same.
In phase 1, if a power of 2 since last registry update is coming up and the validator is uncertain if a registry change will occur, the validator should opportunistically begin to sync the potential new shard for the new shuffling.
To find what the shard to attempt to sync:
* Find the new `committee` using `get_crosslink_committees_at_slot` for slots in the next epoch.
* Let `slot` the be the future slot in which the validator is a committee.
* Let `committee_slot_position` be the position of the committee within the list of committees at that slot.
* Let `shard = get_crosslink_committees_at_slot(state, slot - EPOCH_LENGTH)[committee_slot_position][1]`
Opportunistically sync `shard` during the current epoch. The validator can check `get_crosslink_committees_at_slot` at the start of the next committee to affirm or deny whether the power of 2 committee update did occur.
## How to avoid slashing ## How to avoid slashing
"Slashing" is the burning of some amount of validator funds and immediate ejection from the active validator set. In Phase 0, there are two ways in which funds can be slashed -- [proposal slashing](#proposal-slashing) and [attestation slashing](#casper-slashing). Although being slashed has serious repercussions, it is simple enough to avoid being slashed all together by remaining _consistent_ with respect to the messages you have previously signed. "Slashing" is the burning of some amount of validator funds and immediate ejection from the active validator set. In Phase 0, there are two ways in which funds can be slashed -- [proposal slashing](#proposal-slashing) and [attestation slashing](#casper-slashing). Although being slashed has serious repercussions, it is simple enough to avoid being slashed all together by remaining _consistent_ with respect to the messages you have previously signed.