From b66218a264580e2c54676e4b1305be85973f18fd Mon Sep 17 00:00:00 2001 From: Vitalik Buterin Date: Mon, 7 Jan 2019 18:53:33 -0600 Subject: [PATCH 01/16] Initial commit --- specs/core/0_beacon-chain.md | 185 +++++++++++++++++++---------------- 1 file changed, 100 insertions(+), 85 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 1e7eaccf4..e7794b70c 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -45,7 +45,6 @@ - [`BeaconState`](#beaconstate) - [`ValidatorRecord`](#validatorrecord) - [`CrosslinkRecord`](#crosslinkrecord) - - [`ShardCommittee`](#shardcommittee) - [`DepositRootVote`](#depositrootvote) - [`PendingAttestationRecord`](#pendingattestationrecord) - [`ForkData`](#forkdata) @@ -66,7 +65,10 @@ - [`get_active_validator_indices`](#get_active_validator_indices) - [`shuffle`](#shuffle) - [`split`](#split) + - [`get_committees_per_slot`](#get_committees_per_slot) - [`get_shuffling`](#get_shuffling) + - [`get_prev_epoch_committees_per_slot`](#get_prev_epoch_committees_per_slot) + - [`get_cur_epoch_committees_per_slot`](#get_cur_epoch_committees_per_slot) - [`get_shard_committees_at_slot`](#get_shard_committees_at_slot) - [`get_block_root`](#get_block_root) - [`get_beacon_proposer_index`](#get_beacon_proposer_index) @@ -478,7 +480,10 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted # Randomness and committees 'latest_randao_mixes': ['hash32'], 'latest_vdf_outputs': ['hash32'], - 'shard_committees_at_slots': [[ShardCommittee]], + 'prev_epoch_start_shard': 'uint64', + 'cur_epoch_start_shard': 'uint64', + 'prev_epoch_calculation_slot': 'uint64', + 'cur_epoch_calculation_slot': 'uint64', # Custody challenges 'custody_challenges': [CustodyChallenge], @@ -546,19 +551,6 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted } ``` -#### `ShardCommittee` - -```python -{ - # Shard number - 'shard': 'uint64', - # Validator indices - 'committee': ['uint24'], - # Total validator count (for custody challenges) - 'total_validator_count': 'uint64', -} -``` - #### `DepositRootVote` ```python @@ -854,15 +846,29 @@ def split(values: List[Any], split_count: int) -> List[Any]: ] ``` +#### `get_committees_per_slot` + +```python +def get_committees_per_slot(active_validator_count: int): + return max( + 1, + min( + SHARD_COUNT // EPOCH_LENGTH, + len(active_validator_indices) // EPOCH_LENGTH // TARGET_COMMITTEE_SIZE, + ) + ) +``` + #### `get_shuffling` ```python def get_shuffling(seed: Hash32, validators: List[ValidatorRecord], - crosslinking_start_shard: int, - slot: int) -> List[List[ShardCommittee]]: + slot: int) -> List[List[int]] """ - Shuffles ``validators`` into shard committees using ``seed`` as entropy. + Shuffles ``validators`` into shard committees using ``seed`` as entropy. Returns a list of + ``EPOCH_LENGTH * committees_per_slot`` committees where each committee is itself a list of + validator indices. """ # Normalizes slot to start of epoch boundary @@ -870,59 +876,67 @@ def get_shuffling(seed: Hash32, active_validator_indices = get_active_validator_indices(validators, slot) - committees_per_slot = max( - 1, - min( - SHARD_COUNT // EPOCH_LENGTH, - len(active_validator_indices) // EPOCH_LENGTH // TARGET_COMMITTEE_SIZE, - ) - ) + committees_per_slot = get_committees_per_slot(len(active_validator_indices)) # Shuffle with seed shuffled_active_validator_indices = shuffle(active_validator_indices, seed) - # Split the shuffled list into epoch_length pieces - validators_per_slot = split(shuffled_active_validator_indices, EPOCH_LENGTH) - - output = [] - for slot, slot_indices in enumerate(validators_per_slot): - # Split the shuffled list into committees_per_slot pieces - shard_indices = split(slot_indices, committees_per_slot) - - shard_id_start = crosslinking_start_shard + slot * committees_per_slot - - shard_committees = [ - ShardCommittee( - shard=(shard_id_start + shard_position) % SHARD_COUNT, - committee=indices, - total_validator_count=len(active_validator_indices), - ) - for shard_position, indices in enumerate(shard_indices) - ] - output.append(shard_committees) - - return output + # Split the shuffled list into epoch_length * committees_per_slot pieces + return split(shuffled_active_validator_indices, committees_per_slot * EPOCH_LENGTH) ``` **Invariant**: if `get_shuffling(seed, validators, shard, slot)` returns some value `x`, it should return the same value `x` for the same `seed` and `shard` and possible future modifications of `validators` forever in phase 0, and until the ~1 year deletion delay in phase 2 and in the future. -Here's a diagram of what is going on: +**Note**: this definition and the next few definitions will make heavy use of repetitive computing. Real life implementations are expected to appropriately use caching/memoization to avoid redoing work. -![](http://vitalik.ca/files/ShuffleAndAssign.png?1) +#### `get_prev_epoch_committees_per_slot` + +```python +def get_prev_epoch_committees_per_slot(state: BeaconState): + prev_active_validators = get_active_validator_indices(validators, state.prev_epoch_calculation_slot) + return get_committees_per_slot(len(prev_active_validators)) +``` + +#### `get_cur_epoch_committees_per_slot` + +```python +def get_cur_epoch_committees_per_slot(state: BeaconState): + cur_active_validators = get_active_validator_indices(validators, state.cur_epoch_calculation_slot) + return get_committees_per_slot(len(cur_active_validators)) +``` #### `get_shard_committees_at_slot` ```python def get_shard_committees_at_slot(state: BeaconState, - slot: int) -> List[ShardCommittee]: + slot: int) -> (List[List[int]], int): """ - Returns the ``ShardCommittee`` for the ``slot``. + Returns (i) the list of committees and (ii) the shard associated with the first committee for the ``slot``. """ - earliest_slot_in_array = state.slot - (state.slot % EPOCH_LENGTH) - EPOCH_LENGTH - assert earliest_slot_in_array <= slot < earliest_slot_in_array + EPOCH_LENGTH * 2 - return state.shard_committees_at_slots[slot - earliest_slot_in_array] + earliest_slot = state.slot - (state.slot % EPOCH_LENGTH) - EPOCH_LENGTH + assert earliest_slot <= slot < earliest_slot + EPOCH_LENGTH * 2 + offset = slot % EPOCH_LENGTH + + + if slot < earliest_slot + EPOCH_LENGTH: + committees_per_slot = get_prev_epoch_committees_per_slot(state) + shuffling = get_shuffling(state.latest_randao_mixes[state.prev_epoch_calculation_slot % LATEST_RANDAO_MIXES_LENGTH], + state.validator_registry, + state.slot - (state.slot % EPOCH_LENGTH) - EPOCH_LENGTH) + start_shard = state.prev_epoch_start_shard + else: + committees_per_slot = get_cur_epoch_committees_per_slot(state) + shuffling = get_shuffling(state.latest_randao_mixes[state.cur_epoch_calculation_slot % LATEST_RANDAO_MIXES_LENGTH], + state.validator_registry, + state.slot - (state.slot % EPOCH_LENGTH)) + start_shard = state.cur_epoch_start_shard + + return shuffling[committees_per_slot * offset: committees_per_slot * (offset + 1)], \ + (start_shard + committees_per_slot * offset) % SHARD_COUNT ``` +**Note**: we plan to replace the shuffling algorithm with a pointwise-evaluable shuffle (see https://github.com/ethereum/eth2.0-specs/issues/323), which will allow calculation of the committees for each slot individually. + #### `get_block_root` ```python @@ -946,8 +960,8 @@ def get_beacon_proposer_index(state: BeaconState, """ Returns the beacon proposer index for the ``slot``. """ - first_committee = get_shard_committees_at_slot(state, slot)[0].committee - return first_committee[slot % len(first_committee)] + committees, shard = get_shard_committees_at_slot(state, slot) + return committees[0][slot % len(committees[0])] ``` #### `merkle_root` @@ -974,13 +988,13 @@ def get_attestation_participants(state: BeaconState, """ # Find the relevant committee - shard_committees = get_shard_committees_at_slot(state, attestation_data.slot) - shard_committee = [x for x in shard_committees if x.shard == attestation_data.shard][0] - assert len(participation_bitfield) == ceil_div8(len(shard_committee.committee)) + shard_committees, start_shard = get_shard_committees_at_slot(state, attestation_data.slot) + shard_committee = shard_committee[(attestation_data.shard - start_shard) % SHARD_COUNT] + assert len(participation_bitfield) == ceil_div8(len(shard_committee)) # Find the participating attesters in the committee participants = [] - for i, validator_index in enumerate(shard_committee.committee): + for i, validator_index in enumerate(shard_committee): participation_bit = (participation_bitfield[i//8] >> (7 - (i % 8))) % 2 if participation_bit == 1: participants.append(validator_index) @@ -1165,7 +1179,10 @@ def get_initial_beacon_state(initial_validator_deposits: List[Deposit], # Randomness and committees latest_randao_mixes=[ZERO_HASH for _ in range(LATEST_RANDAO_MIXES_LENGTH)], latest_vdf_outputs=[ZERO_HASH for _ in range(LATEST_RANDAO_MIXES_LENGTH // EPOCH_LENGTH)], - shard_committees_at_slots=[], + prev_epoch_start_shard=0, + cur_epoch_start_shard=0, + prev_epoch_calculation_slot=GENESIS_SLOT, + cur_epoch_calculation_slot=GENESIS_SLOT, # Custody challenges custody_challenges=[], @@ -1205,10 +1222,6 @@ def get_initial_beacon_state(initial_validator_deposits: List[Deposit], if get_effective_balance(state, validator_index) >= MAX_DEPOSIT * GWEI_PER_ETH: activate_validator(state, validator_index, True) - # Set initial committee shuffling - initial_shuffling = get_shuffling(ZERO_HASH, state.validator_registry, 0, GENESIS_SLOT) - state.shard_committees_at_slots = initial_shuffling + initial_shuffling - return state ``` @@ -1554,14 +1567,14 @@ All [validators](#dfn-validator): **Note**: `previous_epoch_boundary_attesting_balance` balance might be marginally different than `current_epoch_boundary_attesting_balance` during the previous epoch transition. Due to the tight bound on validator churn each epoch and small per-epoch rewards/penalties, the potential balance difference is very low and only marginally affects consensus safety. -For every `shard_committee_at_slot` in `state.shard_committees_at_slots` and for every `shard_committee` in `shard_committee_at_slot`: +For every `slot in range(state.slot - 2 * EPOCH_LENGTH, state.slot)`, let `shard_committee_at_slot, start_shard = get_shard_committees_at_slot(slot)`. For every `index in range(len(shard_committee_at_slot))`, let `shard_committee = shard_committee_at_slot[index]`, `shard = (start_shard + index) % SHARD_COUNT`, and compute: -* Let `shard_block_root` be `state.latest_crosslinks[shard_committee.shard].shard_block_root` -* Let `attesting_validator_indices(shard_committee, shard_block_root)` be the union of the [validator](#dfn-validator) index sets given by `[get_attestation_participants(state, a.data, a.participation_bitfield) for a in current_epoch_attestations + previous_epoch_attestations if a.shard == shard_committee.shard and a.shard_block_root == shard_block_root]`. +* Let `shard_block_root` be `state.latest_crosslinks[shard].shard_block_root` +* Let `attesting_validator_indices(shard_committee, shard_block_root)` be the union of the [validator](#dfn-validator) index sets given by `[get_attestation_participants(state, a.data, a.participation_bitfield) for a in current_epoch_attestations + previous_epoch_attestations if a.shard == shard and a.shard_block_root == shard_block_root]`. * Let `winning_root(shard_committee)` be equal to the value of `shard_block_root` such that `sum([get_effective_balance(state, i) for i in attesting_validator_indices(shard_committee, shard_block_root)])` is maximized (ties broken by favoring lower `shard_block_root` values). * Let `attesting_validators(shard_committee)` be equal to `attesting_validator_indices(shard_committee, winning_root(shard_committee))` for convenience. * Let `total_attesting_balance(shard_committee) = sum([get_effective_balance(state, i) for i in attesting_validators(shard_committee)])`. -* Let `total_balance(shard_committee) = sum([get_effective_balance(state, i) for i in shard_committee.committee])`. +* Let `total_balance(shard_committee) = sum([get_effective_balance(state, i) for i in shard_committee])`. * Let `inclusion_slot(state, index) = a.slot_included` for the attestation `a` where `index` is in `get_attestation_participants(state, a.data, a.participation_bitfield)`. * Let `inclusion_distance(state, index) = a.slot_included - a.data.slot` where `a` is the above attestation. @@ -1587,9 +1600,9 @@ Set `state.finalized_slot = state.previous_justified_slot` if any of the followi ### Crosslinks -For every `shard_committee_at_slot` in `state.shard_committees_at_slots` and for every `shard_committee`in `shard_committee_at_slot`: +For every `slot in range(state.slot - 2 * EPOCH_LENGTH, state.slot)`, let `shard_committee_at_slot, start_shard = get_shard_committees_at_slot(slot)`. For every `index in range(len(shard_committee_at_slot))`, let `shard_committee = shard_committee_at_slot[index]`, `shard = (start_shard + index) % SHARD_COUNT`, and compute: -* Set `state.latest_crosslinks[shard_committee.shard] = CrosslinkRecord(slot=state.slot, shard_block_root=winning_root(shard_committee))` if `3 * total_attesting_balance(shard_committee) >= 2 * total_balance(shard_committee)`. +* Set `state.latest_crosslinks[shard] = CrosslinkRecord(slot=state.slot, shard_block_root=winning_root(shard_committee))` if `3 * total_attesting_balance(shard_committee) >= 2 * total_balance(shard_committee)`. ### Rewards and penalties @@ -1633,7 +1646,7 @@ For each `index` in `previous_epoch_attester_indices`, we determine the proposer #### Crosslinks -For every `shard_committee_at_slot` in `state.shard_committees_at_slots[:EPOCH_LENGTH]` (i.e. the objects corresponding to the epoch before the current one), for each `shard_committee` in `shard_committee_at_slot`, and for each `index` in `shard_committee.committee`, adjust balances as follows: +For every `i in range(state.slot - 2 * EPOCH_LENGTH, state.slot - EPOCH_LENGTH)`, let `shard_committee_at_slot, start_shard = get_shard_committees_at_slot(i)`. For every `j in range(len(shard_committee_at_slot))`, let `shard_committee = shard_committee_at_slot[j]`, `shard = (start_shard + j) % SHARD_COUNT`, and compute: * If `index in attesting_validators(shard_committee)`, `state.validator_balances[index] += base_reward(state, index) * total_attesting_balance(shard_committee) // total_balance(shard_committee))`. * If `index not in attesting_validators(shard_committee)`, `state.validator_balances[index] -= base_reward(state, index)`. @@ -1658,7 +1671,7 @@ def process_ejections(state: BeaconState) -> None: If the following are satisfied: * `state.finalized_slot > state.validator_registry_latest_change_slot` -* `state.latest_crosslinks[shard].slot > state.validator_registry_latest_change_slot` for every shard number `shard` in `state.shard_committees_at_slots` +* `state.latest_crosslinks[shard].slot > state.validator_registry_latest_change_slot` for every shard number `shard` in `[(state.cur_epoch_start_shard + i) % SHARD_COUNT for i in range(get_cur_epoch_committees_per_slot(state) * EPOCH_LENGTH)]` (that is, for every shard in the current committees) update the validator registry and associated fields by running @@ -1706,7 +1719,21 @@ def update_validator_registry(state: BeaconState) -> None: state.validator_registry_latest_change_slot = state.slot ``` -Regardless of whether the above conditions are satisfied, run the following: +and perform the following updates: + +* Set `state.prev_epoch_calculation_slot = state.cur_epoch_calculation_slot` +* Set `state.prev_epoch_start_shard = state.cur_epoch_start_shard` +* Set `state.cur_epoch_calculation_slot = state.slot` +* Set `state.cur_epoch_start_shard = (state.cur_epoch_start_shard + get_cur_epoch_committees_per_slot(state) * EPOCH_LENGTH) % SHARD_COUNT` + +If a validator registry update does _not_ happen do the following: + +* Set `state.prev_epoch_calculation_slot = state.cur_epoch_calculation_slot` +* Set `state.prev_epoch_start_shard = state.cur_epoch_start_shard` +* Let `epochs_since_last_registry_change = (state.slot - state.validator_registry_latest_change_slot) // EPOCH_LENGTH`. +* If `epochs_since_last_registry_change` is an exact power of 2, set `state.cur_epoch_calculation_slot = state.slot`. Note that `state.cur_epoch_start_shard` is left unchanged. + +Regardless of whether or not a validator set change happens, run the following: ```python def process_penalties_and_exits(state: BeaconState) -> None: @@ -1744,18 +1771,6 @@ def process_penalties_and_exits(state: BeaconState) -> None: break ``` -Also perform the following updates: - -* Set `state.shard_committees_at_slots[:EPOCH_LENGTH] = state.shard_committees_at_slots[EPOCH_LENGTH:]`. -* Set `state.shard_committees_at_slots[EPOCH_LENGTH:] = get_shuffling(state.latest_randao_mixes[(state.slot - SEED_LOOKAHEAD) % LATEST_RANDAO_MIXES_LENGTH], state.validator_registry, next_start_shard, state.slot)` where `next_start_shard = (state.shard_committees_at_slots[-1][-1].shard + 1) % SHARD_COUNT`. - -If a validator registry update does _not_ happen do the following: - -* Set `state.shard_committees_at_slots[:EPOCH_LENGTH] = state.shard_committees_at_slots[EPOCH_LENGTH:]`. -* Let `epochs_since_last_registry_change = (state.slot - state.validator_registry_latest_change_slot) // EPOCH_LENGTH`. -* Let `start_shard = state.shard_committees_at_slots[0][0].shard`. -* If `epochs_since_last_registry_change` is an exact power of 2, set `state.shard_committees_at_slots[EPOCH_LENGTH:] = get_shuffling(state.latest_randao_mixes[(state.slot - SEED_LOOKAHEAD) % LATEST_RANDAO_MIXES_LENGTH], state.validator_registry, start_shard, state.slot)`. Note that `start_shard` is not changed from the last epoch. - ### Final updates * Let `e = state.slot // EPOCH_LENGTH`. Set `state.latest_penalized_exit_balances[(e+1) % LATEST_PENALIZED_EXIT_LENGTH] = state.latest_penalized_exit_balances[e % LATEST_PENALIZED_EXIT_LENGTH]` From 1daab4659aedf31ab232e89f0cab59fb65feddda Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Wed, 9 Jan 2019 10:40:40 -0600 Subject: [PATCH 02/16] Update specs/core/0_beacon-chain.md Co-Authored-By: vbuterin --- specs/core/0_beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index e7794b70c..0143cde2e 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -887,7 +887,7 @@ def get_shuffling(seed: Hash32, **Invariant**: if `get_shuffling(seed, validators, shard, slot)` returns some value `x`, it should return the same value `x` for the same `seed` and `shard` and possible future modifications of `validators` forever in phase 0, and until the ~1 year deletion delay in phase 2 and in the future. -**Note**: this definition and the next few definitions will make heavy use of repetitive computing. Real life implementations are expected to appropriately use caching/memoization to avoid redoing work. +**Note**: this definition and the next few definitions make heavy use of repetitive computing. Production implementations are expected to appropriately use caching/memoization to avoid redoing work. #### `get_prev_epoch_committees_per_slot` From 8f1325f95ea34764884564f95a408da9113b81ea Mon Sep 17 00:00:00 2001 From: Vitalik Buterin Date: Wed, 9 Jan 2019 10:58:33 -0600 Subject: [PATCH 03/16] Fixed bugs found by Danny --- specs/core/0_beacon-chain.md | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 0143cde2e..c5f2c5bbc 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -484,6 +484,8 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted 'cur_epoch_start_shard': 'uint64', 'prev_epoch_calculation_slot': 'uint64', 'cur_epoch_calculation_slot': 'uint64', + 'prev_epoch_randao_mix': 'hash32', + 'cur_epoch_randao_mix': 'hash32', # Custody challenges 'custody_challenges': [CustodyChallenge], @@ -917,22 +919,23 @@ def get_shard_committees_at_slot(state: BeaconState, assert earliest_slot <= slot < earliest_slot + EPOCH_LENGTH * 2 offset = slot % EPOCH_LENGTH - if slot < earliest_slot + EPOCH_LENGTH: committees_per_slot = get_prev_epoch_committees_per_slot(state) - shuffling = get_shuffling(state.latest_randao_mixes[state.prev_epoch_calculation_slot % LATEST_RANDAO_MIXES_LENGTH], + shuffling = get_shuffling(state.prev_epoch_randao_mix, state.validator_registry, - state.slot - (state.slot % EPOCH_LENGTH) - EPOCH_LENGTH) + state.prev_epoch_calculation_slot) start_shard = state.prev_epoch_start_shard else: committees_per_slot = get_cur_epoch_committees_per_slot(state) - shuffling = get_shuffling(state.latest_randao_mixes[state.cur_epoch_calculation_slot % LATEST_RANDAO_MIXES_LENGTH], + shuffling = get_shuffling(state.cur_epoch_randao_mix, state.validator_registry, - state.slot - (state.slot % EPOCH_LENGTH)) + state.cur_epoch_calculation_slot) start_shard = state.cur_epoch_start_shard - return shuffling[committees_per_slot * offset: committees_per_slot * (offset + 1)], \ + return ( + shuffling[committees_per_slot * offset: committees_per_slot * (offset + 1)], (start_shard + committees_per_slot * offset) % SHARD_COUNT + ) ``` **Note**: we plan to replace the shuffling algorithm with a pointwise-evaluable shuffle (see https://github.com/ethereum/eth2.0-specs/issues/323), which will allow calculation of the committees for each slot individually. @@ -1183,6 +1186,8 @@ def get_initial_beacon_state(initial_validator_deposits: List[Deposit], cur_epoch_start_shard=0, prev_epoch_calculation_slot=GENESIS_SLOT, cur_epoch_calculation_slot=GENESIS_SLOT, + prev_epoch_randao_mix=ZERO_HASH, + cur_epoch_randao_mix=ZERO_HASH, # Custody challenges custody_challenges=[], @@ -1723,15 +1728,17 @@ and perform the following updates: * Set `state.prev_epoch_calculation_slot = state.cur_epoch_calculation_slot` * Set `state.prev_epoch_start_shard = state.cur_epoch_start_shard` +* Set `state.prev_epoch_randao_mix = state.cur_epoch_randao_mix` * Set `state.cur_epoch_calculation_slot = state.slot` * Set `state.cur_epoch_start_shard = (state.cur_epoch_start_shard + get_cur_epoch_committees_per_slot(state) * EPOCH_LENGTH) % SHARD_COUNT` +* Set `state.cur_epoch_randao_mix = state.latest_randao_mixes[(state.cur_epoch_calculation_slot - SEED_LOOKAHEAD) % LATEST_RANDAO_MIXES_LENGTH]` If a validator registry update does _not_ happen do the following: * Set `state.prev_epoch_calculation_slot = state.cur_epoch_calculation_slot` * Set `state.prev_epoch_start_shard = state.cur_epoch_start_shard` * Let `epochs_since_last_registry_change = (state.slot - state.validator_registry_latest_change_slot) // EPOCH_LENGTH`. -* If `epochs_since_last_registry_change` is an exact power of 2, set `state.cur_epoch_calculation_slot = state.slot`. Note that `state.cur_epoch_start_shard` is left unchanged. +* If `epochs_since_last_registry_change` is an exact power of 2, set `state.cur_epoch_calculation_slot = state.slot` and `state.cur_epoch_randao_mix = state.latest_randao_mixes[(state.cur_epoch_calculation_slot - SEED_LOOKAHEAD) % LATEST_RANDAO_MIXES_LENGTH]`. Note that `state.cur_epoch_start_shard` is left unchanged. Regardless of whether or not a validator set change happens, run the following: From 35851b5303e0a37826a6568c7e0ee3b86b2a85b8 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Wed, 9 Jan 2019 10:59:20 -0600 Subject: [PATCH 04/16] Update specs/core/0_beacon-chain.md Co-Authored-By: vbuterin --- specs/core/0_beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index c5f2c5bbc..40b3526b0 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -851,7 +851,7 @@ def split(values: List[Any], split_count: int) -> List[Any]: #### `get_committees_per_slot` ```python -def get_committees_per_slot(active_validator_count: int): +def get_committees_per_slot(active_validator_count: int) -> int: return max( 1, min( From 06c5c11cd5d34a478146db7d316a9788864bb0a8 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Wed, 9 Jan 2019 10:59:31 -0600 Subject: [PATCH 05/16] Update specs/core/0_beacon-chain.md Co-Authored-By: vbuterin --- specs/core/0_beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 40b3526b0..ad88ee49f 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -911,7 +911,7 @@ def get_cur_epoch_committees_per_slot(state: BeaconState): ```python def get_shard_committees_at_slot(state: BeaconState, - slot: int) -> (List[List[int]], int): + slot: int) -> Tuple[List[List[int]], int]: """ Returns (i) the list of committees and (ii) the shard associated with the first committee for the ``slot``. """ From 83d54f6aa4da262b06317f67c1aa9b4f02cce3d2 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Wed, 9 Jan 2019 10:59:45 -0600 Subject: [PATCH 06/16] Update specs/core/0_beacon-chain.md Co-Authored-By: vbuterin --- specs/core/0_beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index ad88ee49f..6ddfb0cca 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -902,7 +902,7 @@ def get_prev_epoch_committees_per_slot(state: BeaconState): #### `get_cur_epoch_committees_per_slot` ```python -def get_cur_epoch_committees_per_slot(state: BeaconState): +def get_cur_epoch_committees_per_slot(state: BeaconState) -> int: cur_active_validators = get_active_validator_indices(validators, state.cur_epoch_calculation_slot) return get_committees_per_slot(len(cur_active_validators)) ``` From 608ec2452c08769aa5239f770da60a5e9bf34ac9 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Wed, 9 Jan 2019 10:59:56 -0600 Subject: [PATCH 07/16] Update specs/core/0_beacon-chain.md Co-Authored-By: vbuterin --- specs/core/0_beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 6ddfb0cca..07c75091d 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1183,7 +1183,7 @@ def get_initial_beacon_state(initial_validator_deposits: List[Deposit], latest_randao_mixes=[ZERO_HASH for _ in range(LATEST_RANDAO_MIXES_LENGTH)], latest_vdf_outputs=[ZERO_HASH for _ in range(LATEST_RANDAO_MIXES_LENGTH // EPOCH_LENGTH)], prev_epoch_start_shard=0, - cur_epoch_start_shard=0, + cur_epoch_start_shard=GENESIS_START_SHARD, prev_epoch_calculation_slot=GENESIS_SLOT, cur_epoch_calculation_slot=GENESIS_SLOT, prev_epoch_randao_mix=ZERO_HASH, From 0b16430cf57ab2116827c63f27f471ff735c63d0 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Wed, 9 Jan 2019 11:00:13 -0600 Subject: [PATCH 08/16] Update specs/core/0_beacon-chain.md Co-Authored-By: vbuterin --- specs/core/0_beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 07c75091d..358dd5924 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -894,7 +894,7 @@ def get_shuffling(seed: Hash32, #### `get_prev_epoch_committees_per_slot` ```python -def get_prev_epoch_committees_per_slot(state: BeaconState): +def get_prev_epoch_committees_per_slot(state: BeaconState) -> int: prev_active_validators = get_active_validator_indices(validators, state.prev_epoch_calculation_slot) return get_committees_per_slot(len(prev_active_validators)) ``` From e2886bf3d3299c7f8c6979a36fadcad03d5a0413 Mon Sep 17 00:00:00 2001 From: Vitalik Buterin Date: Thu, 10 Jan 2019 11:01:19 -0600 Subject: [PATCH 09/16] prev -> previous, cur -> current, get_shard_committee_at_slot rework, get_randao_mix rework --- specs/core/0_beacon-chain.md | 118 ++++++++++++++++++++--------------- 1 file changed, 66 insertions(+), 52 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 358dd5924..a728817c3 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -67,10 +67,11 @@ - [`split`](#split) - [`get_committees_per_slot`](#get_committees_per_slot) - [`get_shuffling`](#get_shuffling) - - [`get_prev_epoch_committees_per_slot`](#get_prev_epoch_committees_per_slot) - - [`get_cur_epoch_committees_per_slot`](#get_cur_epoch_committees_per_slot) + - [`get_previous_epoch_committees_per_slot`](#get_previous_epoch_committees_per_slot) + - [`get_current_epoch_committees_per_slot`](#get_current_epoch_committees_per_slot) - [`get_shard_committees_at_slot`](#get_shard_committees_at_slot) - [`get_block_root`](#get_block_root) + - [`get_randao_mix`](#get_randao_mix) - [`get_beacon_proposer_index`](#get_beacon_proposer_index) - [`merkle_root`](#merkle_root) - [`get_attestation_participants`](#get_attestation_participants) @@ -480,12 +481,12 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted # Randomness and committees 'latest_randao_mixes': ['hash32'], 'latest_vdf_outputs': ['hash32'], - 'prev_epoch_start_shard': 'uint64', - 'cur_epoch_start_shard': 'uint64', - 'prev_epoch_calculation_slot': 'uint64', - 'cur_epoch_calculation_slot': 'uint64', - 'prev_epoch_randao_mix': 'hash32', - 'cur_epoch_randao_mix': 'hash32', + 'previous_epoch_start_shard': 'uint64', + 'current_epoch_start_shard': 'uint64', + 'previous_epoch_calculation_slot': 'uint64', + 'current_epoch_calculation_slot': 'uint64', + 'previous_epoch_randao_mix': 'hash32', + 'current_epoch_randao_mix': 'hash32', # Custody challenges 'custody_challenges': [CustodyChallenge], @@ -891,27 +892,27 @@ def get_shuffling(seed: Hash32, **Note**: this definition and the next few definitions make heavy use of repetitive computing. Production implementations are expected to appropriately use caching/memoization to avoid redoing work. -#### `get_prev_epoch_committees_per_slot` +#### `get_previous_epoch_committees_per_slot` ```python -def get_prev_epoch_committees_per_slot(state: BeaconState) -> int: - prev_active_validators = get_active_validator_indices(validators, state.prev_epoch_calculation_slot) - return get_committees_per_slot(len(prev_active_validators)) +def get_previous_epoch_committees_per_slot(state: BeaconState) -> int: + previous_active_validators = get_active_validator_indices(validators, state.previous_epoch_calculation_slot) + return get_committees_per_slot(len(previous_active_validators)) ``` -#### `get_cur_epoch_committees_per_slot` +#### `get_current_epoch_committees_per_slot` ```python -def get_cur_epoch_committees_per_slot(state: BeaconState) -> int: - cur_active_validators = get_active_validator_indices(validators, state.cur_epoch_calculation_slot) - return get_committees_per_slot(len(cur_active_validators)) +def get_current_epoch_committees_per_slot(state: BeaconState) -> int: + current_active_validators = get_active_validator_indices(validators, state.current_epoch_calculation_slot) + return get_committees_per_slot(len(current_active_validators)) ``` #### `get_shard_committees_at_slot` ```python def get_shard_committees_at_slot(state: BeaconState, - slot: int) -> Tuple[List[List[int]], int]: + slot: int) -> List[Tuple[List[int], int]]: """ Returns (i) the list of committees and (ii) the shard associated with the first committee for the ``slot``. """ @@ -920,22 +921,22 @@ def get_shard_committees_at_slot(state: BeaconState, offset = slot % EPOCH_LENGTH if slot < earliest_slot + EPOCH_LENGTH: - committees_per_slot = get_prev_epoch_committees_per_slot(state) - shuffling = get_shuffling(state.prev_epoch_randao_mix, + committees_per_slot = get_previous_epoch_committees_per_slot(state) + shuffling = get_shuffling(state.previous_epoch_randao_mix, state.validator_registry, - state.prev_epoch_calculation_slot) - start_shard = state.prev_epoch_start_shard + state.previous_epoch_calculation_slot) + slot_start_shard = (state.previous_epoch_start_shard + committees_per_slot * offset) % SHARD_COUNT else: - committees_per_slot = get_cur_epoch_committees_per_slot(state) - shuffling = get_shuffling(state.cur_epoch_randao_mix, + committees_per_slot = get_current_epoch_committees_per_slot(state) + shuffling = get_shuffling(state.current_epoch_randao_mix, state.validator_registry, - state.cur_epoch_calculation_slot) - start_shard = state.cur_epoch_start_shard + state.current_epoch_calculation_slot) + slot_start_shard = (state.current_epoch_start_shard + committees_per_slot * offset) % SHARD_COUNT - return ( - shuffling[committees_per_slot * offset: committees_per_slot * (offset + 1)], - (start_shard + committees_per_slot * offset) % SHARD_COUNT - ) + return [ + (shuffling[committees_per_slot * offset + i], (slot_start_shard + i) % SHARD_COUNT) + for i in range(committees_per_slot) + ] ``` **Note**: we plan to replace the shuffling algorithm with a pointwise-evaluable shuffle (see https://github.com/ethereum/eth2.0-specs/issues/323), which will allow calculation of the committees for each slot individually. @@ -955,6 +956,19 @@ def get_block_root(state: BeaconState, `get_block_root(_, s)` should always return `hash_tree_root` of the block in the beacon chain at slot `s`, and `get_shard_committees_at_slot(_, s)` should not change unless the [validator](#dfn-validator) registry changes. +#### `get_randao_mix` + +```python +def get_randao_mix(state: BeaconState, + slot: int) -> Hash32: + """ + Returns the randao mix at a recent ``slot``. + """ + assert state.slot <= slot + LATEST_RANDAO_MIXES_LENGTH + assert slot < state.slot + return state.latest_block_roots[slot % LATEST_RANDAO_MIXES_LENGTH] +``` + #### `get_beacon_proposer_index` ```python @@ -963,8 +977,8 @@ def get_beacon_proposer_index(state: BeaconState, """ Returns the beacon proposer index for the ``slot``. """ - committees, shard = get_shard_committees_at_slot(state, slot) - return committees[0][slot % len(committees[0])] + first_committee, _ = get_shard_committees_at_slot(state, slot)[0] + return first_committee[slot % len(first_committee)] ``` #### `merkle_root` @@ -990,9 +1004,9 @@ def get_attestation_participants(state: BeaconState, Returns the participant indices at for the ``attestation_data`` and ``participation_bitfield``. """ - # Find the relevant committee - shard_committees, start_shard = get_shard_committees_at_slot(state, attestation_data.slot) - shard_committee = shard_committee[(attestation_data.shard - start_shard) % SHARD_COUNT] + # Find the committee in the list with the desired shard + shard_committees = get_shard_committees_at_slot(state, attestation_data.slot) + shard_committee = [committee for committee, shard in shard_committees if shard == attestation_data.shard][0] assert len(participation_bitfield) == ceil_div8(len(shard_committee)) # Find the participating attesters in the committee @@ -1182,12 +1196,12 @@ def get_initial_beacon_state(initial_validator_deposits: List[Deposit], # Randomness and committees latest_randao_mixes=[ZERO_HASH for _ in range(LATEST_RANDAO_MIXES_LENGTH)], latest_vdf_outputs=[ZERO_HASH for _ in range(LATEST_RANDAO_MIXES_LENGTH // EPOCH_LENGTH)], - prev_epoch_start_shard=0, - cur_epoch_start_shard=GENESIS_START_SHARD, - prev_epoch_calculation_slot=GENESIS_SLOT, - cur_epoch_calculation_slot=GENESIS_SLOT, - prev_epoch_randao_mix=ZERO_HASH, - cur_epoch_randao_mix=ZERO_HASH, + previous_epoch_start_shard=0, + current_epoch_start_shard=GENESIS_START_SHARD, + previous_epoch_calculation_slot=GENESIS_SLOT, + current_epoch_calculation_slot=GENESIS_SLOT, + previous_epoch_randao_mix=ZERO_HASH, + current_epoch_randao_mix=ZERO_HASH, # Custody challenges custody_challenges=[], @@ -1572,7 +1586,7 @@ All [validators](#dfn-validator): **Note**: `previous_epoch_boundary_attesting_balance` balance might be marginally different than `current_epoch_boundary_attesting_balance` during the previous epoch transition. Due to the tight bound on validator churn each epoch and small per-epoch rewards/penalties, the potential balance difference is very low and only marginally affects consensus safety. -For every `slot in range(state.slot - 2 * EPOCH_LENGTH, state.slot)`, let `shard_committee_at_slot, start_shard = get_shard_committees_at_slot(slot)`. For every `index in range(len(shard_committee_at_slot))`, let `shard_committee = shard_committee_at_slot[index]`, `shard = (start_shard + index) % SHARD_COUNT`, and compute: +For every `slot in range(state.slot - 2 * EPOCH_LENGTH, state.slot)`, let `shard_committee_at_slot = get_shard_committees_at_slot(slot)`. For every `(shard_committee, shard)` in `shard_committee_at_slot`, compute: * Let `shard_block_root` be `state.latest_crosslinks[shard].shard_block_root` * Let `attesting_validator_indices(shard_committee, shard_block_root)` be the union of the [validator](#dfn-validator) index sets given by `[get_attestation_participants(state, a.data, a.participation_bitfield) for a in current_epoch_attestations + previous_epoch_attestations if a.shard == shard and a.shard_block_root == shard_block_root]`. @@ -1605,7 +1619,7 @@ Set `state.finalized_slot = state.previous_justified_slot` if any of the followi ### Crosslinks -For every `slot in range(state.slot - 2 * EPOCH_LENGTH, state.slot)`, let `shard_committee_at_slot, start_shard = get_shard_committees_at_slot(slot)`. For every `index in range(len(shard_committee_at_slot))`, let `shard_committee = shard_committee_at_slot[index]`, `shard = (start_shard + index) % SHARD_COUNT`, and compute: +For every `slot in range(state.slot - 2 * EPOCH_LENGTH, state.slot)`, let `shard_committee_at_slot = get_shard_committees_at_slot(slot)`. For every `(shard_committee, shard)` in `shard_committee_at_slot`, compute: * Set `state.latest_crosslinks[shard] = CrosslinkRecord(slot=state.slot, shard_block_root=winning_root(shard_committee))` if `3 * total_attesting_balance(shard_committee) >= 2 * total_balance(shard_committee)`. @@ -1676,7 +1690,7 @@ def process_ejections(state: BeaconState) -> None: If the following are satisfied: * `state.finalized_slot > state.validator_registry_latest_change_slot` -* `state.latest_crosslinks[shard].slot > state.validator_registry_latest_change_slot` for every shard number `shard` in `[(state.cur_epoch_start_shard + i) % SHARD_COUNT for i in range(get_cur_epoch_committees_per_slot(state) * EPOCH_LENGTH)]` (that is, for every shard in the current committees) +* `state.latest_crosslinks[shard].slot > state.validator_registry_latest_change_slot` for every shard number `shard` in `[(state.current_epoch_start_shard + i) % SHARD_COUNT for i in range(get_current_epoch_committees_per_slot(state) * EPOCH_LENGTH)]` (that is, for every shard in the current committees) update the validator registry and associated fields by running @@ -1726,19 +1740,19 @@ def update_validator_registry(state: BeaconState) -> None: and perform the following updates: -* Set `state.prev_epoch_calculation_slot = state.cur_epoch_calculation_slot` -* Set `state.prev_epoch_start_shard = state.cur_epoch_start_shard` -* Set `state.prev_epoch_randao_mix = state.cur_epoch_randao_mix` -* Set `state.cur_epoch_calculation_slot = state.slot` -* Set `state.cur_epoch_start_shard = (state.cur_epoch_start_shard + get_cur_epoch_committees_per_slot(state) * EPOCH_LENGTH) % SHARD_COUNT` -* Set `state.cur_epoch_randao_mix = state.latest_randao_mixes[(state.cur_epoch_calculation_slot - SEED_LOOKAHEAD) % LATEST_RANDAO_MIXES_LENGTH]` +* Set `state.previous_epoch_calculation_slot = state.current_epoch_calculation_slot` +* Set `state.previous_epoch_start_shard = state.current_epoch_start_shard` +* Set `state.previous_epoch_randao_mix = state.current_epoch_randao_mix` +* Set `state.current_epoch_calculation_slot = state.slot` +* Set `state.current_epoch_start_shard = (state.current_epoch_start_shard + get_current_epoch_committees_per_slot(state) * EPOCH_LENGTH) % SHARD_COUNT` +* Set `state.current_epoch_randao_mix = get_randao_mix(state, state.current_epoch_calculation_slot - SEED_LOOKAHEAD)` If a validator registry update does _not_ happen do the following: -* Set `state.prev_epoch_calculation_slot = state.cur_epoch_calculation_slot` -* Set `state.prev_epoch_start_shard = state.cur_epoch_start_shard` +* Set `state.previous_epoch_calculation_slot = state.current_epoch_calculation_slot` +* Set `state.previous_epoch_start_shard = state.current_epoch_start_shard` * Let `epochs_since_last_registry_change = (state.slot - state.validator_registry_latest_change_slot) // EPOCH_LENGTH`. -* If `epochs_since_last_registry_change` is an exact power of 2, set `state.cur_epoch_calculation_slot = state.slot` and `state.cur_epoch_randao_mix = state.latest_randao_mixes[(state.cur_epoch_calculation_slot - SEED_LOOKAHEAD) % LATEST_RANDAO_MIXES_LENGTH]`. Note that `state.cur_epoch_start_shard` is left unchanged. +* If `epochs_since_last_registry_change` is an exact power of 2, set `state.current_epoch_calculation_slot = state.slot` and `state.current_epoch_randao_mix = state.latest_randao_mixes[(state.current_epoch_calculation_slot - SEED_LOOKAHEAD) % LATEST_RANDAO_MIXES_LENGTH]`. Note that `state.current_epoch_start_shard` is left unchanged. Regardless of whether or not a validator set change happens, run the following: From a0a96c7e7c3487a41a3f20e62bce1575a423c171 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Thu, 10 Jan 2019 21:00:59 -0600 Subject: [PATCH 10/16] Update specs/core/0_beacon-chain.md Co-Authored-By: vbuterin --- specs/core/0_beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 69031dc86..48e7e688a 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -905,7 +905,7 @@ def get_previous_epoch_committees_per_slot(state: BeaconState) -> int: #### `get_current_epoch_committees_per_slot` ```python -def get_current_epoch_committees_per_slot(state: BeaconState) -> int: +def get_current_epoch_committee_count_per_slot(state: BeaconState) -> int: current_active_validators = get_active_validator_indices(validators, state.current_epoch_calculation_slot) return get_committees_per_slot(len(current_active_validators)) ``` From 648c35dc3d7aa9e8c97e256a8bf54c9d65fd1501 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Thu, 10 Jan 2019 21:01:05 -0600 Subject: [PATCH 11/16] Update specs/core/0_beacon-chain.md Co-Authored-By: vbuterin --- specs/core/0_beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 48e7e688a..29c0a4793 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -897,7 +897,7 @@ def get_shuffling(seed: Hash32, #### `get_previous_epoch_committees_per_slot` ```python -def get_previous_epoch_committees_per_slot(state: BeaconState) -> int: +def get_previous_epoch_committee_count_per_slot(state: BeaconState) -> int: previous_active_validators = get_active_validator_indices(validators, state.previous_epoch_calculation_slot) return get_committees_per_slot(len(previous_active_validators)) ``` From 7736843917fc7a496b54c8a9af151f80705bf93c Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Thu, 10 Jan 2019 21:01:30 -0600 Subject: [PATCH 12/16] Update specs/core/0_beacon-chain.md Co-Authored-By: vbuterin --- specs/core/0_beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 29c0a4793..090567886 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -916,7 +916,7 @@ def get_current_epoch_committee_count_per_slot(state: BeaconState) -> int: def get_shard_committees_at_slot(state: BeaconState, slot: int) -> List[Tuple[List[int], int]]: """ - Returns (i) the list of committees and (ii) the shard associated with the first committee for the ``slot``. + Returns the list of ``(committee, shard)`` tuples for the ``slot``. """ earliest_slot = state.slot - (state.slot % EPOCH_LENGTH) - EPOCH_LENGTH assert earliest_slot <= slot < earliest_slot + EPOCH_LENGTH * 2 From eec8b4ac44fce85a4faa35ff675640e933f49536 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Thu, 10 Jan 2019 21:02:51 -0600 Subject: [PATCH 13/16] Update specs/core/0_beacon-chain.md Co-Authored-By: vbuterin --- specs/core/0_beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 090567886..dabafcda8 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -853,7 +853,7 @@ def split(values: List[Any], split_count: int) -> List[Any]: #### `get_committees_per_slot` ```python -def get_committees_per_slot(active_validator_count: int) -> int: +def get_committee_count_per_slot(active_validator_count: int) -> int: return max( 1, min( From 70c0cc43c52ae6077b9239a3c4f8f30fa95c9af9 Mon Sep 17 00:00:00 2001 From: vbuterin Date: Thu, 10 Jan 2019 22:33:22 -0600 Subject: [PATCH 14/16] Fixes as per Danny and Terence --- specs/core/0_beacon-chain.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index dabafcda8..b399eac16 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -858,7 +858,7 @@ def get_committee_count_per_slot(active_validator_count: int) -> int: 1, min( SHARD_COUNT // EPOCH_LENGTH, - len(active_validator_indices) // EPOCH_LENGTH // TARGET_COMMITTEE_SIZE, + active_validator_count // EPOCH_LENGTH // TARGET_COMMITTEE_SIZE, ) ) ``` @@ -883,7 +883,7 @@ def get_shuffling(seed: Hash32, committees_per_slot = get_committees_per_slot(len(active_validator_indices)) # Shuffle - seed = xor(randao_mix, bytes32(slot)) + seed = xor(seed, bytes32(slot)) shuffled_active_validator_indices = shuffle(active_validator_indices, seed) # Split the shuffled list into epoch_length * committees_per_slot pieces @@ -898,7 +898,7 @@ def get_shuffling(seed: Hash32, ```python def get_previous_epoch_committee_count_per_slot(state: BeaconState) -> int: - previous_active_validators = get_active_validator_indices(validators, state.previous_epoch_calculation_slot) + previous_active_validators = get_active_validator_indices(state.validator_registry, state.previous_epoch_calculation_slot) return get_committees_per_slot(len(previous_active_validators)) ``` @@ -1008,7 +1008,10 @@ def get_attestation_participants(state: BeaconState, # Find the committee in the list with the desired shard shard_committees = get_shard_committees_at_slot(state, attestation_data.slot) + + assert attestation.shard in [shard for _, shard in shard_committees] shard_committee = [committee for committee, shard in shard_committees if shard == attestation_data.shard][0] + assert len(participation_bitfield) == ceil_div8(len(shard_committee)) # Find the participating attesters in the committee From 459734cb9eb17da49da515592c7441205d79d5e3 Mon Sep 17 00:00:00 2001 From: vbuterin Date: Thu, 10 Jan 2019 22:34:13 -0600 Subject: [PATCH 15/16] get_randao_mix slot boundary fix --- specs/core/0_beacon-chain.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index b399eac16..06a47b052 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -966,8 +966,8 @@ def get_randao_mix(state: BeaconState, """ Returns the randao mix at a recent ``slot``. """ - assert state.slot <= slot + LATEST_RANDAO_MIXES_LENGTH - assert slot < state.slot + assert state.slot < slot + LATEST_RANDAO_MIXES_LENGTH + assert slot <= state.slot return state.latest_block_roots[slot % LATEST_RANDAO_MIXES_LENGTH] ``` From 2b66811a04f261051c197e5379190dd6286c0476 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 11 Jan 2019 11:35:18 -0600 Subject: [PATCH 16/16] address terence pr feedback --- specs/core/0_beacon-chain.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index cb4bcc9c2..4a47ec644 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -969,7 +969,7 @@ def get_randao_mix(state: BeaconState, """ assert state.slot < slot + LATEST_RANDAO_MIXES_LENGTH assert slot <= state.slot - return state.latest_block_roots[slot % LATEST_RANDAO_MIXES_LENGTH] + return state.latest_randao_mixes[slot % LATEST_RANDAO_MIXES_LENGTH] ``` #### `get_beacon_proposer_index` @@ -1202,7 +1202,7 @@ def get_initial_beacon_state(initial_validator_deposits: List[Deposit], # Randomness and committees latest_randao_mixes=[ZERO_HASH for _ in range(LATEST_RANDAO_MIXES_LENGTH)], latest_vdf_outputs=[ZERO_HASH for _ in range(LATEST_RANDAO_MIXES_LENGTH // EPOCH_LENGTH)], - previous_epoch_start_shard=0, + previous_epoch_start_shard=GENESIS_START_SHARD, current_epoch_start_shard=GENESIS_START_SHARD, previous_epoch_calculation_slot=GENESIS_SLOT, current_epoch_calculation_slot=GENESIS_SLOT,