From 9e75a76fc1f1bbc820269e61441e83ccda471423 Mon Sep 17 00:00:00 2001 From: vbuterin Date: Fri, 18 Jan 2019 21:06:21 -0600 Subject: [PATCH 01/11] Implement #459 Contents: * Peg entries and exits to epoch boundaries * Add a store of historical active index roots * Mix it into the randomness * Remove the delta hash chain Note that the actual light client implementation is beyond the scope of the spec. [Note to reviewers: verify that the invariant added in the PR is correct] Question: * Do we want to also only store epoch-boundary randao values? I don't think we use the epoch-intermediate ones anywhere..... --- specs/core/0_beacon-chain.md | 91 ++++++++++++++---------------------- 1 file changed, 35 insertions(+), 56 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 5640340b6..05d138649 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -18,7 +18,6 @@ - [Reward and penalty quotients](#reward-and-penalty-quotients) - [Status flags](#status-flags) - [Max operations per block](#max-operations-per-block) - - [Validator registry delta flags](#validator-registry-delta-flags) - [Signature domains](#signature-domains) - [Data structures](#data-structures) - [Beacon chain operations](#beacon-chain-operations) @@ -47,7 +46,6 @@ - [`Crosslink`](#crosslink) - [`PendingAttestation`](#pendingattestation) - [`Fork`](#fork) - - [`ValidatorRegistryDeltaBlock`](#validatorregistrydeltablock) - [`Eth1Data`](#eth1data) - [`Eth1DataVote`](#eth1datavote) - [Ethereum 1.0 deposit contract](#ethereum-10-deposit-contract) @@ -73,6 +71,7 @@ - [`get_crosslink_committees_at_slot`](#get_crosslink_committees_at_slot) - [`get_block_root`](#get_block_root) - [`get_randao_mix`](#get_randao_mix) + - [`get_active_index_root`](#get_active_index_root) - [`get_beacon_proposer_index`](#get_beacon_proposer_index) - [`merkle_root`](#merkle_root) - [`get_attestation_participants`](#get_attestation_participants) @@ -168,6 +167,7 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted | `MAX_CASPER_VOTES` | `2**10` (= 1,024) | votes | | `LATEST_BLOCK_ROOTS_LENGTH` | `2**13` (= 8,192) | block roots | | `LATEST_RANDAO_MIXES_LENGTH` | `2**13` (= 8,192) | randao mixes | +| `LATEST_INDEX_ROOTS_LENGTH` | `2**13` (= 8,192) | index roots | | `LATEST_PENALIZED_EXIT_LENGTH` | `2**13` (= 8,192) | epochs | ~36 days | | `MAX_WITHDRAWALS_PER_EPOCH` | `2**2` (= 4) | withdrawals | @@ -235,13 +235,6 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted | `MAX_DEPOSITS` | `2**4` (= 16) | | `MAX_EXITS` | `2**4` (= 16) | -### Validator registry delta flags - -| Name | Value | -| - | - | -| `ACTIVATION` | `0` | -| `EXIT` | `1` | - ### Signature domains | Name | Value | @@ -478,7 +471,6 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted 'validator_balances': ['uint64'], 'validator_registry_update_slot': 'uint64', 'validator_registry_exit_count': 'uint64', - 'validator_registry_delta_chain_tip': 'hash32', # For light clients to track deltas # Randomness and committees 'latest_randao_mixes': ['hash32'], @@ -487,8 +479,8 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted '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', + 'previous_epoch_seed': 'hash32', + 'current_epoch_seed': 'hash32', # Custody challenges 'custody_challenges': [CustodyChallenge], @@ -502,6 +494,7 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted # Recent state 'latest_crosslinks': [Crosslink], 'latest_block_roots': ['hash32'], # Needed to process attestations, older to newer + 'latest_index_roots': ['hash32'], 'latest_penalized_balances': ['uint64'], # Balances penalized at every withdrawal period 'latest_attestations': [PendingAttestation], 'batched_block_roots': ['hash32'], @@ -584,18 +577,6 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted } ``` -#### `ValidatorRegistryDeltaBlock` - -```python -{ - 'latest_registry_delta_root': 'hash32', - 'validator_index': 'uint24', - 'pubkey': 'uint384', - 'slot': 'uint64', - 'flag': 'uint64', -} -``` - #### `Eth1Data` ```python @@ -954,7 +935,7 @@ def get_crosslink_committees_at_slot(state: BeaconState, if slot < state_epoch_slot: committees_per_slot = get_previous_epoch_committee_count_per_slot(state) shuffling = get_shuffling( - state.previous_epoch_randao_mix, + state.previous_epoch_seed, state.validator_registry, state.previous_epoch_calculation_slot, ) @@ -962,7 +943,7 @@ def get_crosslink_committees_at_slot(state: BeaconState, else: committees_per_slot = get_current_epoch_committee_count_per_slot(state) shuffling = get_shuffling( - state.current_epoch_randao_mix, + state.current_epoch_seed, state.validator_registry, state.current_epoch_calculation_slot, ) @@ -1007,6 +988,19 @@ def get_randao_mix(state: BeaconState, return state.latest_randao_mixes[slot % LATEST_RANDAO_MIXES_LENGTH] ``` +#### `get_active_index_root` + +```python +def get_active_index_root(state: BeaconState, + slot: int) -> Hash32: + """ + Returns the randao mix at a recent ``slot``. + """ + assert state.slot // EPOCH_LENGTH < slot // EPOCH_LENGTH + LATEST_INDEX_ROOTS_LENGTH + assert slot // EPOCH_LENGTH <= state.slot // EPOCH_LENGTH + return state.latest_index_roots[(slot // EPOCH_LENGTH) % LATEST_INDEX_ROOTS_LENGTH] +``` + #### `get_beacon_proposer_index` ```python @@ -1235,7 +1229,6 @@ def get_initial_beacon_state(initial_validator_deposits: List[Deposit], validator_balances=[], validator_registry_update_slot=GENESIS_SLOT, validator_registry_exit_count=0, - validator_registry_delta_chain_tip=ZERO_HASH, # Randomness and committees latest_randao_mixes=[ZERO_HASH for _ in range(LATEST_RANDAO_MIXES_LENGTH)], @@ -1244,8 +1237,8 @@ def get_initial_beacon_state(initial_validator_deposits: List[Deposit], 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, + previous_epoch_seed=ZERO_HASH, + current_epoch_seed=ZERO_HASH, # Custody challenges custody_challenges=[], @@ -1259,6 +1252,7 @@ def get_initial_beacon_state(initial_validator_deposits: List[Deposit], # Recent state latest_crosslinks=[Crosslink(slot=GENESIS_SLOT, shard_block_root=ZERO_HASH) for _ in range(SHARD_COUNT)], latest_block_roots=[ZERO_HASH for _ in range(LATEST_BLOCK_ROOTS_LENGTH)], + latest_index_roots=[ZERO_HASH for _ in range(LATEST_INDEX_ROOTS_LENGTH)], latest_penalized_balances=[0 for _ in range(LATEST_PENALIZED_EXIT_LENGTH)], latest_attestations=[], batched_block_roots=[], @@ -1383,16 +1377,7 @@ Note: All functions in this section mutate `state`. def activate_validator(state: BeaconState, index: int, genesis: bool) -> None: validator = state.validator_registry[index] - validator.activation_slot = GENESIS_SLOT if genesis else (state.slot + ENTRY_EXIT_DELAY) - state.validator_registry_delta_chain_tip = hash_tree_root( - ValidatorRegistryDeltaBlock( - latest_registry_delta_root=state.validator_registry_delta_chain_tip, - validator_index=index, - pubkey=validator.pubkey, - slot=validator.activation_slot, - flag=ACTIVATION, - ) - ) + validator.activation_slot = GENESIS_SLOT if genesis else (state.slot - state.slot % EPOCH_LENGTH + ENTRY_EXIT_DELAY) ``` ```python @@ -1406,22 +1391,13 @@ def exit_validator(state: BeaconState, index: int) -> None: validator = state.validator_registry[index] # The following updates only occur if not previous exited - if validator.exit_slot <= state.slot + ENTRY_EXIT_DELAY: + if validator.exit_slot <= state.slot - state.slot % EPOCH_LENGTH + ENTRY_EXIT_DELAY: return - validator.exit_slot = state.slot + ENTRY_EXIT_DELAY + validator.exit_slot = state.slot - state.slot % EPOCH_LENGTH + ENTRY_EXIT_DELAY state.validator_registry_exit_count += 1 validator.exit_count = state.validator_registry_exit_count - state.validator_registry_delta_chain_tip = hash_tree_root( - ValidatorRegistryDeltaBlock( - latest_registry_delta_root=state.validator_registry_delta_chain_tip, - validator_index=index, - pubkey=validator.pubkey, - slot=validator.exit_slot, - flag=EXIT, - ) - ) ``` ```python @@ -1583,7 +1559,7 @@ Verify that `len(block.body.exits) <= MAX_EXITS`. For each `exit` in `block.body.exits`: * Let `validator = state.validator_registry[exit.validator_index]`. -* Verify that `validator.exit_slot > state.slot + ENTRY_EXIT_DELAY`. +* Verify that `validator.exit_slot > state.slot - state.slot % EPOCH_LENGTH + ENTRY_EXIT_DELAY`. * Verify that `state.slot >= exit.slot`. * Let `exit_message = hash_tree_root(Exit(slot=exit.slot, validator_index=exit.validator_index, signature=EMPTY_SIGNATURE))`. * Verify that `bls_verify(pubkey=validator.pubkey, message=exit_message, signature=exit.signature, domain=get_domain(state.fork, exit.slot, DOMAIN_EXIT))`. @@ -1763,7 +1739,7 @@ def update_validator_registry(state: BeaconState) -> None: # Activate validators within the allowable balance churn balance_churn = 0 for index, validator in enumerate(state.validator_registry): - if validator.activation_slot > state.slot + ENTRY_EXIT_DELAY and state.validator_balances[index] >= MAX_DEPOSIT_AMOUNT: + if validator.activation_slot > state.slot - state.slot % EPOCH_LENGTH + ENTRY_EXIT_DELAY and state.validator_balances[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: @@ -1775,7 +1751,7 @@ def update_validator_registry(state: BeaconState) -> None: # Exit validators within the allowable balance churn balance_churn = 0 for index, validator in enumerate(state.validator_registry): - if validator.exit_slot > state.slot + ENTRY_EXIT_DELAY and validator.status_flags & INITIATED_EXIT: + if validator.exit_slot > state.slot - state.slot % EPOCH_LENGTH + ENTRY_EXIT_DELAY and validator.status_flags & INITIATED_EXIT: # Check the balance churn would be within the allowance balance_churn += get_effective_balance(state, index) if balance_churn > max_balance_churn: @@ -1791,17 +1767,19 @@ and perform the following updates: * 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.previous_epoch_seed = state.current_epoch_seed` * Set `state.current_epoch_calculation_slot = state.slot` * Set `state.current_epoch_start_shard = (state.current_epoch_start_shard + get_current_epoch_committee_count_per_slot(state) * EPOCH_LENGTH) % SHARD_COUNT` -* Set `state.current_epoch_randao_mix = get_randao_mix(state, state.current_epoch_calculation_slot - SEED_LOOKAHEAD)` +* Set `state.current_epoch_seed = hash(get_randao_mix(state, state.current_epoch_calculation_slot - SEED_LOOKAHEAD) + get_active_index_root(state, state.current_epoch_calculation_slot))` If a validator registry update does _not_ happen do the following: * 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_update_slot) // EPOCH_LENGTH`. -* 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. +* If `epochs_since_last_registry_change` is an exact power of 2, set `state.current_epoch_calculation_slot = state.slot` and `state.current_epoch_seed = hash(get_randao_mix(state, state.current_epoch_calculation_slot - SEED_LOOKAHEAD) + get_active_index_root(state, state.current_epoch_calculation_slot))`. Note that `state.current_epoch_start_shard` is left unchanged. + +**Invariant**: the active index root that is hashed into the shuffling seed actually is the `hash_tree_root` of the validator set that is used for that epoch. Regardless of whether or not a validator set change happens, run the following: @@ -1844,6 +1822,7 @@ def process_penalties_and_exits(state: BeaconState) -> None: * Let `e = state.slot // EPOCH_LENGTH`. Set `state.latest_penalized_balances[(e+1) % LATEST_PENALIZED_EXIT_LENGTH] = state.latest_penalized_balances[e % LATEST_PENALIZED_EXIT_LENGTH]` * Remove any `attestation` in `state.latest_attestations` such that `attestation.data.slot < state.slot - EPOCH_LENGTH`. +* Let `epoch = state.slot // EPOCH_LENGTH`. Set `state.latest_index_roots[epoch % LATEST_INDEX_ROOTS_LENGTH] = hash_tree_root(get_active_validator_indices(state, state.slot))` ## State root processing From 958c338c8fe1e9ea8e7494add7d33eecdced5513 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Sat, 19 Jan 2019 18:11:07 -0600 Subject: [PATCH 02/11] 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 3f687618a..afa87a140 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -994,7 +994,7 @@ def get_randao_mix(state: BeaconState, def get_active_index_root(state: BeaconState, slot: int) -> Hash32: """ - Returns the randao mix at a recent ``slot``. + Returns the index root at a recent ``slot``. """ assert state.slot // EPOCH_LENGTH < slot // EPOCH_LENGTH + LATEST_INDEX_ROOTS_LENGTH assert slot // EPOCH_LENGTH <= state.slot // EPOCH_LENGTH From 02725b870e0cc8b6c01427906cafe4a36461a528 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Sat, 19 Jan 2019 18:11:14 -0600 Subject: [PATCH 03/11] 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 afa87a140..25eb7bbe6 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -992,7 +992,7 @@ def get_randao_mix(state: BeaconState, ```python def get_active_index_root(state: BeaconState, - slot: int) -> Hash32: + slot: int) -> Bytes32: """ Returns the index root at a recent ``slot``. """ From 12b217df70ea36fa7322efd00fdd8491cba5ed7f Mon Sep 17 00:00:00 2001 From: vbuterin Date: Sat, 19 Jan 2019 18:13:17 -0600 Subject: [PATCH 04/11] Updated as per hww's suggestions --- specs/core/0_beacon-chain.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 25eb7bbe6..88b3c0384 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -996,9 +996,11 @@ def get_active_index_root(state: BeaconState, """ Returns the index root at a recent ``slot``. """ - assert state.slot // EPOCH_LENGTH < slot // EPOCH_LENGTH + LATEST_INDEX_ROOTS_LENGTH - assert slot // EPOCH_LENGTH <= state.slot // EPOCH_LENGTH - return state.latest_index_roots[(slot // EPOCH_LENGTH) % LATEST_INDEX_ROOTS_LENGTH] + state_epoch = state.slot // EPOCH_LENGTH + given_epoch = slot // EPOCH_LENGTH + assert state_epoch < given_epoch + LATEST_INDEX_ROOTS_LENGTH + assert given_epoch <= state_epoch + return state.latest_index_roots[given_epoch % LATEST_INDEX_ROOTS_LENGTH] ``` #### `get_beacon_proposer_index` @@ -1819,9 +1821,10 @@ def process_penalties_and_exits(state: BeaconState) -> None: ### Final updates -* Let `e = state.slot // EPOCH_LENGTH`. Set `state.latest_penalized_balances[(e+1) % LATEST_PENALIZED_EXIT_LENGTH] = state.latest_penalized_balances[e % LATEST_PENALIZED_EXIT_LENGTH]` +* Let `epoch = state.slot // EPOCH_LENGTH`. +* Set `state.latest_penalized_balances[(epoch+1) % LATEST_PENALIZED_EXIT_LENGTH] = state.latest_penalized_balances[epoch % LATEST_PENALIZED_EXIT_LENGTH]` * Remove any `attestation` in `state.latest_attestations` such that `attestation.data.slot < state.slot - EPOCH_LENGTH`. -* Let `epoch = state.slot // EPOCH_LENGTH`. Set `state.latest_index_roots[epoch % LATEST_INDEX_ROOTS_LENGTH] = hash_tree_root(get_active_validator_indices(state, state.slot))` +* Set `state.latest_index_roots[epoch % LATEST_INDEX_ROOTS_LENGTH] = hash_tree_root(get_active_validator_indices(state, state.slot))` ## State root processing From 697545a9e056c08e54e02027f16fdfc0c72c2cde Mon Sep 17 00:00:00 2001 From: vbuterin Date: Tue, 22 Jan 2019 22:47:07 -0600 Subject: [PATCH 05/11] Added entry_exit_effect_slot helper and moved index roots update --- specs/core/0_beacon-chain.md | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index b0e7303c5..56789d822 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -83,6 +83,7 @@ - [`is_double_vote`](#is_double_vote) - [`is_surround_vote`](#is_surround_vote) - [`integer_squareroot`](#integer_squareroot) + - [`entry_exit_effect_slot`](#entry_exit_effect_slot) - [`bls_verify`](#bls_verify) - [`bls_verify_multiple`](#bls_verify_multiple) - [`bls_aggregate_pubkeys`](#bls_aggregate_pubkeys) @@ -1159,7 +1160,7 @@ def is_surround_vote(attestation_data_1: AttestationData, ```python def integer_squareroot(n: int) -> int: """ - The largest integer ``x`` such that ``x**2`` is less than ``n``. + The largest integer ``x`` such that ``x**2`` is less than or equal to ``n``. """ assert n >= 0 x = n @@ -1170,6 +1171,17 @@ def integer_squareroot(n: int) -> int: return x ``` +#### `entry_exit_effect_slot` + +```python +def entry_exit_effect_slot(n: int) -> int: + """ + An entry or exit triggered in the slot given by the input takes effect at + the slot given by the output. + """ + return (n - n % EPOCH_LENGTH) + EPOCH_LENGTH + ENTRY_EXIT_DELAY +``` + #### `bls_verify` `bls_verify` is a function for verifying a BLS signature, defined in the [BLS Signature spec](https://github.com/ethereum/eth2.0-specs/blob/master/specs/bls_signature.md#bls_verify). @@ -1372,13 +1384,13 @@ def process_deposit(state: BeaconState, ### Routines for updating validator status -Note: All functions in this section mutate `state`. +Note: All functions in this section mutate `state`. ```python def activate_validator(state: BeaconState, index: int, genesis: bool) -> None: validator = state.validator_registry[index] - validator.activation_slot = GENESIS_SLOT if genesis else (state.slot - state.slot % EPOCH_LENGTH + ENTRY_EXIT_DELAY) + validator.activation_slot = GENESIS_SLOT if genesis else entry_exit_effect_slot(state.slot) ``` ```python @@ -1392,10 +1404,10 @@ def exit_validator(state: BeaconState, index: int) -> None: validator = state.validator_registry[index] # The following updates only occur if not previous exited - if validator.exit_slot <= state.slot - state.slot % EPOCH_LENGTH + ENTRY_EXIT_DELAY: + if validator.exit_slot <= entry_exit_effect_slot(state.slot): return - validator.exit_slot = state.slot - state.slot % EPOCH_LENGTH + ENTRY_EXIT_DELAY + validator.exit_slot = entry_exit_effect_slot(state.slot) state.validator_registry_exit_count += 1 validator.exit_count = state.validator_registry_exit_count @@ -1560,7 +1572,7 @@ Verify that `len(block.body.exits) <= MAX_EXITS`. For each `exit` in `block.body.exits`: * Let `validator = state.validator_registry[exit.validator_index]`. -* Verify that `validator.exit_slot > state.slot - state.slot % EPOCH_LENGTH + ENTRY_EXIT_DELAY`. +* Verify that `validator.exit_slot > entry_exit_effect_slot(state.slot)`. * Verify that `state.slot >= exit.slot`. * Let `exit_message = hash_tree_root(Exit(slot=exit.slot, validator_index=exit.validator_index, signature=EMPTY_SIGNATURE))`. * Verify that `bls_verify(pubkey=validator.pubkey, message=exit_message, signature=exit.signature, domain=get_domain(state.fork, exit.slot, DOMAIN_EXIT))`. @@ -1711,12 +1723,13 @@ def process_ejections(state: BeaconState) -> None: exit_validator(state, index) ``` -### Validator registry +### Validator registry and shuffling seed data -First, update `previous_epoch_calculation_slot` and `previous_epoch_start_shard`: +First, update `previous_epoch_calculation_slot`, `previous_epoch_start_shard` and `latest_index_roots`: * Set `state.previous_epoch_calculation_slot = state.current_epoch_calculation_slot` * Set `state.previous_epoch_start_shard = state.current_epoch_start_shard` +* Set `state.latest_index_roots[epoch % LATEST_INDEX_ROOTS_LENGTH] = hash_tree_root(get_active_validator_indices(state, state.slot))` If the following are satisfied: @@ -1745,7 +1758,7 @@ def update_validator_registry(state: BeaconState) -> None: # Activate validators within the allowable balance churn balance_churn = 0 for index, validator in enumerate(state.validator_registry): - if validator.activation_slot > state.slot - state.slot % EPOCH_LENGTH + ENTRY_EXIT_DELAY and state.validator_balances[index] >= MAX_DEPOSIT_AMOUNT: + if validator.activation_slot > entry_exit_effect_slot(state.slot) and state.validator_balances[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: @@ -1757,7 +1770,7 @@ def update_validator_registry(state: BeaconState) -> None: # Exit validators within the allowable balance churn balance_churn = 0 for index, validator in enumerate(state.validator_registry): - if validator.exit_slot > state.slot - state.slot % EPOCH_LENGTH + ENTRY_EXIT_DELAY and validator.status_flags & INITIATED_EXIT: + if validator.exit_slot > entry_exit_effect_slot(state.slot) and validator.status_flags & INITIATED_EXIT: # Check the balance churn would be within the allowance balance_churn += get_effective_balance(state, index) if balance_churn > max_balance_churn: @@ -1825,7 +1838,6 @@ def process_penalties_and_exits(state: BeaconState) -> None: * Let `epoch = state.slot // EPOCH_LENGTH`. * Set `state.latest_penalized_balances[(epoch+1) % LATEST_PENALIZED_EXIT_LENGTH] = state.latest_penalized_balances[epoch % LATEST_PENALIZED_EXIT_LENGTH]` * Remove any `attestation` in `state.latest_attestations` such that `attestation.data.slot < state.slot - EPOCH_LENGTH`. -* Set `state.latest_index_roots[epoch % LATEST_INDEX_ROOTS_LENGTH] = hash_tree_root(get_active_validator_indices(state, state.slot))` ## State root processing From f9097bfe8b3832db07b8a263320aff93368b3a68 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Wed, 23 Jan 2019 00:22:47 -0600 Subject: [PATCH 06/11] 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 56789d822..9399bc255 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1384,7 +1384,7 @@ def process_deposit(state: BeaconState, ### Routines for updating validator status -Note: All functions in this section mutate `state`. +Note: All functions in this section mutate `state`. ```python def activate_validator(state: BeaconState, index: int, genesis: bool) -> None: From f61d3643521b9ad06642c8a2026be22fe9f5735d Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 25 Jan 2019 14:56:10 -0700 Subject: [PATCH 07/11] clean up top language in validator registry section --- 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 4cecb4ddd..ddfb833f8 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1701,7 +1701,7 @@ def process_ejections(state: BeaconState) -> None: ### Validator registry and shuffling seed data -First, update `previous_epoch_calculation_slot`, `previous_epoch_start_shard` and `latest_index_roots`: +First, update the following: * Set `state.previous_epoch_calculation_slot = state.current_epoch_calculation_slot` * Set `state.previous_epoch_start_shard = state.current_epoch_start_shard` From f96cd871b1e9b48f54b23cab106937d5f9d66cc3 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 25 Jan 2019 15:25:19 -0700 Subject: [PATCH 08/11] update ordering of assignments --- 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 ddfb833f8..dc9fadd54 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1705,8 +1705,8 @@ First, update the following: * Set `state.previous_epoch_calculation_slot = state.current_epoch_calculation_slot` * Set `state.previous_epoch_start_shard = state.current_epoch_start_shard` -* Set `state.latest_index_roots[epoch % LATEST_INDEX_ROOTS_LENGTH] = hash_tree_root(get_active_validator_indices(state, state.slot))` * Set `state.previous_epoch_seed = state.current_epoch_seed` +* Set `state.latest_index_roots[epoch % LATEST_INDEX_ROOTS_LENGTH] = hash_tree_root(get_active_validator_indices(state, state.slot))` If the following are satisfied: From 86faacdcd2fdebda137b0ce661553d7e4286e4b4 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 25 Jan 2019 15:27:27 -0700 Subject: [PATCH 09/11] clarify assignments in val reg not change --- specs/core/0_beacon-chain.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index dc9fadd54..b6dc26a7a 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1768,7 +1768,10 @@ and perform the following updates: If a validator registry update does _not_ happen do the following: * Let `epochs_since_last_registry_change = (state.slot - state.validator_registry_update_slot) // EPOCH_LENGTH`. -* If `epochs_since_last_registry_change` is an exact power of 2, set `state.current_epoch_calculation_slot = state.slot` and `state.current_epoch_seed = hash(get_randao_mix(state, state.current_epoch_calculation_slot - SEED_LOOKAHEAD) + get_active_index_root(state, state.current_epoch_calculation_slot))`. Note that `state.current_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` + * Set `state.current_epoch_seed = hash(get_randao_mix(state, state.current_epoch_calculation_slot - SEED_LOOKAHEAD) + get_active_index_root(state, state.current_epoch_calculation_slot))`. + * _Note_ that `state.current_epoch_start_shard` is left unchanged. **Invariant**: the active index root that is hashed into the shuffling seed actually is the `hash_tree_root` of the validator set that is used for that epoch. From 56037726210fa6e79be3afe974c6284ad4eb18fe Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 25 Jan 2019 15:28:08 -0700 Subject: [PATCH 10/11] add missing period --- 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 b6dc26a7a..d949af716 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1769,7 +1769,7 @@ If a validator registry update does _not_ happen do the following: * Let `epochs_since_last_registry_change = (state.slot - state.validator_registry_update_slot) // EPOCH_LENGTH`. * If `epochs_since_last_registry_change` is an exact power of 2: - * Set `state.current_epoch_calculation_slot = state.slot` + * Set `state.current_epoch_calculation_slot = state.slot`. * Set `state.current_epoch_seed = hash(get_randao_mix(state, state.current_epoch_calculation_slot - SEED_LOOKAHEAD) + get_active_index_root(state, state.current_epoch_calculation_slot))`. * _Note_ that `state.current_epoch_start_shard` is left unchanged. From 85d39af1cad0e4869944be8bdcbfb75b7c3c64f6 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 25 Jan 2019 15:28:49 -0700 Subject: [PATCH 11/11] add missing period --- 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 d949af716..8eaa2b5e4 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1815,7 +1815,7 @@ def process_penalties_and_exits(state: BeaconState) -> None: ### Final updates * Let `epoch = state.slot // EPOCH_LENGTH`. -* Set `state.latest_penalized_balances[(epoch+1) % LATEST_PENALIZED_EXIT_LENGTH] = state.latest_penalized_balances[epoch % LATEST_PENALIZED_EXIT_LENGTH]` +* Set `state.latest_penalized_balances[(epoch+1) % LATEST_PENALIZED_EXIT_LENGTH] = state.latest_penalized_balances[epoch % LATEST_PENALIZED_EXIT_LENGTH]`. * Remove any `attestation` in `state.latest_attestations` such that `attestation.data.slot < state.slot - EPOCH_LENGTH`. ## State root processing