cleanup shard reassignment logic

This commit is contained in:
Danny Ryan 2018-11-05 13:38:25 +01:00
parent 0df4141f05
commit cc910d831a
No known key found for this signature in database
GPG Key ID: 2765A792E42CE07A
1 changed files with 34 additions and 21 deletions

View File

@ -208,7 +208,7 @@ The `CrystallizedState` has the following fields:
'shard_and_committee_for_slots': [[ShardAndCommittee]],
# Persistent shard committees
'persistent_committees': [['uint24']],
'shard_reassignment_records': [ShardReassignmentRecord],
'persistent_shard_reassignments': [ShardReassignmentRecord],
# 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)
@ -273,7 +273,7 @@ A `ShardReassignmentRecord` object has the following fields:
```python
{
# Which validator to reassign
'validator_id': 'uint64',
'validator_index': 'uint64',
# To which shard
'shard': 'uint16',
# When
@ -478,6 +478,8 @@ def get_block_hash(active_state: ActiveState,
`get_block_hash(_, _, s)` should always return the block in the beacon chain at slot `s`, and `get_shards_and_committees_for_slot(_, s)` should not change unless the validator set changes.
We define another set of helpers to be used throughout: `bytes1(x): return x.to_bytes(1, 'big')`, `bytes2(x): return x.to_bytes(2, 'big')`, and so on for all integers, particularly 1, 2, 3, 4, 8, 32.
We define a function to "add a link" to the validator hash chain, used when a validator is added or removed:
```python
@ -490,8 +492,6 @@ def add_validator_set_change_record(crystallized_state: CrystallizedState,
bytes1(flag) + bytes3(index) + bytes32(pubkey))
```
We define another set of helpers: `bytes1(x): return x.to_bytes(1, 'big')`, `bytes2(x): return x.to_bytes(2, 'big')`, and so on for all integers, particularly 1, 2, 3, 4, 8, 32.
Finally, we abstractly define `int_sqrt(n)` for use in reward/penalty calculations as the largest integer `k` such that `k**2 <= n`. Here is one possible implementation, though clients are free to use their own including standard libraries for [integer square root](https://en.wikipedia.org/wiki/Integer_square_root) if available and meet the specification.
```python
@ -803,38 +803,51 @@ def change_validators(validators: List[ValidatorRecord]) -> None:
# STUB: withdraw to shard chain
```
#### Finally...
* 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`
* 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:]`
* 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...
* Remove all attestation records older than slot `crystallized_state.last_state_recalculation_slot`
* Set `crystallized_state.validator_set_change_slot = crystallized_state.last_state_recalculation_slot`
* 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`
* Empty the `active_state.pending_specials` list
* Set `active_state.recent_block_hashes = active_state.recent_block_hashes[CYCLE_LENGTH:]`
* If a validator set change did _not_ occur during this state recalculation, 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 `persistent_committees` and `next_persistent_committees` objects.
* If the validator was added with index `validator_index`, let `assigned_shard = hash(active_state.randao_mix + bytes8(validator_index)) % SHARD_COUNT`. Add `validator_index` to the end of `next_persistent_committees[assigned_shard]`.
* If the validator was removed, remove their index from the `persistent_committees` and remove any `ShardReassignmentRecord`s containing their index from `persistent_shard_reassignments`.
* If the validator was added with index `validator_index`:
* let `assigned_shard = hash(active_state.randao_mix + bytes8(validator_index)) % SHARD_COUNT`
* let `reassignment_record = ShardReassignmentRecord(validator_index=validator_index, shard=assigned_shard, slot=block.slot + SHARD_PERSISTENT_COMMITTEE_CHANGE_PERIOD)`
* Append `reassignment_record` to the end of `persistent_shard_reassignments`
Now run the following code to reshuffle a few proposers:
```python
active_validator_indices = get_active_validator_indices(validators)
for i in range(len(active_validator_indices) // SHARD_PERSISTENT_COMMITTEE_CHANGE_PERIOD):
num_validators_to_reshuffle = len(active_validator_indices) // SHARD_PERSISTENT_COMMITTEE_CHANGE_PERIOD
for i in range(num_validators_to_reshuffle):
vid = active_validator_indices[hash(active_state.randao_mix + bytes8(i * 2)) % len(active_validator_indices)]
new_shard = hash(active_state.randao_mix + bytes8(i * 2 + 1)) % SHARD_COUNT
crystallized_state.persistent_shard_reassignments.append(ShardReassignmentRecord(validator_id=vid, shard=new_shard, slot=block.slot + SHARD_PERSISTENT_COMMITTEE_CHANGE_PERIOD))
shard_reassignment_record = ShardReassignmentRecord(
validator_index=vid,
shard=new_shard,
slot=block.slot + SHARD_PERSISTENT_COMMITTEE_CHANGE_PERIOD
)
crystallized_state.persistent_shard_reassignments.append(shard_reassignment_record)
while len(crystallized_state.persistent_shard_reassignments) > 0 and crystallized_state.persistent_shard_reassignments[0].slot <= block.slot:
rec = crystallized_state.persistent_shard_reassignments[0]
for c in crystallized_state.persistent_committees:
if rec.validator_id in c:
c.pop(c.index(rec.validator_id))
rec = crystallized_state.persistent_shard_reassignments.pop(0)
for committee in crystallized_state.persistent_committees:
if rec.validator_index in committee:
committee.pop(
committee.index(rec.validator_index)
)
crystallized_state.persistent_committees[rec.shard].append(vid)
```