From b4b60ae16ac6a8278d2a1ebca6d8e59c7f696b55 Mon Sep 17 00:00:00 2001 From: Vitalik Buterin Date: Thu, 18 Oct 2018 13:54:57 -0400 Subject: [PATCH] Assign validators to persistent committees for shard block production --- specs/beacon-chain.md | 43 +++++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/specs/beacon-chain.md b/specs/beacon-chain.md index c22b71a24..111966c9b 100644 --- a/specs/beacon-chain.md +++ b/specs/beacon-chain.md @@ -42,6 +42,7 @@ The primary source of load on the beacon chain are "attestations". Attestations | `RANDAO_SLOTS_PER_LAYER` | 2**12 (= 4096) | slots | ~18 hours | | `SQRT_E_DROP_TIME` | 2**16 (= 65,536) | slots | ~12 days | | `WITHDRAWAL_PERIOD` | 2**19 (= 524,288) | slots | ~97 days | +| `SHARD_PERSISTENT_COMMITTEE_CHANGE_PERIOD` | 2**16 (= 65,536) | slots | ~12 days | | `BASE_REWARD_QUOTIENT` | 2**15 (= 32,768) | — | | `MAX_VALIDATOR_CHURN_QUOTIENT` | 2**5 (= 32) | — | | `LOGOUT_MESSAGE` | `"LOGOUT"` | — | @@ -205,6 +206,9 @@ The `CrystallizedState` has the following fields: 'justified_streak': 'uint64', # Committee members and their assigned shard, per slot 'shard_and_committee_for_slots': [[ShardAndCommittee]], + # Persistent shard committees + 'current_persistent_committees': [['uint24']], + 'next_persistent_committees': [['uint24']], # Total deposits penalized in the given withdrawal period 'deposits_penalized_in_period': ['uint32'], # Hash chain of validator set changes (for light clients to easily track deltas) @@ -442,6 +446,15 @@ Here's a diagram of what's going on: ![](http://vitalik.ca/files/ShuffleAndAssign.png?1) +We also make a function for generating persistent committees: + +```python +def get_persistent_shuffling(validators: List[ValidatorRecord], seed: Hash32): + active_validators = get_active_validator_indices(validators) + shuffled_active_validator_indices = shuffle(active_validators, seed) + return split(shuffled_active_validator_indices, SHARD_COUNT) +``` + We also define two functions for retrieving data from the state: ```python @@ -716,15 +729,6 @@ For each `SpecialRecord` `obj` in `active_state.pending_specials`: * **[covers `NO_DBL_VOTE`, `NO_SURROUND`, `NO_DBL_PROPOSE` slashing conditions]:** If `obj.kind == CASPER_SLASHING`, interpret `data[0]` as a list of concatenated `uint32` values where each value represents an index into `validators`, `data[1]` as the data being signed and `data[2]` as an aggregate signature. Interpret `data[3:6]` similarly. Verify that both signatures are valid, that the two signatures are signing distinct data, and that they are either signing the same slot number, or that one surrounds the other (ie. `source1 < source2 < target2 < target1`). Let `indices` be the list of indices in both signatures; verify that its length is at least 1. For each validator index `v` in `indices`, if its `status` does not equal `PENALIZED`, then run `exit_validator(v, crystallized_state, penalize=True, current_slot=block.slot)` * **[covers RANDAO updates]**: If `obj.kind == RANDAO_REVEAL`, interpret `data[0]` as an integer and `data[1]` as a hash32. Set `validators[data[0]].randao_commitment = data[1]`. -#### Finally... - -* For any validator with index `v` with balance less than `MIN_ONLINE_DEPOSIT_SIZE` and status `ACTIVE`, run `exit_validator(v, crystallized_state, penalize=False, current_slot=block.slot)` -* Set `crystallized_state.last_state_recalculation_slot += CYCLE_LENGTH` -* Remove all attestation records older than slot `crystallized_state.last_state_recalculation_slot` -* Empty the `active_state.pending_specials` list -* Set `active_state.recent_block_hashes = active_state.recent_block_hashes[CYCLE_LENGTH:]` -* Set `shard_and_committee_for_slots[:CYCLE_LENGTH] = shard_and_committee_for_slots[CYCLE_LENGTH:]` - ### Validator set change A validator set change can happen after a state recalculation if all of the following criteria are satisfied: @@ -791,13 +795,32 @@ def change_validators(validators: List[ValidatorRecord]) -> None: # STUB: withdraw to shard chain ``` -Finally: +Then: * Set `crystallized_state.validator_set_change_slot = crystallized_state.last_state_recalculation_slot` * For all `c` in `crystallized_state.crosslinks`, set `c.recently_changed = False` * Let `next_start_shard = (shard_and_committee_for_slots[-1][-1].shard + 1) % SHARD_COUNT` * Set `shard_and_committee_for_slots[CYCLE_LENGTH:] = get_new_shuffling(active_state.randao_mix, validators, next_start_shard)` +#### Finally... + +* For any validator with index `v` with balance less than `MIN_ONLINE_DEPOSIT_SIZE` and status `ACTIVE`, run `exit_validator(v, crystallized_state, penalize=False, current_slot=block.slot)` +* Set `crystallized_state.last_state_recalculation_slot += CYCLE_LENGTH` +* Remove all attestation records older than slot `crystallized_state.last_state_recalculation_slot` +* Empty the `active_state.pending_specials` list +* Set `active_state.recent_block_hashes = active_state.recent_block_hashes[CYCLE_LENGTH:]` +* Set `shard_and_committee_for_slots[:CYCLE_LENGTH] = shard_and_committee_for_slots[CYCLE_LENGTH:]` + +For any validator that was added or removed from the active validator list during this state recalculation: + +* If the validator was removed, remove their index from the `current_persistent_committees` and `next_persistent_committees` objects. +* If the validator was added with index `validator_index`, let `assigned_shard = hash(crystallized_state.randao_mix + bytes8(validator_index)) % SHARD_COUNT`. Add `validator_index` to the end of `next_persistent_committees[assigned_shard]`. + +If `block.slot % SHARD_PERSISTENT_COMMITTEE_CHANGE_PERIOD == 0`, then: + +* Set `current_persistent_committees = next_persistent_committees` +* Set `next_persistent_committees = get_persistent_shuffling(validators, crystallized_state.randao_mix)` + ### TODO Note: This spec is ~60% complete.