From befc3498783c62b99cc395d6ea5c0d785d96afaf Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Tue, 11 Dec 2018 11:14:42 -0600 Subject: [PATCH 01/30] 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/30] 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/30] 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 add628d26bcb0b55d7f1a4b4c3031f4241922c66 Mon Sep 17 00:00:00 2001 From: vbuterin Date: Thu, 13 Dec 2018 19:06:07 -0500 Subject: [PATCH 04/30] Edit BLS spec as per issue #300 See https://github.com/ethereum/eth2.0-specs/issues/300 --- specs/{bls_verify.md => bls_signature.md} | 10 ++++++++++ 1 file changed, 10 insertions(+) rename specs/{bls_verify.md => bls_signature.md} (91%) diff --git a/specs/bls_verify.md b/specs/bls_signature.md similarity index 91% rename from specs/bls_verify.md rename to specs/bls_signature.md index a6c41e555..47f7b69c0 100644 --- a/specs/bls_verify.md +++ b/specs/bls_signature.md @@ -117,6 +117,16 @@ Let `bls_verify(pubkey: uint384, message: bytes32, signature: [uint384], domain: * Verify that `signature` is a valid G2 point. * Verify that `e(pubkey, hash_to_G2(message, domain)) == e(g, signature)`. +## Operations involving aggregate signatures + +### `bls_aggregate_pubkeys` + +Let `bls_aggregate_pubkeys(pubkeys: [uint384]) -> uint384` return `pubkeys[0] + .... + pubkeys[len(pubkeys)-1]`, where `+` is the elliptic curve addition operation over the G1 curve. + +### `bls_aggregate_signatures` + +Let `bls_aggregate_signatures(signatures: [[uint384]]) -> [uint384]` return `signatures[0] + .... + signatures[len(signatures)-1]`, where `+` is the elliptic curve addition operation over the G2 curve. + ### `bls_verify_multiple` Let `bls_verify_multiple(pubkeys: [uint384], messages: [bytes32], signature: [uint384], domain: uint64) -> bool`: From 2b9a0e999c60f7f466801f91b1eabcf3d00ba3a7 Mon Sep 17 00:00:00 2001 From: vbuterin Date: Thu, 13 Dec 2018 19:28:59 -0500 Subject: [PATCH 05/30] 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 06/30] 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 7b4c4f299da3ce19ec84f2344ada723ea4a5d4a9 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 14 Dec 2018 09:39:14 -0600 Subject: [PATCH 07/30] add bls_aggregate_pubkeys ref in beacon chain spec --- specs/core/0_beacon-chain.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 198c4872a..f6ee34c01 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -84,6 +84,7 @@ - [`integer_squareroot`](#integer_squareroot) - [`bls_verify`](#bls_verify) - [`bls_verify_multiple`](#bls_verify_multiple) + - [`bls_aggregate_pubkeys`](#bls_aggregate_pubkeys) - [On startup](#on-startup) - [Routine for processing deposits](#routine-for-processing-deposits) - [Routine for updating validator status](#routine-for-updating-validator-status) @@ -1104,11 +1105,15 @@ def integer_squareroot(n: int) -> int: #### `bls_verify` -`bls_verify` is a function for verifying a BLS12-381 signature, defined in the [BLS Verification spec](https://github.com/ethereum/eth2.0-specs/blob/master/specs/bls_verify.md#bls_verify). +`bls_verify` is a function for verifying a BLS12-381 signature, defined in the [BLS Signature spec](https://github.com/ethereum/eth2.0-specs/blob/master/specs/bls_signature.md#bls_verify). #### `bls_verify_multiple` -`bls_verify_multiple` is a function for verifying a BLS12-381 signature constructed from multiple messages, defined in the [BLS Verification spec](https://github.com/ethereum/eth2.0-specs/blob/master/specs/bls_verify.md#bls_verify_multiple). +`bls_verify_multiple` is a function for verifying a BLS12-381 signature constructed from multiple messages, defined in the [BLS Signature spec](https://github.com/ethereum/eth2.0-specs/blob/master/specs/bls_signature.md#bls_verify_multiple). + +#### `bls_aggregate_pubkeys` + +`bls_aggregate_pubkeys` is a function for aggregating a BLS12-381 public keys into a single aggregate key, defined in the [BLS Signature spec](https://github.com/ethereum/eth2.0-specs/blob/master/specs/bls_signature.md#bls_aggregate_pubkeys). ### On startup @@ -1473,7 +1478,7 @@ For each `attestation` in `block.body.attestations`: * Verify that either `attestation.data.latest_crosslink_root` or `attestation.data.shard_block_root` equals `state.latest_crosslinks[shard].shard_block_root`. * `aggregate_signature` verification: * Let `participants = get_attestation_participants(state, attestation.data, attestation.participation_bitfield)`. - * Let `group_public_key = BLSAddPubkeys([state.validator_registry[v].pubkey for v in participants])`. + * Let `group_public_key = bls_aggregate_pubkeys([state.validator_registry[v].pubkey for v in participants])`. * Verify that `bls_verify(pubkey=group_public_key, message=hash_tree_root(attestation.data) + bytes1(0), signature=attestation.aggregate_signature, domain=get_domain(state.fork_data, attestation.data.slot, DOMAIN_ATTESTATION))`. * [TO BE REMOVED IN PHASE 1] Verify that `attestation.data.shard_block_root == ZERO_HASH`. * Append `PendingAttestationRecord(data=attestation.data, participation_bitfield=attestation.participation_bitfield, custody_bitfield=attestation.custody_bitfield, slot_included=state.slot)` to `state.latest_attestations`. From 829911c0fdd0d2337fda320a6c333ae053eaa3d0 Mon Sep 17 00:00:00 2001 From: vbuterin Date: Fri, 14 Dec 2018 19:55:05 -0500 Subject: [PATCH 08/30] Swapped order of aggregate and verify --- specs/bls_signature.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/specs/bls_signature.md b/specs/bls_signature.md index 47f7b69c0..394d6bbc3 100644 --- a/specs/bls_signature.md +++ b/specs/bls_signature.md @@ -99,6 +99,16 @@ def modular_squareroot(value: int) -> int: return None ``` +## Operations involving asignature aggregation + +### `bls_aggregate_pubkeys` + +Let `bls_aggregate_pubkeys(pubkeys: [uint384]) -> uint384` return `pubkeys[0] + .... + pubkeys[len(pubkeys)-1]`, where `+` is the elliptic curve addition operation over the G1 curve. + +### `bls_aggregate_signatures` + +Let `bls_aggregate_signatures(signatures: [[uint384]]) -> [uint384]` return `signatures[0] + .... + signatures[len(signatures)-1]`, where `+` is the elliptic curve addition operation over the G2 curve. + ## Signature verification In the following `e` is the pairing function and `g` is the G1 generator with the following coordinates (see [here](https://github.com/zkcrypto/pairing/tree/master/src/bls12_381#g1)): @@ -117,16 +127,6 @@ Let `bls_verify(pubkey: uint384, message: bytes32, signature: [uint384], domain: * Verify that `signature` is a valid G2 point. * Verify that `e(pubkey, hash_to_G2(message, domain)) == e(g, signature)`. -## Operations involving aggregate signatures - -### `bls_aggregate_pubkeys` - -Let `bls_aggregate_pubkeys(pubkeys: [uint384]) -> uint384` return `pubkeys[0] + .... + pubkeys[len(pubkeys)-1]`, where `+` is the elliptic curve addition operation over the G1 curve. - -### `bls_aggregate_signatures` - -Let `bls_aggregate_signatures(signatures: [[uint384]]) -> [uint384]` return `signatures[0] + .... + signatures[len(signatures)-1]`, where `+` is the elliptic curve addition operation over the G2 curve. - ### `bls_verify_multiple` Let `bls_verify_multiple(pubkeys: [uint384], messages: [bytes32], signature: [uint384], domain: uint64) -> bool`: From f09a1fa4f5bd524b2f64fafa2d727ae10e067e77 Mon Sep 17 00:00:00 2001 From: vbuterin Date: Sat, 15 Dec 2018 03:25:25 -0500 Subject: [PATCH 09/30] Add pointers to explanatory materials in readme. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fd8748d5e..1182ff637 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Ethereum 2.0 Specifications -[![Join the chat at https://gitter.im/ethereum/sharding](https://badges.gitter.im/ethereum/sharding.svg)](https://gitter.im/ethereum/sharding?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![Join the chat at https://gitter.im/ethereum/sharding](https://badges.gitter.im/ethereum/sharding.svg)](https://gitter.im/ethereum/sharding?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge). To learn more about sharding and eth2.0/Serenity, see the [sharding FAQ](https://github.com/ethereum/wiki/wiki/Sharding-FAQs) and the [research compendium](https://notes.ethereum.org/oa8wCimaTPGBl2nHuBTXWQ). This repo hosts the current eth2.0 specifications. Discussions about design rationale and proposed changes can be brought up and discussed as issues. Solidified, agreed upon changes to spec can be made through pull requests. From 3dc37d258e8f26513f3e837fe343faba74ea4d15 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Sat, 15 Dec 2018 04:59:18 -0500 Subject: [PATCH 10/30] Update README.md Co-Authored-By: vbuterin --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1182ff637..25d9abe83 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Ethereum 2.0 Specifications -[![Join the chat at https://gitter.im/ethereum/sharding](https://badges.gitter.im/ethereum/sharding.svg)](https://gitter.im/ethereum/sharding?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge). To learn more about sharding and eth2.0/Serenity, see the [sharding FAQ](https://github.com/ethereum/wiki/wiki/Sharding-FAQs) and the [research compendium](https://notes.ethereum.org/oa8wCimaTPGBl2nHuBTXWQ). +[![Join the chat at https://gitter.im/ethereum/sharding](https://badges.gitter.im/ethereum/sharding.svg)](https://gitter.im/ethereum/sharding?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge). +To learn more about sharding and eth2.0/Serenity, see the [sharding FAQ](https://github.com/ethereum/wiki/wiki/Sharding-FAQs) and the [research compendium](https://notes.ethereum.org/s/H1PGqDhpm). This repo hosts the current eth2.0 specifications. Discussions about design rationale and proposed changes can be brought up and discussed as issues. Solidified, agreed upon changes to spec can be made through pull requests. From 9e6c1a6244a60e678d4738f20d90a8552a9329ca Mon Sep 17 00:00:00 2001 From: vbuterin Date: Sat, 15 Dec 2018 06:44:18 -0500 Subject: [PATCH 11/30] Remove clamp Removed the use of `clamp` from the spec, as there's no point in a helper function that's used exactly once; it only increases the amount people have to jump around the spec to understand what's going on. --- specs/core/0_beacon-chain.md | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 2097f6a0e..7623eae70 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -65,7 +65,6 @@ - [`get_active_validator_indices`](#get_active_validator_indices) - [`shuffle`](#shuffle) - [`split`](#split) - - [`clamp`](#clamp) - [`get_new_shuffling`](#get_new_shuffling) - [`get_shard_committees_at_slot`](#get_shard_committees_at_slot) - [`get_block_root`](#get_block_root) @@ -833,21 +832,6 @@ def split(values: List[Any], split_count: int) -> List[Any]: ] ``` -#### `clamp` - -```python -def clamp(minval: int, maxval: int, x: int) -> int: - """ - Clamps ``x`` between ``minval`` and ``maxval``. - """ - if x <= minval: - return minval - elif x >= maxval: - return maxval - else: - return x -``` - #### `get_new_shuffling` ```python @@ -859,10 +843,12 @@ def get_new_shuffling(seed: Hash32, """ active_validator_indices = get_active_validator_indices(validators) - committees_per_slot = clamp( + committees_per_slot = max( 1, - SHARD_COUNT // EPOCH_LENGTH, - len(active_validator_indices) // EPOCH_LENGTH // TARGET_COMMITTEE_SIZE, + min( + SHARD_COUNT // EPOCH_LENGTH, + len(active_validator_indices) // EPOCH_LENGTH // TARGET_COMMITTEE_SIZE, + ) ) # Shuffle with seed From 06fd809549397dd8e9a9f58e610e2891ba2114f1 Mon Sep 17 00:00:00 2001 From: chainsafe Date: Sat, 15 Dec 2018 09:28:13 -0500 Subject: [PATCH 12/30] cleaning up README --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 25d9abe83..9563c97ed 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,10 @@ # Ethereum 2.0 Specifications -[![Join the chat at https://gitter.im/ethereum/sharding](https://badges.gitter.im/ethereum/sharding.svg)](https://gitter.im/ethereum/sharding?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge). +[![Join the chat at https://gitter.im/ethereum/sharding](https://badges.gitter.im/ethereum/sharding.svg)](https://gitter.im/ethereum/sharding?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + To learn more about sharding and eth2.0/Serenity, see the [sharding FAQ](https://github.com/ethereum/wiki/wiki/Sharding-FAQs) and the [research compendium](https://notes.ethereum.org/s/H1PGqDhpm). -This repo hosts the current eth2.0 specifications. Discussions about design rationale and proposed changes can be brought up and discussed as issues. Solidified, agreed upon changes to spec can be made through pull requests. +This repo hosts the current eth2.0 specifications. Discussions about design rationale and proposed changes can be brought up and discussed as issues. Solidified, agreed upon changes to spec can be made through pull requests. # Specs From 416bbf9ceab00cdcecc955e5b712e0b32adcc8ea Mon Sep 17 00:00:00 2001 From: vbuterin Date: Mon, 17 Dec 2018 04:40:27 -0500 Subject: [PATCH 13/30] 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 14/30] 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 15/30] 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 16/30] 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 17/30] 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 f4fa55842b8b6fa60f17539b596e2c02aeea3c91 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Mon, 17 Dec 2018 08:48:06 -0600 Subject: [PATCH 18/30] fix bls_signature toc --- specs/bls_signature.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/specs/bls_signature.md b/specs/bls_signature.md index 394d6bbc3..d04c7f39a 100644 --- a/specs/bls_signature.md +++ b/specs/bls_signature.md @@ -14,6 +14,9 @@ - [Helpers](#helpers) - [`hash_to_G2`](#hash_to_g2) - [`modular_squareroot`](#modular_squareroot) + - [Aggregation operations](#aggregation-operations) + - [`bls_aggregate_pubkeys`](#bls_aggregate_pubkeys) + - [`bls_aggregate_signatures`](#bls_aggregate_signatures) - [Signature verification](#signature-verification) - [`bls_verify`](#bls_verify) - [`bls_verify_multiple`](#bls_verify_multiple) @@ -99,7 +102,7 @@ def modular_squareroot(value: int) -> int: return None ``` -## Operations involving asignature aggregation +## Aggregation operations ### `bls_aggregate_pubkeys` From fbabeff83804fdec987fe06889f056afa25d0781 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Mon, 17 Dec 2018 10:40:21 -0500 Subject: [PATCH 19/30] 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 20/30] 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 21/30] 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 22/30] 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 23/30] 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 24/30] 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 edf335ebf0ef4182a06ee5ddce59f9c54c0ff11f Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 14 Dec 2018 15:13:50 +0800 Subject: [PATCH 25/30] Fix on startup functions --- specs/core/0_beacon-chain.md | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 3c2259559..33eb92628 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1111,8 +1111,8 @@ A valid block with slot `INITIAL_SLOT_NUMBER` (a "genesis block") has the follow state_root=STARTUP_STATE_ROOT, randao_reveal=ZERO_HASH, candidate_pow_receipt_root=ZERO_HASH, - proposer_signature=EMPTY_SIGNATURE, - 'body': BeaconBlockBody( + signature=EMPTY_SIGNATURE, + body=BeaconBlockBody( proposer_slashings=[], casper_slashings=[], attestations=[], @@ -1125,7 +1125,8 @@ A valid block with slot `INITIAL_SLOT_NUMBER` (a "genesis block") has the follow `STARTUP_STATE_ROOT` (in the above "genesis block") is generated from the `get_initial_beacon_state` function below. When enough full deposits have been made to the deposit contract and the `ChainStart` log has been emitted, `get_initial_beacon_state` will execute to compute the `hash_tree_root` of `BeaconState`. ```python -def get_initial_beacon_state(initial_validator_deposits: List[Deposit], +def get_initial_beacon_state(initial_validator_registry: List[ValidatorRecord], + initial_validator_deposits: List[Deposit], genesis_time: int, processed_pow_receipt_root: Hash32) -> BeaconState: state = BeaconState( @@ -1179,8 +1180,8 @@ 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: - update_validator_status(state, index, ACTIVE) + if state.validator_registry[validator_index].balance >= MAX_DEPOSIT * GWEI_PER_ETH: + update_validator_status(state, validator_index, ACTIVE) # set initial committee shuffling initial_shuffling = get_new_shuffling(ZERO_HASH, initial_validator_registry, 0) @@ -1218,7 +1219,7 @@ def process_deposit(state: BeaconState, Process a deposit from Ethereum 1.0. Note that this function mutates ``state``. """ - proof_of_possession_data = DepositInput( + deposit_input = DepositInput( pubkey=pubkey, withdrawal_credentials=withdrawal_credentials, randao_commitment=randao_commitment, @@ -1227,7 +1228,7 @@ def process_deposit(state: BeaconState, assert bls_verify( pubkey=pubkey, - message=hash_tree_root(proof_of_possession_data), + message=hash_tree_root(deposit_input), signature=proof_of_possession, domain=get_domain( state.fork_data, @@ -1250,10 +1251,10 @@ def process_deposit(state: BeaconState, exit_count=0 ) - index = min_empty_validator_index(validators_copy) + index = min_empty_validator_index(state.validator_registry, state.slot) if index is None: state.validator_registry.append(validator) - index = len(validators_copy) - 1 + index = len(state.validator_registry) - 1 else: state.validator_registry[index] = validator else: @@ -1303,7 +1304,7 @@ def activate_validator(state: BeaconState, validator.status = ACTIVE validator.latest_status_change_slot = state.slot state.validator_registry_delta_chain_tip = get_new_validator_registry_delta_chain_tip( - validator_registry_delta_chain_tip=state.validator_registry_delta_chain_tip, + current_validator_registry_delta_chain_tip=state.validator_registry_delta_chain_tip, validator_index=index, pubkey=validator.pubkey, flag=ACTIVATION, @@ -1351,14 +1352,14 @@ def exit_validator(state: BeaconState, whistleblower.balance += whistleblower_reward validator.balance -= whistleblower_reward - if prev_status == EXITED_WITHOUT_PENALTY + if prev_status == EXITED_WITHOUT_PENALTY: return # The following updates only occur if not previous exited state.validator_registry_exit_count += 1 validator.exit_count = state.validator_registry_exit_count state.validator_registry_delta_chain_tip = get_new_validator_registry_delta_chain_tip( - validator_registry_delta_chain_tip=state.validator_registry_delta_chain_tip, + current_validator_registry_delta_chain_tip=state.validator_registry_delta_chain_tip, validator_index=index, pubkey=validator.pubkey, flag=EXIT From 49f3746dc79208c23bd46da017b24894efaa32fb Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Tue, 18 Dec 2018 18:58:59 +0800 Subject: [PATCH 26/30] fix --- 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 33eb92628..700da0490 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -982,7 +982,7 @@ def get_new_validator_registry_delta_chain_tip(current_validator_registry_delta_ """ return hash_tree_root( ValidatorRegistryDeltaBlock( - validator_registry_delta_chain_tip=current_validator_registry_delta_chain_tip, + latest_registry_delta_root=current_validator_registry_delta_chain_tip, validator_index=validator_index, pubkey=pubkey, flag=flag, From 5a0d8c8f424ccbb2cf529ccef2538d4ee153f547 Mon Sep 17 00:00:00 2001 From: Dan Burnett Date: Tue, 18 Dec 2018 09:41:59 -0500 Subject: [PATCH 27/30] 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 bb1559a86f2b75f90e32fdcc205cd7c0b394d4a2 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Wed, 19 Dec 2018 01:18:04 +0800 Subject: [PATCH 28/30] PR feedback --- specs/core/0_beacon-chain.md | 54 +++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 700da0490..329deac90 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1125,8 +1125,7 @@ A valid block with slot `INITIAL_SLOT_NUMBER` (a "genesis block") has the follow `STARTUP_STATE_ROOT` (in the above "genesis block") is generated from the `get_initial_beacon_state` function below. When enough full deposits have been made to the deposit contract and the `ChainStart` log has been emitted, `get_initial_beacon_state` will execute to compute the `hash_tree_root` of `BeaconState`. ```python -def get_initial_beacon_state(initial_validator_registry: List[ValidatorRecord], - initial_validator_deposits: List[Deposit], +def get_initial_beacon_state(initial_validator_deposits: List[Deposit], genesis_time: int, processed_pow_receipt_root: Hash32) -> BeaconState: state = BeaconState( @@ -1184,7 +1183,7 @@ def get_initial_beacon_state(initial_validator_registry: List[ValidatorRecord], update_validator_status(state, validator_index, ACTIVE) # set initial committee shuffling - initial_shuffling = get_new_shuffling(ZERO_HASH, initial_validator_registry, 0) + initial_shuffling = get_new_shuffling(ZERO_HASH, state.validator_registry, 0) state.shard_committees_at_slots = initial_shuffling + initial_shuffling # set initial persistent shuffling @@ -1196,7 +1195,7 @@ def get_initial_beacon_state(initial_validator_registry: List[ValidatorRecord], ### Routine for processing deposits -First, a helper function: +First, two helper functions: ```python def min_empty_validator_index(validators: List[ValidatorRecord], current_slot: int) -> int: @@ -1206,6 +1205,31 @@ def min_empty_validator_index(validators: List[ValidatorRecord], current_slot: i return None ``` +```python +def validate_proof_of_possession(state: BeaconState, + pubkey: int, + proof_of_possession: bytes, + withdrawal_credentials: Hash32, + randao_commitment: Hash32) -> bool: + proof_of_possession_data = DepositInput( + pubkey=pubkey, + withdrawal_credentials=withdrawal_credentials, + randao_commitment=randao_commitment, + proof_of_possession=EMPTY_SIGNATURE, + ) + + return bls_verify( + pubkey=pubkey, + message=hash_tree_root(proof_of_possession_data), + signature=proof_of_possession, + domain=get_domain( + state.fork_data, + state.slot, + DOMAIN_DEPOSIT, + ) + ) +``` + Now, to add a [validator](#dfn-validator) or top up an existing [validator](#dfn-validator)'s balance by some `deposit` amount: ```python @@ -1219,23 +1243,15 @@ def process_deposit(state: BeaconState, Process a deposit from Ethereum 1.0. Note that this function mutates ``state``. """ - deposit_input = DepositInput( - pubkey=pubkey, - withdrawal_credentials=withdrawal_credentials, - randao_commitment=randao_commitment, - proof_of_possession=EMPTY_SIGNATURE, + # Validate the given `proof_of_possession` + assert validate_proof_of_possession( + state, + pubkey, + proof_of_possession, + withdrawal_credentials, + randao_commitment, ) - assert bls_verify( - pubkey=pubkey, - message=hash_tree_root(deposit_input), - signature=proof_of_possession, - domain=get_domain( - state.fork_data, - state.slot, - DOMAIN_DEPOSIT - ) - ) validator_pubkeys = [v.pubkey for v in state.validator_registry] if pubkey not in validator_pubkeys: From 5943fd507fb231687a70de0ddb3b8f6aec023eac Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Tue, 18 Dec 2018 12:27:33 -0600 Subject: [PATCH 29/30] 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 30/30] 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) ```