From befc3498783c62b99cc395d6ea5c0d785d96afaf Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Tue, 11 Dec 2018 11:14:42 -0600 Subject: [PATCH 01/19] add balance diff consensus safety note --- 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 06e9c2a56..ae725dc1e 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1468,7 +1468,7 @@ All [validators](#dfn-validator): * Let `previous_epoch_boundary_attestations = [a for a in this_epoch_attestations + previous_epoch_attestations if a.epoch_boundary_hash == get_block_hash(state, state.slot - 2 * EPOCH_LENGTH) and a.justified_slot == state.previous_justified_slot]`. * Let `previous_epoch_boundary_attester_indices` be the union of the validator index sets given by `[get_attestation_participants(state, a.data, a.participation_bitfield) for a in previous_epoch_boundary_attestations]`. * Let `previous_epoch_boundary_attesters = [state.validator_registry[i] for indices in previous_epoch_boundary_attester_indices for i in indices]`. -* Let `previous_epoch_boundary_attesting_balance = sum([get_effective_balance(v) for v in previous_epoch_boundary_attesters])`. +* Let `previous_epoch_boundary_attesting_balance = sum([get_effective_balance(v) for v in previous_epoch_boundary_attesters])`. *Note: this balance might be marginally different than the `this_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` in `state.shard_committees_at_slots`: From 83224c320a336babe0235cc4afac575333fcb855 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Tue, 11 Dec 2018 11:16:24 -0600 Subject: [PATCH 02/19] small edit to language --- 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 ae725dc1e..e8e864927 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1468,7 +1468,7 @@ All [validators](#dfn-validator): * Let `previous_epoch_boundary_attestations = [a for a in this_epoch_attestations + previous_epoch_attestations if a.epoch_boundary_hash == get_block_hash(state, state.slot - 2 * EPOCH_LENGTH) and a.justified_slot == state.previous_justified_slot]`. * Let `previous_epoch_boundary_attester_indices` be the union of the validator index sets given by `[get_attestation_participants(state, a.data, a.participation_bitfield) for a in previous_epoch_boundary_attestations]`. * Let `previous_epoch_boundary_attesters = [state.validator_registry[i] for indices in previous_epoch_boundary_attester_indices for i in indices]`. -* Let `previous_epoch_boundary_attesting_balance = sum([get_effective_balance(v) for v in previous_epoch_boundary_attesters])`. *Note: this balance might be marginally different than the `this_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.* +* Let `previous_epoch_boundary_attesting_balance = sum([get_effective_balance(v) for v in previous_epoch_boundary_attesters])`. *Note: this balance might be marginally different than `this_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` in `state.shard_committees_at_slots`: From acd83973fbc55c70350d3963b04dec793cc03bb8 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Wed, 12 Dec 2018 10:02:49 -0600 Subject: [PATCH 03/19] bold note --- 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 a18bc8d86..257b41c5a 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1502,7 +1502,7 @@ All [validators](#dfn-validator): * Let `previous_epoch_head_attesters = [state.validator_registry[i] for indices in previous_epoch_head_attester_indices for i in indices]`. * Let `previous_epoch_head_attesting_balance = sum([get_effective_balance(v) for v in previous_epoch_head_attesters])`. -_Note_: `previous_epoch_boundary_attesting_balance` balance might be marginally different than `this_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. +**Note**: `previous_epoch_boundary_attesting_balance` balance might be marginally different than `this_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` in `state.shard_committees_at_slots`: From 2b9a0e999c60f7f466801f91b1eabcf3d00ba3a7 Mon Sep 17 00:00:00 2001 From: vbuterin Date: Thu, 13 Dec 2018 19:28:59 -0500 Subject: [PATCH 04/19] Separate validator balances --- specs/core/0_beacon-chain.md | 101 ++++++++++++++++------------------- 1 file changed, 47 insertions(+), 54 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 42929bbd6..d9859407c 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -449,6 +449,7 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted # Validator registry 'validator_registry': [ValidatorRecord], + 'validator_balances': ['uint64'], 'validator_registry_latest_change_slot': 'uint64', 'validator_registry_exit_count': 'uint64', 'validator_registry_delta_chain_tip': 'hash32', # For light clients to track deltas @@ -491,8 +492,6 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted 'randao_commitment': 'hash32', # Slots the proposer has skipped (i.e. layers of RANDAO expected) 'randao_layers': 'uint64', - # Balance in Gwei - 'balance': 'uint64', # Status code 'status': 'uint64', # Slot when validator last changed status (or 0) @@ -956,11 +955,11 @@ def get_attestation_participants(state: BeaconState, #### `get_effective_balance` ```python -def get_effective_balance(validator: ValidatorRecord) -> int: +def get_effective_balance(balance: int) -> int: """ - Returns the effective balance (also known as "balance at stake") for the ``validator``. + Returns the effective balance (also known as "balance at stake") for a ``validator`` with the given balance. """ - return min(validator.balance, MAX_DEPOSIT * GWEI_PER_ETH) + return min(balance, MAX_DEPOSIT * GWEI_PER_ETH) ``` #### `get_new_validator_registry_delta_chain_tip` @@ -1138,7 +1137,7 @@ def get_initial_beacon_state(initial_validator_deposits: List[Deposit], withdrawal_credentials=deposit.deposit_data.deposit_input.withdrawal_credentials, randao_commitment=deposit.deposit_data.deposit_input.randao_commitment ) - if state.validator_registry[index].balance >= MAX_DEPOSIT * GWEI_PER_ETH: + if state.validator_balances[index] >= MAX_DEPOSIT * GWEI_PER_ETH: update_validator_status(state, index, ACTIVE) # set initial committee shuffling @@ -1157,9 +1156,9 @@ def get_initial_beacon_state(initial_validator_deposits: List[Deposit], First, a helper function: ```python -def min_empty_validator_index(validators: List[ValidatorRecord], current_slot: int) -> int: - for i, v in enumerate(validators): - if v.balance == 0 and v.latest_status_change_slot + ZERO_BALANCE_VALIDATOR_TTL <= current_slot: +def min_empty_validator_index(validators: List[ValidatorRecord], validator_balances: List[int], current_slot: int) -> int: + for i, (v, vbal) in enumerate(zip(validators, validator_balances)): + if vbal == 0 and v.latest_status_change_slot + ZERO_BALANCE_VALIDATOR_TTL <= current_slot: return i return None ``` @@ -1212,10 +1211,9 @@ def process_deposit(state: BeaconState, else: # Increase balance by deposit index = validator_pubkeys.index(pubkey) - validator = state.validator_registry[index] - assert validator.withdrawal_credentials == withdrawal_credentials + assert state.validator_registry[index].withdrawal_credentials == withdrawal_credentials - validator.balance += deposit + state.validator_balances[index] += deposit return index ``` @@ -1299,10 +1297,10 @@ def exit_validator(state: BeaconState, if new_status == EXITED_WITH_PENALTY: state.latest_penalized_exit_balances[state.slot // COLLECTIVE_PENALTY_CALCULATION_PERIOD] += get_effective_balance(validator) - whistleblower = state.validator_registry[get_beacon_proposer_index(state, state.slot)] - whistleblower_reward = validator.balance // WHISTLEBLOWER_REWARD_QUOTIENT - whistleblower.balance += whistleblower_reward - validator.balance -= whistleblower_reward + whistleblower_index = get_beacon_proposer_index(state, state.slot) + whistleblower_reward = state.validator_balances[index] // WHISTLEBLOWER_REWARD_QUOTIENT + state.validator_balances[whistleblower_index] += whistleblower_reward + state.validator_balances[index] -= whistleblower_reward if prev_status == EXITED_WITHOUT_PENALTY return @@ -1475,8 +1473,8 @@ The steps below happen when `state.slot % EPOCH_LENGTH == 0`. All [validators](#dfn-validator): -* Let `active_validators = [state.validator_registry[i] for i in get_active_validator_indices(state.validator_registry)]`. -* Let `total_balance = sum([get_effective_balance(v) for v in active_validators])`. +* Let `active_validator_indices = get_active_validator_indices(state.validator_registry)`. +* Let `total_balance = sum([get_effective_balance(state.validator_balances[i]) for i in active_validator_indices])`. [Validators](#dfn-Validator) attesting during the current epoch: @@ -1486,38 +1484,33 @@ All [validators](#dfn-validator): * Let `this_epoch_boundary_attestations = [a for a in this_epoch_attestations if a.data.epoch_boundary_root == get_block_root(state, state.slot-EPOCH_LENGTH) and a.justified_slot == state.justified_slot]`. * Let `this_epoch_boundary_attester_indices` be the union of the [validator](#dfn-validator) index sets given by `[get_attestation_participants(state, a.data, a.participation_bitfield) for a in this_epoch_boundary_attestations]`. - * Let `this_epoch_boundary_attesters = [state.validator_registry[i] for indices in this_epoch_boundary_attester_indices for i in indices]`. - * Let `this_epoch_boundary_attesting_balance = sum([get_effective_balance(v) for v in this_epoch_boundary_attesters])`. + * Let `this_epoch_boundary_attesting_balance = sum([get_effective_balance(state.validator_balances[i]) for v in this_epoch_boundary_attester_indices])`. [Validators](#dfn-Validator) attesting during the previous epoch: * Validators that made an attestation during the previous epoch: * Let `previous_epoch_attestations = [a for a in state.latest_attestations if state.slot - 2 * EPOCH_LENGTH <= a.slot < state.slot - EPOCH_LENGTH]`. * Let `previous_epoch_attester_indices` be the union of the validator index sets given by `[get_attestation_participants(state, a.data, a.participation_bitfield) for a in previous_epoch_attestations]`. - * Let `previous_epoch_attesters = [state.validator_registry[i] for indices in previous_epoch_attester_indices for i in indices]`. * Validators targeting the previous justified hash: * Let `previous_epoch_justified_attestations = [a for a in this_epoch_attestations + previous_epoch_attestations if a.justified_slot == state.previous_justified_slot]`. * Let `previous_epoch_justified_attester_indices` be the union of the validator index sets given by `[get_attestation_participants(state, a.data, a.participation_bitfield) for a in previous_epoch_justified_attestations]`. - * Let `previous_epoch_justified_attesters = [state.validator_registry[i] for indices in previous_epoch_justified_attester_indices for i in indices]`. - * Let `previous_epoch_justified_attesting_balance = sum([get_effective_balance(v) for v in previous_epoch_justified_attesters])`. + * Let `previous_epoch_justified_attesting_balance = sum([get_effective_balance(state.validator_balances[i]) for v in previous_epoch_justified_attester_indices])`. * Validators justifying the epoch boundary block at the start of the previous epoch: * Let `previous_epoch_boundary_attestations = [a for a in previous_epoch_justified_attestations if a.epoch_boundary_root == get_block_root(state, state.slot - 2 * EPOCH_LENGTH)]`. * Let `previous_epoch_boundary_attester_indices` be the union of the validator index sets given by `[get_attestation_participants(state, a.data, a.participation_bitfield) for a in previous_epoch_boundary_attestations]`. - * Let `previous_epoch_boundary_attesters = [state.validator_registry[i] for indices in previous_epoch_boundary_attester_indices for i in indices]`. - * Let `previous_epoch_boundary_attesting_balance = sum([get_effective_balance(v) for v in previous_epoch_boundary_attesters])`. + * Let `previous_epoch_boundary_attesting_balance = sum([get_effective_balance(state.validator_balances[i]) for v in previous_epoch_boundary_attester_indices])`. * Validators attesting to the expected beacon chain head during the previous epoch: * Let `previous_epoch_head_attestations = [a for a in previous_epoch_attestations if a.beacon_block_root == get_block_root(state, a.slot)]`. * Let `previous_epoch_head_attester_indices` be the union of the validator index sets given by `[get_attestation_participants(state, a.data, a.participation_bitfield) for a in previous_epoch_head_attestations]`. - * Let `previous_epoch_head_attesters = [state.validator_registry[i] for indices in previous_epoch_head_attester_indices for i in indices]`. - * Let `previous_epoch_head_attesting_balance = sum([get_effective_balance(v) for v in previous_epoch_head_attesters])`. + * Let `previous_epoch_head_attesting_balance = sum([get_effective_balance(state.validator_balances[i]) for v in previous_epoch_head_attester_indices])`. For every `shard_committee` in `state.shard_committees_at_slots`: -* Let `attesting_validators(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 this_epoch_attestations + previous_epoch_attestations if a.shard == shard_committee.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(v) for v in attesting_validators(shard_committee, shard_block_root)])` is maximized (ties broken by favoring lower `shard_block_root` values). +* 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 this_epoch_attestations + previous_epoch_attestations if a.shard == shard_committee.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.validator_balances[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_validators(shard_committee, winning_root(shard_committee))` for convenience. * Let `total_attesting_balance(shard_committee)` be the sum of the balances-at-stake of `attesting_validators(shard_committee)`. -* Let `total_balance(shard_committee) = sum([get_effective_balance(v) for v in shard_committee.committee])`. +* Let `total_balance(shard_committee) = sum([get_effective_balance(state.validator_balances[i]) for i in shard_committee.committee])`. * Let `inclusion_slot(v) = a.slot_included` for the attestation `a` where `v` is in `get_attestation_participants(state, a.data, a.participation_bitfield)`. * Let `inclusion_distance(v) = a.slot_included - a.data.slot` where `a` is the above attestation. * Let `adjust_for_inclusion_distance(magnitude, distance)` be the function below. @@ -1564,8 +1557,8 @@ For every `shard_committee` in `state.shard_committees_at_slots`: First, we define some additional helpers: * Let `base_reward_quotient = BASE_REWARD_QUOTIENT * integer_squareroot(total_balance // GWEI_PER_ETH)`. -* Let `base_reward(v) = get_effective_balance(v) // base_reward_quotient // 4` for any validator `v`. -* Let `inactivity_penalty(v, slots_since_finality) = base_reward(v) + get_effective_balance(v) * slots_since_finality // INACTIVITY_PENALTY_QUOTIENT` for any validator `v`. +* Let `base_reward(index) = get_effective_balance(state.validator_balances[index]) // base_reward_quotient // 4` for any validator with the given `index`. +* Let `inactivity_penalty(index, slots_since_finality) = base_reward(index) + get_effective_balance(state.validator_balances[index]) * slots_since_finality // INACTIVITY_PENALTY_QUOTIENT` for any validator with the given `index`. #### Justification and finalization @@ -1576,32 +1569,32 @@ Note: When applying penalties in the following balance recalculations implemente Case 1: `slots_since_finality <= 4 * EPOCH_LENGTH`: * Expected FFG source: - * Any [validator](#dfn-validator) `v` in `previous_epoch_justified_attesters` gains `adjust_for_inclusion_distance(base_reward(v) * previous_epoch_justified_attesting_balance // total_balance, inclusion_distance(v))`. - * Any [active validator](#dfn-active-validator) `v` not in `previous_epoch_justified_attesters` loses `base_reward(v)`. + * Any [validator](#dfn-validator) `index` in `previous_epoch_justified_attester_indices` gains `adjust_for_inclusion_distance(base_reward(v) * previous_epoch_justified_attesting_balance // total_balance, inclusion_distance(v))`. + * Any [active validator](#dfn-active-validator) `v` not in `previous_epoch_justified_attester_indices` loses `base_reward(v)`. * Expected FFG target: - * Any [validator](#dfn-validator) `v` in `previous_epoch_boundary_attesters` gains `adjust_for_inclusion_distance(base_reward(v) * previous_epoch_boundary_attesting_balance // total_balance, inclusion_distance(v))`. - * Any [active validator](#dfn-active-validator) `v` not in `previous_epoch_boundary_attesters` loses `base_reward(v)`. + * Any [validator](#dfn-validator) `index` in `previous_epoch_boundary_attester_indices` gains `adjust_for_inclusion_distance(base_reward(v) * previous_epoch_boundary_attesting_balance // total_balance, inclusion_distance(v))`. + * Any [active validator](#dfn-active-validator) `v` not in `previous_epoch_boundary_attester_indices` loses `base_reward(v)`. * Expected beacon chain head: - * Any [validator](#dfn-validator) `v` in `previous_epoch_head_attesters` gains `adjust_for_inclusion_distance(base_reward(v) * previous_epoch_head_attesting_balance // total_balance, inclusion_distance(v))`. - * Any [active validator](#dfn-active-validator) `v` not in `previous_epoch_head_attesters` loses `base_reward(v)`. + * Any [validator](#dfn-validator) `index` in `previous_epoch_head_attester_indices` gains `adjust_for_inclusion_distance(base_reward(v) * previous_epoch_head_attesting_balance // total_balance, inclusion_distance(v))`. + * Any [active validator](#dfn-active-validator) `v` not in `previous_epoch_head_attester_indices` loses `base_reward(v)`. Case 2: `slots_since_finality > 4 * EPOCH_LENGTH`: -* Any [active validator](#dfn-active-validator) `v` not in `previous_epoch_justified_attesters`, loses `inactivity_penalty(v, slots_since_finality)`. -* Any [active validator](#dfn-active-validator) `v` not in `previous_epoch_boundary_attesters`, loses `inactivity_penalty(v, slots_since_finality)`. -* Any [active validator](#dfn-active-validator) `v` not in `previous_epoch_head_attesters`, loses `inactivity_penalty(v, slots_since_finality)`. +* Any [active validator](#dfn-active-validator) `v` not in `previous_epoch_justified_attester_indices`, loses `inactivity_penalty(v, slots_since_finality)`. +* Any [active validator](#dfn-active-validator) `v` not in `previous_epoch_boundary_attester_indices`, loses `inactivity_penalty(v, slots_since_finality)`. +* Any [active validator](#dfn-active-validator) `v` not in `previous_epoch_head_attester_indices`, loses `inactivity_penalty(v, slots_since_finality)`. * Any [validator](#dfn-validator) with `status == EXITED_WITH_PENALTY`, loses `3 * inactivity_penalty(v, slots_since_finality)`. #### Attestation inclusion -For each `v` in `previous_epoch_attesters`, we determine the proposer `proposer_index = get_beacon_proposer_index(state, inclusion_slot(v))` and set `state.validator_registry[proposer_index].balance += base_reward(v) // INCLUDER_REWARD_QUOTIENT`. +For each `v` in `previous_epoch_attesters`, we determine the proposer `proposer_index = get_beacon_proposer_index(state, inclusion_slot(v))` and set `state.validator_balances[proposer_index] += base_reward(v) // INCLUDER_REWARD_QUOTIENT`. #### Crosslinks -For every `shard_committee` in `state.shard_committees_at_slots[:EPOCH_LENGTH]` (i.e. the objects corresponding to the epoch before the current one), for each `v` in `[state.validator_registry[index] for index in shard_committee.committee]`, adjust balances as follows: +For every `shard_committee` in `state.shard_committees_at_slots[:EPOCH_LENGTH]` (i.e. the objects corresponding to the epoch before the current one), for each `vindex` in `shard_committee.committee`, adjust balances as follows: -* If `v in attesting_validators(shard_committee)`, `v.balance += adjust_for_inclusion_distance(base_reward(v) * total_attesting_balance(shard_committee) // total_balance(shard_committee)), inclusion_distance(v))`. -* If `v not in attesting_validators(shard_committee)`, `v.balance -= base_reward(v)`. +* If `vindex in attesting_validators(shard_committee)`, `state.validator_balances[vindex] += adjust_for_inclusion_distance(base_reward(v) * total_attesting_balance(shard_committee) // total_balance(shard_committee)), inclusion_distance(v))`. +* If `vindex not in attesting_validators(shard_committee)`, `state.validator_balances[vindex] -= base_reward(v)`. ### Ejections @@ -1614,7 +1607,7 @@ def process_ejections(state: BeaconState) -> None: and eject active validators with balance below ``EJECTION_BALANCE``. """ for index in active_validator_indices(state.validator_registry): - if state.validator_registry[index].balance < EJECTION_BALANCE: + if state.validator_balances[index] < EJECTION_BALANCE: update_validator_status(state, index, new_status=EXITED_WITHOUT_PENALTY) ``` @@ -1647,9 +1640,9 @@ 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.status == PENDING_ACTIVATION and validator.balance >= MAX_DEPOSIT * GWEI_PER_ETH: + if validator.status == PENDING_ACTIVATION and state.validator_balances[index] >= MAX_DEPOSIT * GWEI_PER_ETH: # Check the balance churn would be within the allowance - balance_churn += get_effective_balance(validator) + balance_churn += get_effective_balance(state.validator_balances[index]) if balance_churn > max_balance_churn: break @@ -1661,7 +1654,7 @@ def update_validator_registry(state: BeaconState) -> None: for index, validator in enumerate(state.validator_registry): if validator.status == ACTIVE_PENDING_EXIT: # Check the balance churn would be within the allowance - balance_churn += get_effective_balance(validator) + balance_churn += get_effective_balance(state.validator_balances[index]) if balance_churn > max_balance_churn: break @@ -1678,11 +1671,11 @@ def update_validator_registry(state: BeaconState) -> None: ) # Calculate penalties for slashed validators - def to_penalize(v): - return v.status == EXITED_WITH_PENALTY - validators_to_penalize = filter(to_penalize, validator_registry) - for v in validators_to_penalize: - v.balance -= get_effective_balance(v) * min(total_penalties * 3, total_balance) // total_balance + def to_penalize(index): + return state.validator_registry[index].status == EXITED_WITH_PENALTY + validators_to_penalize = filter(to_penalize, range(len(validator_registry))) + for index in validators_to_penalize: + state.validator_balances[index] -= get_effective_balance(state.validator_balances[index]) * min(total_penalties * 3, total_balance) // total_balance return validator_registry, latest_penalized_exit_balances, validator_registry_delta_chain_tip ``` From 964395c362f90cfed2cda1224ea6587d01e8d80b Mon Sep 17 00:00:00 2001 From: vbuterin Date: Thu, 13 Dec 2018 19:40:00 -0500 Subject: [PATCH 05/19] Some bugfixes --- specs/core/0_beacon-chain.md | 48 +++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index d9859407c..d999b27e4 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1098,6 +1098,7 @@ def get_initial_beacon_state(initial_validator_deposits: List[Deposit], # Validator registry validator_registry=[], + validator_balances=[], validator_registry_latest_change_slot=INITIAL_SLOT_NUMBER, validator_registry_exit_count=0, validator_registry_delta_chain_tip=ZERO_HASH, @@ -1196,18 +1197,19 @@ def process_deposit(state: BeaconState, withdrawal_credentials=withdrawal_credentials, randao_commitment=randao_commitment, randao_layers=0, - balance=deposit, status=PENDING_ACTIVATION, latest_status_change_slot=state.slot, exit_count=0 ) - index = min_empty_validator_index(validators_copy) + index = min_empty_validator_index(state.validator_registry, state.validator_balances, state.slot) if index is None: state.validator_registry.append(validator) - index = len(validators_copy) - 1 + state.validator_balances.append(deposit) + index = len(state.validator_registry) - 1 else: state.validator_registry[index] = validator + state.validator_balances[index] = deposit else: # Increase balance by deposit index = validator_pubkeys.index(pubkey) @@ -1295,7 +1297,7 @@ def exit_validator(state: BeaconState, validator.latest_status_change_slot = state.slot if new_status == EXITED_WITH_PENALTY: - state.latest_penalized_exit_balances[state.slot // COLLECTIVE_PENALTY_CALCULATION_PERIOD] += get_effective_balance(validator) + state.latest_penalized_exit_balances[state.slot // COLLECTIVE_PENALTY_CALCULATION_PERIOD] += get_effective_balance(state.validator_balances[index]) whistleblower_index = get_beacon_proposer_index(state, state.slot) whistleblower_reward = state.validator_balances[index] // WHISTLEBLOWER_REWARD_QUOTIENT @@ -1511,8 +1513,8 @@ For every `shard_committee` in `state.shard_committees_at_slots`: * Let `attesting_validators(shard_committee)` be equal to `attesting_validators(shard_committee, winning_root(shard_committee))` for convenience. * Let `total_attesting_balance(shard_committee)` be the sum of the balances-at-stake of `attesting_validators(shard_committee)`. * Let `total_balance(shard_committee) = sum([get_effective_balance(state.validator_balances[i]) for i in shard_committee.committee])`. -* Let `inclusion_slot(v) = a.slot_included` for the attestation `a` where `v` is in `get_attestation_participants(state, a.data, a.participation_bitfield)`. -* Let `inclusion_distance(v) = a.slot_included - a.data.slot` where `a` is the above attestation. +* 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. * Let `adjust_for_inclusion_distance(magnitude, distance)` be the function below. ```python @@ -1557,8 +1559,8 @@ For every `shard_committee` in `state.shard_committees_at_slots`: First, we define some additional helpers: * Let `base_reward_quotient = BASE_REWARD_QUOTIENT * integer_squareroot(total_balance // GWEI_PER_ETH)`. -* Let `base_reward(index) = get_effective_balance(state.validator_balances[index]) // base_reward_quotient // 4` for any validator with the given `index`. -* Let `inactivity_penalty(index, slots_since_finality) = base_reward(index) + get_effective_balance(state.validator_balances[index]) * slots_since_finality // INACTIVITY_PENALTY_QUOTIENT` for any validator with the given `index`. +* Let `base_reward(state, index) = get_effective_balance(state.validator_balances[index]) // base_reward_quotient // 4` for any validator with the given `index`. +* Let `inactivity_penalty(state, index, slots_since_finality) = base_reward(state, index) + get_effective_balance(state.validator_balances[index]) * slots_since_finality // INACTIVITY_PENALTY_QUOTIENT` for any validator with the given `index`. #### Justification and finalization @@ -1569,32 +1571,32 @@ Note: When applying penalties in the following balance recalculations implemente Case 1: `slots_since_finality <= 4 * EPOCH_LENGTH`: * Expected FFG source: - * Any [validator](#dfn-validator) `index` in `previous_epoch_justified_attester_indices` gains `adjust_for_inclusion_distance(base_reward(v) * previous_epoch_justified_attesting_balance // total_balance, inclusion_distance(v))`. - * Any [active validator](#dfn-active-validator) `v` not in `previous_epoch_justified_attester_indices` loses `base_reward(v)`. + * Any [validator](#dfn-validator) `index` in `previous_epoch_justified_attester_indices` gains `adjust_for_inclusion_distance(base_reward(state, index) * previous_epoch_justified_attesting_balance // total_balance, inclusion_distance(state, index))`. + * Any [active validator](#dfn-active-validator) `v` not in `previous_epoch_justified_attester_indices` loses `base_reward(state, index)`. * Expected FFG target: - * Any [validator](#dfn-validator) `index` in `previous_epoch_boundary_attester_indices` gains `adjust_for_inclusion_distance(base_reward(v) * previous_epoch_boundary_attesting_balance // total_balance, inclusion_distance(v))`. - * Any [active validator](#dfn-active-validator) `v` not in `previous_epoch_boundary_attester_indices` loses `base_reward(v)`. + * Any [validator](#dfn-validator) `index` in `previous_epoch_boundary_attester_indices` gains `adjust_for_inclusion_distance(base_reward(state, index) * previous_epoch_boundary_attesting_balance // total_balance, inclusion_distance(state, index))`. + * Any [active validator](#dfn-active-validator) `index` not in `previous_epoch_boundary_attester_indices` loses `base_reward(state, index)`. * Expected beacon chain head: - * Any [validator](#dfn-validator) `index` in `previous_epoch_head_attester_indices` gains `adjust_for_inclusion_distance(base_reward(v) * previous_epoch_head_attesting_balance // total_balance, inclusion_distance(v))`. - * Any [active validator](#dfn-active-validator) `v` not in `previous_epoch_head_attester_indices` loses `base_reward(v)`. + * Any [validator](#dfn-validator) `index` in `previous_epoch_head_attester_indices` gains `adjust_for_inclusion_distance(base_reward(state, index) * previous_epoch_head_attesting_balance // total_balance, inclusion_distance(state, index))`. + * Any [active validator](#dfn-active-validator) `index` not in `previous_epoch_head_attester_indices` loses `base_reward(state, index)`. Case 2: `slots_since_finality > 4 * EPOCH_LENGTH`: -* Any [active validator](#dfn-active-validator) `v` not in `previous_epoch_justified_attester_indices`, loses `inactivity_penalty(v, slots_since_finality)`. -* Any [active validator](#dfn-active-validator) `v` not in `previous_epoch_boundary_attester_indices`, loses `inactivity_penalty(v, slots_since_finality)`. -* Any [active validator](#dfn-active-validator) `v` not in `previous_epoch_head_attester_indices`, loses `inactivity_penalty(v, slots_since_finality)`. -* Any [validator](#dfn-validator) with `status == EXITED_WITH_PENALTY`, loses `3 * inactivity_penalty(v, slots_since_finality)`. +* Any [active validator](#dfn-active-validator) `index` not in `previous_epoch_justified_attester_indices`, loses `inactivity_penalty(state, index, slots_since_finality)`. +* Any [active validator](#dfn-active-validator) `index` not in `previous_epoch_boundary_attester_indices`, loses `inactivity_penalty(state, index, slots_since_finality)`. +* Any [active validator](#dfn-active-validator) `index` not in `previous_epoch_head_attester_indices`, loses `inactivity_penalty(state, index, slots_since_finality)`. +* Any [validator](#dfn-validator) `index` with `status == EXITED_WITH_PENALTY`, loses `3 * inactivity_penalty(state, index, slots_since_finality)`. #### Attestation inclusion -For each `v` in `previous_epoch_attesters`, we determine the proposer `proposer_index = get_beacon_proposer_index(state, inclusion_slot(v))` and set `state.validator_balances[proposer_index] += base_reward(v) // INCLUDER_REWARD_QUOTIENT`. +For each `index` in `previous_epoch_attester_indices`, we determine the proposer `proposer_index = get_beacon_proposer_index(state, inclusion_slot(state, index))` and set `state.validator_balances[proposer_index] += base_reward(state, index) // INCLUDER_REWARD_QUOTIENT`. #### Crosslinks -For every `shard_committee` in `state.shard_committees_at_slots[:EPOCH_LENGTH]` (i.e. the objects corresponding to the epoch before the current one), for each `vindex` in `shard_committee.committee`, adjust balances as follows: +For every `shard_committee` in `state.shard_committees_at_slots[:EPOCH_LENGTH]` (i.e. the objects corresponding to the epoch before the current one), for each `index` in `shard_committee.committee`, adjust balances as follows: -* If `vindex in attesting_validators(shard_committee)`, `state.validator_balances[vindex] += adjust_for_inclusion_distance(base_reward(v) * total_attesting_balance(shard_committee) // total_balance(shard_committee)), inclusion_distance(v))`. -* If `vindex not in attesting_validators(shard_committee)`, `state.validator_balances[vindex] -= base_reward(v)`. +* If `index in attesting_validators(shard_committee)`, `state.validator_balances[index] += adjust_for_inclusion_distance(base_reward(state, index) * total_attesting_balance(shard_committee) // total_balance(shard_committee)), inclusion_distance(state, index))`. +* If `index not in attesting_validators(shard_committee)`, `state.validator_balances[index] -= base_reward(state, index)`. ### Ejections @@ -1629,7 +1631,7 @@ def update_validator_registry(state: BeaconState) -> None: # The active validators active_validator_indices = get_active_validator_indices(state.validator_registry) # The total effective balance of active validators - total_balance = sum([get_effective_balance(v) for i, v in enumerate(validator_registry) if i in active_validator_indices]) + total_balance = sum([get_effective_balance(state.validator_blances[i]) for i in active_validator_indices]) # The maximum balance churn in Gwei (for deposits and exits separately) max_balance_churn = max( From 416bbf9ceab00cdcecc955e5b712e0b32adcc8ea Mon Sep 17 00:00:00 2001 From: vbuterin Date: Mon, 17 Dec 2018 04:40:27 -0500 Subject: [PATCH 06/19] Edit latest_block_roots in place instead of as a queue Faster editing that way; otherwise every block will require completely reconstructing a 8192-sized Merkle tree. --- 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 d999b27e4..7718a906e 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1337,7 +1337,7 @@ Below are the processing steps that happen at every slot. ### Block roots * Let `previous_block_root` be the `tree_hash_root` of the previous beacon block processed in the chain. -* Set `state.latest_block_roots = state.latest_block_roots[1:] + [previous_block_root]`. +* Set `state.latest_block_roots[(state.slot - 1) % LATEST_BLOCK_ROOTS_LENGTH] = previous_block_root`. * If `state.slot % LATEST_BLOCK_ROOTS_LENGTH == 0` append `merkle_root(state.latest_block_roots)` to `state.batched_block_roots`. ## Per-block processing From e9f986971ed1d990a3954ad576165ee909cd5837 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Mon, 17 Dec 2018 09:08:13 -0500 Subject: [PATCH 07/19] 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 7718a906e..e2553e498 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -957,7 +957,7 @@ def get_attestation_participants(state: BeaconState, ```python def get_effective_balance(balance: int) -> int: """ - Returns the effective balance (also known as "balance at stake") for a ``validator`` with the given balance. + Returns the effective balance (also known as "balance at stake") for a ``validator`` with the given ``validator_index``. """ return min(balance, MAX_DEPOSIT * GWEI_PER_ETH) ``` From c0d65cc334c58b082084e5629902ff3d3d769005 Mon Sep 17 00:00:00 2001 From: vbuterin Date: Mon, 17 Dec 2018 09:10:44 -0500 Subject: [PATCH 08/19] Changed get_effective_balance definition to use state+index --- specs/core/0_beacon-chain.md | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index e2553e498..1b267fa84 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -955,11 +955,11 @@ def get_attestation_participants(state: BeaconState, #### `get_effective_balance` ```python -def get_effective_balance(balance: int) -> int: +def get_effective_balance(state: State, index: int) -> int: """ Returns the effective balance (also known as "balance at stake") for a ``validator`` with the given ``validator_index``. """ - return min(balance, MAX_DEPOSIT * GWEI_PER_ETH) + return min(state.validator_balances[index], MAX_DEPOSIT * GWEI_PER_ETH) ``` #### `get_new_validator_registry_delta_chain_tip` @@ -1297,7 +1297,7 @@ def exit_validator(state: BeaconState, validator.latest_status_change_slot = state.slot if new_status == EXITED_WITH_PENALTY: - state.latest_penalized_exit_balances[state.slot // COLLECTIVE_PENALTY_CALCULATION_PERIOD] += get_effective_balance(state.validator_balances[index]) + state.latest_penalized_exit_balances[state.slot // COLLECTIVE_PENALTY_CALCULATION_PERIOD] += get_effective_balance(state, index) whistleblower_index = get_beacon_proposer_index(state, state.slot) whistleblower_reward = state.validator_balances[index] // WHISTLEBLOWER_REWARD_QUOTIENT @@ -1476,7 +1476,7 @@ The steps below happen when `state.slot % EPOCH_LENGTH == 0`. All [validators](#dfn-validator): * Let `active_validator_indices = get_active_validator_indices(state.validator_registry)`. -* Let `total_balance = sum([get_effective_balance(state.validator_balances[i]) for i in active_validator_indices])`. +* Let `total_balance = sum([get_effective_balance(state, i) for i in active_validator_indices])`. [Validators](#dfn-Validator) attesting during the current epoch: @@ -1486,7 +1486,7 @@ All [validators](#dfn-validator): * Let `this_epoch_boundary_attestations = [a for a in this_epoch_attestations if a.data.epoch_boundary_root == get_block_root(state, state.slot-EPOCH_LENGTH) and a.justified_slot == state.justified_slot]`. * Let `this_epoch_boundary_attester_indices` be the union of the [validator](#dfn-validator) index sets given by `[get_attestation_participants(state, a.data, a.participation_bitfield) for a in this_epoch_boundary_attestations]`. - * Let `this_epoch_boundary_attesting_balance = sum([get_effective_balance(state.validator_balances[i]) for v in this_epoch_boundary_attester_indices])`. + * Let `this_epoch_boundary_attesting_balance = sum([get_effective_balance(state, i) for v in this_epoch_boundary_attester_indices])`. [Validators](#dfn-Validator) attesting during the previous epoch: @@ -1496,23 +1496,23 @@ All [validators](#dfn-validator): * Validators targeting the previous justified hash: * Let `previous_epoch_justified_attestations = [a for a in this_epoch_attestations + previous_epoch_attestations if a.justified_slot == state.previous_justified_slot]`. * Let `previous_epoch_justified_attester_indices` be the union of the validator index sets given by `[get_attestation_participants(state, a.data, a.participation_bitfield) for a in previous_epoch_justified_attestations]`. - * Let `previous_epoch_justified_attesting_balance = sum([get_effective_balance(state.validator_balances[i]) for v in previous_epoch_justified_attester_indices])`. + * Let `previous_epoch_justified_attesting_balance = sum([get_effective_balance(state, i) for v in previous_epoch_justified_attester_indices])`. * Validators justifying the epoch boundary block at the start of the previous epoch: * Let `previous_epoch_boundary_attestations = [a for a in previous_epoch_justified_attestations if a.epoch_boundary_root == get_block_root(state, state.slot - 2 * EPOCH_LENGTH)]`. * Let `previous_epoch_boundary_attester_indices` be the union of the validator index sets given by `[get_attestation_participants(state, a.data, a.participation_bitfield) for a in previous_epoch_boundary_attestations]`. - * Let `previous_epoch_boundary_attesting_balance = sum([get_effective_balance(state.validator_balances[i]) for v in previous_epoch_boundary_attester_indices])`. + * Let `previous_epoch_boundary_attesting_balance = sum([get_effective_balance(state, i) for v in previous_epoch_boundary_attester_indices])`. * Validators attesting to the expected beacon chain head during the previous epoch: * Let `previous_epoch_head_attestations = [a for a in previous_epoch_attestations if a.beacon_block_root == get_block_root(state, a.slot)]`. * Let `previous_epoch_head_attester_indices` be the union of the validator index sets given by `[get_attestation_participants(state, a.data, a.participation_bitfield) for a in previous_epoch_head_attestations]`. - * Let `previous_epoch_head_attesting_balance = sum([get_effective_balance(state.validator_balances[i]) for v in previous_epoch_head_attester_indices])`. + * Let `previous_epoch_head_attesting_balance = sum([get_effective_balance(state, i) for v in previous_epoch_head_attester_indices])`. For every `shard_committee` in `state.shard_committees_at_slots`: * 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 this_epoch_attestations + previous_epoch_attestations if a.shard == shard_committee.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.validator_balances[i]) for i in attesting_validator_indices(shard_committee, shard_block_root)])` is maximized (ties broken by favoring lower `shard_block_root` values). +* 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_validators(shard_committee, winning_root(shard_committee))` for convenience. * Let `total_attesting_balance(shard_committee)` be the sum of the balances-at-stake of `attesting_validators(shard_committee)`. -* Let `total_balance(shard_committee) = sum([get_effective_balance(state.validator_balances[i]) for i in shard_committee.committee])`. +* Let `total_balance(shard_committee) = sum([get_effective_balance(state, i) for i in shard_committee.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. * Let `adjust_for_inclusion_distance(magnitude, distance)` be the function below. @@ -1559,8 +1559,8 @@ For every `shard_committee` in `state.shard_committees_at_slots`: First, we define some additional helpers: * Let `base_reward_quotient = BASE_REWARD_QUOTIENT * integer_squareroot(total_balance // GWEI_PER_ETH)`. -* Let `base_reward(state, index) = get_effective_balance(state.validator_balances[index]) // base_reward_quotient // 4` for any validator with the given `index`. -* Let `inactivity_penalty(state, index, slots_since_finality) = base_reward(state, index) + get_effective_balance(state.validator_balances[index]) * slots_since_finality // INACTIVITY_PENALTY_QUOTIENT` for any validator with the given `index`. +* Let `base_reward(state, index) = get_effective_balance(state, index) // base_reward_quotient // 4` for any validator with the given `index`. +* Let `inactivity_penalty(state, index, slots_since_finality) = base_reward(state, index) + get_effective_balance(state, index) * slots_since_finality // INACTIVITY_PENALTY_QUOTIENT` for any validator with the given `index`. #### Justification and finalization @@ -1631,7 +1631,7 @@ def update_validator_registry(state: BeaconState) -> None: # The active validators active_validator_indices = get_active_validator_indices(state.validator_registry) # The total effective balance of active validators - total_balance = sum([get_effective_balance(state.validator_blances[i]) for i in active_validator_indices]) + total_balance = sum([get_effective_balance(state, i) for i in active_validator_indices]) # The maximum balance churn in Gwei (for deposits and exits separately) max_balance_churn = max( @@ -1644,7 +1644,7 @@ def update_validator_registry(state: BeaconState) -> None: for index, validator in enumerate(state.validator_registry): if validator.status == PENDING_ACTIVATION and state.validator_balances[index] >= MAX_DEPOSIT * GWEI_PER_ETH: # Check the balance churn would be within the allowance - balance_churn += get_effective_balance(state.validator_balances[index]) + balance_churn += get_effective_balance(state, index) if balance_churn > max_balance_churn: break @@ -1656,7 +1656,7 @@ def update_validator_registry(state: BeaconState) -> None: for index, validator in enumerate(state.validator_registry): if validator.status == ACTIVE_PENDING_EXIT: # Check the balance churn would be within the allowance - balance_churn += get_effective_balance(state.validator_balances[index]) + balance_churn += get_effective_balance(state, index) if balance_churn > max_balance_churn: break @@ -1677,7 +1677,7 @@ def update_validator_registry(state: BeaconState) -> None: return state.validator_registry[index].status == EXITED_WITH_PENALTY validators_to_penalize = filter(to_penalize, range(len(validator_registry))) for index in validators_to_penalize: - state.validator_balances[index] -= get_effective_balance(state.validator_balances[index]) * min(total_penalties * 3, total_balance) // total_balance + state.validator_balances[index] -= get_effective_balance(state, index) * min(total_penalties * 3, total_balance) // total_balance return validator_registry, latest_penalized_exit_balances, validator_registry_delta_chain_tip ``` From eccfc912b598f17f9c6af17acaffe2bfaf1da2a1 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Mon, 17 Dec 2018 09:11:39 -0500 Subject: [PATCH 09/19] 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 1b267fa84..5c6b065d5 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1138,7 +1138,7 @@ def get_initial_beacon_state(initial_validator_deposits: List[Deposit], withdrawal_credentials=deposit.deposit_data.deposit_input.withdrawal_credentials, randao_commitment=deposit.deposit_data.deposit_input.randao_commitment ) - if state.validator_balances[index] >= MAX_DEPOSIT * GWEI_PER_ETH: + if get_effective_balance(state, validator_index) == MAX_DEPOSIT * GWEI_PER_ETH: update_validator_status(state, index, ACTIVE) # set initial committee shuffling From b402a7c1d680cf70330318bde11de4e9dc934c6f Mon Sep 17 00:00:00 2001 From: vbuterin Date: Mon, 17 Dec 2018 09:12:51 -0500 Subject: [PATCH 10/19] Made a function multiline --- specs/core/0_beacon-chain.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 5c6b065d5..73f91b504 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1157,7 +1157,9 @@ def get_initial_beacon_state(initial_validator_deposits: List[Deposit], First, a helper function: ```python -def min_empty_validator_index(validators: List[ValidatorRecord], validator_balances: List[int], current_slot: int) -> int: +def min_empty_validator_index(validators: List[ValidatorRecord], + validator_balances: List[int], + current_slot: int) -> int: for i, (v, vbal) in enumerate(zip(validators, validator_balances)): if vbal == 0 and v.latest_status_change_slot + ZERO_BALANCE_VALIDATOR_TTL <= current_slot: return i From fbabeff83804fdec987fe06889f056afa25d0781 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Mon, 17 Dec 2018 10:40:21 -0500 Subject: [PATCH 11/19] 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 73f91b504..33324dcb7 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1488,7 +1488,7 @@ All [validators](#dfn-validator): * Let `this_epoch_boundary_attestations = [a for a in this_epoch_attestations if a.data.epoch_boundary_root == get_block_root(state, state.slot-EPOCH_LENGTH) and a.justified_slot == state.justified_slot]`. * Let `this_epoch_boundary_attester_indices` be the union of the [validator](#dfn-validator) index sets given by `[get_attestation_participants(state, a.data, a.participation_bitfield) for a in this_epoch_boundary_attestations]`. - * Let `this_epoch_boundary_attesting_balance = sum([get_effective_balance(state, i) for v in this_epoch_boundary_attester_indices])`. + * Let `this_epoch_boundary_attesting_balance = sum([get_effective_balance(state, i) for i in this_epoch_boundary_attester_indices])`. [Validators](#dfn-Validator) attesting during the previous epoch: From 110fe75a700032f2d90695fe7749e4ef06cdd9e1 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Mon, 17 Dec 2018 10:40:31 -0500 Subject: [PATCH 12/19] 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 33324dcb7..7a88427b2 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1502,7 +1502,7 @@ All [validators](#dfn-validator): * Validators justifying the epoch boundary block at the start of the previous epoch: * Let `previous_epoch_boundary_attestations = [a for a in previous_epoch_justified_attestations if a.epoch_boundary_root == get_block_root(state, state.slot - 2 * EPOCH_LENGTH)]`. * Let `previous_epoch_boundary_attester_indices` be the union of the validator index sets given by `[get_attestation_participants(state, a.data, a.participation_bitfield) for a in previous_epoch_boundary_attestations]`. - * Let `previous_epoch_boundary_attesting_balance = sum([get_effective_balance(state, i) for v in previous_epoch_boundary_attester_indices])`. + * Let `previous_epoch_boundary_attesting_balance = sum([get_effective_balance(state, i) for i in previous_epoch_boundary_attester_indices])`. * Validators attesting to the expected beacon chain head during the previous epoch: * Let `previous_epoch_head_attestations = [a for a in previous_epoch_attestations if a.beacon_block_root == get_block_root(state, a.slot)]`. * Let `previous_epoch_head_attester_indices` be the union of the validator index sets given by `[get_attestation_participants(state, a.data, a.participation_bitfield) for a in previous_epoch_head_attestations]`. From 2c48bab3d8383980403014ce090ce6167fd2def7 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Mon, 17 Dec 2018 10:40:41 -0500 Subject: [PATCH 13/19] 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 7a88427b2..6c597c355 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1506,7 +1506,7 @@ All [validators](#dfn-validator): * Validators attesting to the expected beacon chain head during the previous epoch: * Let `previous_epoch_head_attestations = [a for a in previous_epoch_attestations if a.beacon_block_root == get_block_root(state, a.slot)]`. * Let `previous_epoch_head_attester_indices` be the union of the validator index sets given by `[get_attestation_participants(state, a.data, a.participation_bitfield) for a in previous_epoch_head_attestations]`. - * Let `previous_epoch_head_attesting_balance = sum([get_effective_balance(state, i) for v in previous_epoch_head_attester_indices])`. + * Let `previous_epoch_head_attesting_balance = sum([get_effective_balance(state, i) for i in previous_epoch_head_attester_indices])`. For every `shard_committee` in `state.shard_committees_at_slots`: From 7f66f06871a28f0d01a5ae706cf0400785306a1b Mon Sep 17 00:00:00 2001 From: vbuterin Date: Mon, 17 Dec 2018 10:43:05 -0500 Subject: [PATCH 14/19] Fixed one more outdated-style balance query --- 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 71a829adb..67fe2c7eb 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1349,7 +1349,7 @@ def exit_validator(state: BeaconState, state.latest_penalized_exit_balances[state.slot // COLLECTIVE_PENALTY_CALCULATION_PERIOD] += get_effective_balance(state, index) whistleblower_index = get_beacon_proposer_index(state, state.slot) - whistleblower_reward = state.validator_balances[index] // WHISTLEBLOWER_REWARD_QUOTIENT + whistleblower_reward = get_effective_balance(state, index) // WHISTLEBLOWER_REWARD_QUOTIENT state.validator_balances[whistleblower_index] += whistleblower_reward state.validator_balances[index] -= whistleblower_reward From d505aa28fe4a3c258fe7be835a394367cd34b94a Mon Sep 17 00:00:00 2001 From: Dan Burnett Date: Mon, 17 Dec 2018 15:15:37 -0500 Subject: [PATCH 15/19] make Casper FFG normative --- specs/core/0_beacon-chain.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 3c2259559..57442748f 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -147,7 +147,7 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted * **Crosslink** - a set of signatures from a committee attesting to a block in a shard chain, which can be included into the beacon chain. Crosslinks are the main means by which the beacon chain "learns about" the updated state of shard chains. * **Slot** - a period of `SLOT_DURATION` seconds, during which one proposer has the ability to create a beacon chain block and some attesters have the ability to make attestations * **Epoch** - an aligned span of slots during which all [validators](#dfn-validator) get exactly one chance to make an attestation -* **Finalized**, **justified** - see Casper FFG finalization here: https://arxiv.org/abs/1710.09437 +* **Finalized**, **justified** - see Casper FFG finalization [[casper-ffg]](#ref-casper-ffg) * **Withdrawal period** - the number of slots between a [validator](#dfn-validator) exit and the [validator](#dfn-validator) balance being withdrawable * **Genesis time** - the Unix time of the genesis beacon chain block at slot 0 @@ -1790,6 +1790,8 @@ Verify `block.state_root == hash_tree_root(state)` if there exists a `block` for This section is divided into Normative and Informative references. Normative references are those that must be read in order to implement this specification, while Informative references are merely that, information. An example of the former might be the details of a required consensus algorithm, and an example of the latter might be a pointer to research that demonstrates why a particular consensus algorithm might be better suited for inclusion in the standard than another. ## Normative + _**casper-ffg**_ +   _Casper the Friendly Finality Gadget_. V. Buterin and V. Griffith. URL: https://arxiv.org/abs/1710.09437 ## Informative _**python-poc**_ From cc4e0660293d8b4564b23eb93c04dd08129f996a Mon Sep 17 00:00:00 2001 From: Dan Burnett Date: Mon, 17 Dec 2018 15:19:58 -0500 Subject: [PATCH 16/19] formatting change --- 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 57442748f..ac2d4ba86 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1790,11 +1790,11 @@ Verify `block.state_root == hash_tree_root(state)` if there exists a `block` for This section is divided into Normative and Informative references. Normative references are those that must be read in order to implement this specification, while Informative references are merely that, information. An example of the former might be the details of a required consensus algorithm, and an example of the latter might be a pointer to research that demonstrates why a particular consensus algorithm might be better suited for inclusion in the standard than another. ## Normative - _**casper-ffg**_ + _**casper-ffg**_   _Casper the Friendly Finality Gadget_. V. Buterin and V. Griffith. URL: https://arxiv.org/abs/1710.09437 ## Informative - _**python-poc**_ + _**python-poc**_   _Python proof-of-concept implementation_. Ethereum Foundation. URL: https://github.com/ethereum/beacon_chain # Copyright From 5a0d8c8f424ccbb2cf529ccef2538d4ee153f547 Mon Sep 17 00:00:00 2001 From: Dan Burnett Date: Tue, 18 Dec 2018 09:41:59 -0500 Subject: [PATCH 17/19] move to Informative --- specs/core/0_beacon-chain.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index ac2d4ba86..7dde677b9 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1790,10 +1790,11 @@ Verify `block.state_root == hash_tree_root(state)` if there exists a `block` for This section is divided into Normative and Informative references. Normative references are those that must be read in order to implement this specification, while Informative references are merely that, information. An example of the former might be the details of a required consensus algorithm, and an example of the latter might be a pointer to research that demonstrates why a particular consensus algorithm might be better suited for inclusion in the standard than another. ## Normative + +## Informative _**casper-ffg**_   _Casper the Friendly Finality Gadget_. V. Buterin and V. Griffith. URL: https://arxiv.org/abs/1710.09437 -## Informative _**python-poc**_   _Python proof-of-concept implementation_. Ethereum Foundation. URL: https://github.com/ethereum/beacon_chain From 5943fd507fb231687a70de0ddb3b8f6aec023eac Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Tue, 18 Dec 2018 12:27:33 -0600 Subject: [PATCH 18/19] fix remaining index error --- 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 67fe2c7eb..e94268388 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1547,7 +1547,7 @@ All [validators](#dfn-validator): * Validators targeting the previous justified hash: * Let `previous_epoch_justified_attestations = [a for a in this_epoch_attestations + previous_epoch_attestations if a.justified_slot == state.previous_justified_slot]`. * Let `previous_epoch_justified_attester_indices` be the union of the validator index sets given by `[get_attestation_participants(state, a.data, a.participation_bitfield) for a in previous_epoch_justified_attestations]`. - * Let `previous_epoch_justified_attesting_balance = sum([get_effective_balance(state, i) for v in previous_epoch_justified_attester_indices])`. + * Let `previous_epoch_justified_attesting_balance = sum([get_effective_balance(state, i) for i in previous_epoch_justified_attester_indices])`. * Validators justifying the epoch boundary block at the start of the previous epoch: * Let `previous_epoch_boundary_attestations = [a for a in previous_epoch_justified_attestations if a.epoch_boundary_root == get_block_root(state, state.slot - 2 * EPOCH_LENGTH)]`. * Let `previous_epoch_boundary_attester_indices` be the union of the validator index sets given by `[get_attestation_participants(state, a.data, a.participation_bitfield) for a in previous_epoch_boundary_attestations]`. From f7afd679dadf6dc083c34543309ce7b9b71acfd6 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Tue, 18 Dec 2018 12:37:25 -0600 Subject: [PATCH 19/19] fix comment --- 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 e94268388..ffe584bf8 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -964,7 +964,7 @@ def get_attestation_participants(state: BeaconState, ```python def get_effective_balance(state: State, index: int) -> int: """ - Returns the effective balance (also known as "balance at stake") for a ``validator`` with the given ``validator_index``. + Returns the effective balance (also known as "balance at stake") for a ``validator`` with the given ``index``. """ return min(state.validator_balances[index], MAX_DEPOSIT * GWEI_PER_ETH) ```