From befc3498783c62b99cc395d6ea5c0d785d96afaf Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Tue, 11 Dec 2018 11:14:42 -0600 Subject: [PATCH 01/68] 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/68] 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/68] 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 3b0fe25c14349c29268437728ccce53eab2a6fd3 Mon Sep 17 00:00:00 2001 From: terence tsao Date: Wed, 12 Dec 2018 09:29:26 -0800 Subject: [PATCH 04/68] multiply GWEI_PER_ETH --- specs/core/0_beacon-chain.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 6a5540cca..f3748a56c 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -955,7 +955,7 @@ def get_effective_balance(validator: ValidatorRecord) -> int: """ Returns the effective balance (also known as "balance at stake") for the ``validator``. """ - return min(validator.balance, MAX_DEPOSIT) + return min(validator.balance, MAX_DEPOSIT * GWEI_PER_ETH) ``` #### `get_new_validator_registry_delta_chain_tip` @@ -1118,7 +1118,7 @@ def on_startup(initial_validator_deposits: List[Deposit], withdrawal_credentials=deposit.deposit_data.deposit_parameters.withdrawal_credentials, randao_commitment=deposit.deposit_data.deposit_parameters.randao_commitment ) - if state.validator_registry[index].balance >= MAX_DEPOSIT: + if state.validator_registry[index].balance >= MAX_DEPOSIT * GWEI_PER_ETH: update_validator_status(state, index, ACTIVE) # set initial committee shuffling @@ -1625,7 +1625,7 @@ def update_validator_registry(state: BeaconState) -> None: # Activate validators within the allowable balance churn balance_churn = 0 for index, validator in enumerate(state.validator_registry): - if validator.status == PENDING_ACTIVATION and validator.balance >= MAX_DEPOSIT: + if validator.status == PENDING_ACTIVATION and validator.balance >= MAX_DEPOSIT * GWEI_PER_ETH: # Check the balance churn would be within the allowance balance_churn += get_effective_balance(validator) if balance_churn > max_balance_churn: From cc34097fbafc34b00a3d700b0e21917e48ed94d6 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Wed, 12 Dec 2018 11:51:42 -0600 Subject: [PATCH 05/68] fix genesis --- specs/core/0_beacon-chain.md | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index f3748a56c..4536cc063 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -395,7 +395,7 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted 'slot': 'uint64', # Skip list of ancestor beacon block hashes # i'th item is the most recent ancestor whose slot is a multiple of 2**i for i = 0, ..., 31 - 'parent_hash': 'hash32', + 'parent_root': 'hash32', 'state_root': 'hash32', 'randao_reveal': 'hash32', 'candidate_pow_receipt_root': 'hash32', @@ -410,9 +410,9 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted ```python { - 'attestations': [Attestation], 'proposer_slashings': [ProposerSlashing], 'casper_slashings': [CasperSlashing], + 'attestations': [Attestation], 'deposits': [Deposit], 'exits': [Exit], } @@ -1044,14 +1044,12 @@ A valid block with slot `INITIAL_SLOT_NUMBER` (a "genesis block") has the follow ```python { - 'header': BeaconBlockHeader( - slot=INITIAL_SLOT_NUMBER, - parent_hash=ZERO_HASH, - state_root=STARTUP_STATE_ROOT, - randao_reveal=ZERO_HASH, - candidate_pow_receipt_root=ZERO_HASH, - proposer_signature=[0, 0] - ), + slot=INITIAL_SLOT_NUMBER, + parent_root=ZERO_HASH, + state_root=STARTUP_STATE_ROOT, + randao_reveal=ZERO_HASH, + candidate_pow_receipt_root=ZERO_HASH, + proposer_signature=[0, 0], 'body': BeaconBlockBody( proposer_slashings=[], casper_slashings=[], From 81c6b561fcab8c316916db079489c11281540d82 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Thu, 13 Dec 2018 02:07:12 +0800 Subject: [PATCH 06/68] `CandidatePoWReceiptRootRecord.votes` -> `CandidatePoWReceiptRootRecord.vote_count` --- specs/core/0_beacon-chain.md | 46 ++++-------------------------------- 1 file changed, 4 insertions(+), 42 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index f3748a56c..363172dfb 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -59,44 +59,6 @@ - [Helper functions](#helper-functions) - [`hash`](#hash) - [`is_active_validator`](#is_active_validator) - - [`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) - - [`get_beacon_proposer_index`](#get_beacon_proposer_index) - - [`merkle_root`](#merkle_root) - - [`get_attestation_participants`](#get_attestation_participants) - - [`bytes1`, `bytes2`, ...](#bytes1-bytes2-) - - [`get_effective_balance`](#get_effective_balance) - - [`get_new_validator_registry_delta_chain_tip`](#get_new_validator_registry_delta_chain_tip) - - [`get_fork_version`](#get_fork_version) - - [`get_domain`](#get_domain) - - [`hash_tree_root`](#hash_tree_root) - - [`verify_casper_votes`](#verify_casper_votes) - - [`integer_squareroot`](#integer_squareroot) - - [`bls_verify`](#bls_verify) - - [`bls_verify_multiple`](#bls_verify_multiple) - - [On startup](#on-startup) - - [Routine for processing deposits](#routine-for-processing-deposits) - - [Routine for updating validator status](#routine-for-updating-validator-status) - - [Per-slot processing](#per-slot-processing) - - [Misc counters](#misc-counters) - - [Block roots](#block-roots) - - [Per-block processing](#per-block-processing) - - [Slot](#slot) - - [Proposer signature](#proposer-signature) - - [RANDAO](#randao) - - [PoW receipt root](#pow-receipt-root) - - [Operations](#operations) - - [Proposer slashings](#proposer-slashings-1) - - [Casper slashings](#casper-slashings-1) - - [Attestations](#attestations-1) - - [Deposits](#deposits-1) - - [Exits](#exits-1) - - [Ejections](#ejections) - [Per-epoch processing](#per-epoch-processing) - [Helpers](#helpers) - [Receipt roots](#receipt-roots) @@ -541,7 +503,7 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted # Candidate PoW receipt root 'candidate_pow_receipt_root': 'hash32', # Vote count - 'votes': 'uint64', + 'vote_count': 'uint64', } ``` @@ -1343,8 +1305,8 @@ Below are the processing steps that happen at every `block`. ### PoW receipt root -* If `block.candidate_pow_receipt_root` is `x.candidate_pow_receipt_root` for some `x` in `state.candidate_pow_receipt_roots`, set `x.votes += 1`. -* Otherwise, append to `state.candidate_pow_receipt_roots` a new `CandidatePoWReceiptRootRecord(candidate_pow_receipt_root=block.candidate_pow_receipt_root, votes=1)`. +* If `block.candidate_pow_receipt_root` is `x.candidate_pow_receipt_root` for some `x` in `state.candidate_pow_receipt_roots`, set `x.vote_count += 1`. +* Otherwise, append to `state.candidate_pow_receipt_roots` a new `CandidatePoWReceiptRootRecord(candidate_pow_receipt_root=block.candidate_pow_receipt_root, vote_count=1)`. ### Operations @@ -1528,7 +1490,7 @@ def adjust_for_inclusion_distance(magnitude: int, distance: int) -> int: If `state.slot % POW_RECEIPT_ROOT_VOTING_PERIOD == 0`: -* Set `state.processed_pow_receipt_root = x.receipt_root` if `x.votes * 2 > POW_RECEIPT_ROOT_VOTING_PERIOD` for some `x` in `state.candidate_pow_receipt_root`. +* Set `state.processed_pow_receipt_root = x.receipt_root` if `x.vote_count * 2 > POW_RECEIPT_ROOT_VOTING_PERIOD` for some `x` in `state.candidate_pow_receipt_root`. * Set `state.candidate_pow_receipt_roots = []`. ### Justification From ac3ffb3df62764712a34590525f330bbb952e1df Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Thu, 13 Dec 2018 02:08:37 +0800 Subject: [PATCH 07/68] `LATEST_BLOCK_ROOTS_COUNT` -> `LATEST_BLOCK_ROOT_COUNT` --- specs/core/0_beacon-chain.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 363172dfb..fe1b9c24e 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -122,7 +122,7 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted | `BEACON_CHAIN_SHARD_NUMBER` | `2**64 - 1` | - | | `BLS_WITHDRAWAL_PREFIX_BYTE` | `0x00` | - | | `MAX_CASPER_VOTES` | `2**10` (= 1,024) | votes | -| `LATEST_BLOCK_ROOTS_COUNT` | `2**13` (= 8,192) | block roots | +| `LATEST_BLOCK_ROOT_COUNT` | `2**13` (= 8,192) | block roots | * For the safety of crosslinks a minimum committee size of 111 is [recommended](https://vitalik.ca/files/Ithaca201807_Sharding.pdf). (Unbiasable randomness with a Verifiable Delay Function (VDF) will improve committee robustness and lower the safe minimum committee size.) The shuffling algorithm generally ensures (assuming sufficient validators) committee sizes at least `TARGET_COMMITTEE_SIZE // 2`. @@ -1061,7 +1061,7 @@ def on_startup(initial_validator_deposits: List[Deposit], # Recent state latest_crosslinks=[CrosslinkRecord(slot=INITIAL_SLOT_NUMBER, shard_block_root=ZERO_HASH) for _ in range(SHARD_COUNT)], - latest_block_roots=[ZERO_HASH for _ in range(LATEST_BLOCK_ROOTS_COUNT)], + latest_block_roots=[ZERO_HASH for _ in range(LATEST_BLOCK_ROOT_COUNT)], latest_penalized_exit_balances=[], latest_attestations=[], batched_block_roots=[] @@ -1278,7 +1278,7 @@ Below are the processing steps that happen at every slot. * 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]`. -* If `state.slot % LATEST_BLOCK_ROOTS_COUNT == 0` append `merkle_root(state.latest_block_roots)` to `state.batched_block_roots`. +* If `state.slot % LATEST_BLOCK_ROOT_COUNT == 0` append `merkle_root(state.latest_block_roots)` to `state.batched_block_roots`. ## Per-block processing From ae5221c4f83ef2e2d9b084fad4d6ddd5309c43a4 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Thu, 13 Dec 2018 02:11:47 +0800 Subject: [PATCH 08/68] Move BLS verification to later step --- specs/core/0_beacon-chain.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index fe1b9c24e..5b845ff4f 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1317,12 +1317,12 @@ Verify that `len(block.body.proposer_slashings) <= MAX_PROPOSER_SLASHINGS`. For each `proposer_slashing` in `block.body.proposer_slashings`: * Let `proposer = state.validator_registry[proposer_slashing.proposer_index]`. -* Verify that `bls_verify(pubkey=proposer.pubkey, message=hash_tree_root(proposer_slashing.proposal_data_1), signature=proposer_slashing.proposal_signature_1, domain=get_domain(state.fork_data, proposer_slashing.proposal_data_1.slot, DOMAIN_PROPOSAL))`. -* Verify that `bls_verify(pubkey=proposer.pubkey, message=hash_tree_root(proposer_slashing.proposal_data_2), signature=proposer_slashing.proposal_signature_2, domain=get_domain(state.fork_data, proposer_slashing.proposal_data_2.slot, DOMAIN_PROPOSAL))`. * Verify that `proposer_slashing.proposal_data_1.slot == proposer_slashing.proposal_data_2.slot`. * Verify that `proposer_slashing.proposal_data_1.shard == proposer_slashing.proposal_data_2.shard`. * Verify that `proposer_slashing.proposal_data_1.block_root != proposer_slashing.proposal_data_2.block_root`. * Verify that `proposer.status != EXITED_WITH_PENALTY`. +* Verify that `bls_verify(pubkey=proposer.pubkey, message=hash_tree_root(proposer_slashing.proposal_data_1), signature=proposer_slashing.proposal_signature_1, domain=get_domain(state.fork_data, proposer_slashing.proposal_data_1.slot, DOMAIN_PROPOSAL))`. +* Verify that `bls_verify(pubkey=proposer.pubkey, message=hash_tree_root(proposer_slashing.proposal_data_2), signature=proposer_slashing.proposal_signature_2, domain=get_domain(state.fork_data, proposer_slashing.proposal_data_2.slot, DOMAIN_PROPOSAL))`. * Run `update_validator_status(state, proposer_slashing.proposer_index, new_status=EXITED_WITH_PENALTY)`. #### Casper slashings @@ -1401,10 +1401,10 @@ Verify that `len(block.body.exits) <= MAX_EXITS`. For each `exit` in `block.body.exits`: * Let `validator = state.validator_registry[exit.validator_index]`. -* Verify that `bls_verify(pubkey=validator.pubkey, message=ZERO_HASH, signature=exit.signature, domain=get_domain(state.fork_data, exit.slot, DOMAIN_EXIT))`. * Verify that `validator.status == ACTIVE`. * Verify that `state.slot >= exit.slot`. * Verify that `state.slot >= validator.latest_status_change_slot + SHARD_PERSISTENT_COMMITTEE_CHANGE_PERIOD`. +* Verify that `bls_verify(pubkey=validator.pubkey, message=ZERO_HASH, signature=exit.signature, domain=get_domain(state.fork_data, exit.slot, DOMAIN_EXIT))`. * Run `update_validator_status(state, validator_index, new_status=ACTIVE_PENDING_EXIT)`. ### Ejections From 4aa6ec4468e6410bff4a21fddaadba4330212f29 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Thu, 13 Dec 2018 02:55:28 +0800 Subject: [PATCH 09/68] Update `CasperSlashing` and `verify_casper_votes` 1. Rename `verify_casper_votes` -> `verify_slashable_vote_data` 2. Rename `CasperSlashing.votes_1` -> `CasperSlashing.slashable_vote_data_1` 3. Rename `CasperSlashing.votes_2` -> `CasperSlashing.slashable_vote_data_2` 4. Fix `verify_slashable_vote_data` `(verify_casper_votes)` --- specs/core/0_beacon-chain.md | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 5b845ff4f..fa15e53c6 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -234,9 +234,9 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted ```python { # First batch of votes - 'votes_1': SlashableVoteData, + 'slashable_vote_data_1': SlashableVoteData, # Second batch of votes - 'votes_2': SlashableVoteData, + 'slashable_vote_data_2': SlashableVoteData, } ``` @@ -965,16 +965,22 @@ def get_domain(fork_data: ForkData, `hash_tree_root` is a function for hashing objects into a single root utilizing a hash tree structure. `hash_tree_root` is defined in the [SimpleSerialize spec](https://github.com/ethereum/eth2.0-specs/blob/master/specs/simple-serialize.md#tree-hash). -#### `verify_casper_votes` +#### `verify_slashable_vote_data` ```python -def verify_casper_votes(state: BeaconState, votes: SlashableVoteData) -> bool: - if len(votes.aggregate_signature_poc_0_indices) + len(votes.aggregate_signature_poc_1_indices) > MAX_CASPER_VOTES: +def verify_slashable_vote_data(state: BeaconState, vote_data: SlashableVoteData) -> bool: + if len(vote_data.aggregate_signature_poc_0_indices) + len(vote_data.aggregate_signature_poc_1_indices) > MAX_CASPER_VOTES: return False - pubs = [aggregate_pubkey([state.validators[i].pubkey for i in votes.aggregate_signature_poc_0_indices]), - aggregate_pubkey([state.validators[i].pubkey for i in votes.aggregate_signature_poc_1_indices])] - return bls_verify_multiple(pubkeys=pubs, messages=[hash_tree_root(votes)+bytes1(0), hash_tree_root(votes)+bytes1(1), signature=aggregate_signature) + pubs = [ + aggregate_pubkey([state.validators[i].pubkey for i in vote_data.aggregate_signature_poc_0_indices]), + aggregate_pubkey([state.validators[i].pubkey for i in vote_data.aggregate_signature_poc_1_indices]) + ] + return bls_verify_multiple( + pubkeys=pubs, + messages=[hash_tree_root(vote_data)+bytes1(0), hash_tree_root(vote_data)+bytes1(1)],signature=vote_data.aggregate_signature, + domain=DOMAIN_ATTESTATION, + ) ``` #### `integer_squareroot` @@ -1331,13 +1337,13 @@ Verify that `len(block.body.casper_slashings) <= MAX_CASPER_SLASHINGS`. For each `casper_slashing` in `block.body.casper_slashings`: -* Verify that `verify_casper_votes(state, casper_slashing.votes_1)`. -* Verify that `verify_casper_votes(state, casper_slashing.votes_2)`. -* Verify that `casper_slashing.votes_1.data != casper_slashing.votes_2.data`. +* Verify that `verify_slashable_vote_data(state, casper_slashing.slashable_vote_data_1)`. +* Verify that `verify_slashable_vote_data(state, casper_slashing.slashable_vote_data_2)`. +* Verify that `casper_slashing.slashable_vote_data_1.data != casper_slashing.slashable_vote_data_2.data`. * Let `indices(vote) = vote.aggregate_signature_poc_0_indices + vote.aggregate_signature_poc_1_indices`. -* Let `intersection = [x for x in indices(casper_slashing.votes_1) if x in indices(casper_slashing.votes_2)]`. +* Let `intersection = [x for x in indices(casper_slashing.slashable_vote_data_1) if x in indices(casper_slashing.slashable_vote_data_2)]`. * Verify that `len(intersection) >= 1`. -* Verify that `casper_slashing.votes_1.data.justified_slot + 1 < casper_slashing.votes_2.data.justified_slot + 1 == casper_slashing.votes_2.data.slot < casper_slashing.votes_1.data.slot` or `casper_slashing.votes_1.data.slot == casper_slashing.votes_2.data.slot`. +* Verify that `casper_slashing.slashable_vote_data_1.data.justified_slot + 1 < casper_slashing.slashable_vote_data_2.data.justified_slot + 1 == casper_slashing.slashable_vote_data_2.data.slot < casper_slashing.slashable_vote_data_1.data.slot` or `casper_slashing.slashable_vote_data_1.data.slot == casper_slashing.slashable_vote_data_2.data.slot`. * For each [validator](#dfn-validator) index `i` in `intersection`, if `state.validator_registry[i].status` does not equal `EXITED_WITH_PENALTY`, then run `update_validator_status(state, i, new_status=EXITED_WITH_PENALTY)` #### Attestations From d2fda68ccb18de7b9a060753e9a701edec72623d Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Thu, 13 Dec 2018 03:00:53 +0800 Subject: [PATCH 10/68] Fix ToC --- specs/core/0_beacon-chain.md | 42 ++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index fa15e53c6..cd63413c0 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -59,6 +59,44 @@ - [Helper functions](#helper-functions) - [`hash`](#hash) - [`is_active_validator`](#is_active_validator) + - [`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) + - [`get_beacon_proposer_index`](#get_beacon_proposer_index) + - [`merkle_root`](#merkle_root) + - [`get_attestation_participants`](#get_attestation_participants) + - [`bytes1`, `bytes2`, ...](#bytes1-bytes2-) + - [`get_effective_balance`](#get_effective_balance) + - [`get_new_validator_registry_delta_chain_tip`](#get_new_validator_registry_delta_chain_tip) + - [`get_fork_version`](#get_fork_version) + - [`get_domain`](#get_domain) + - [`hash_tree_root`](#hash_tree_root) + - [`verify_slashable_vote_data`](#verify_slashable_vote_data) + - [`integer_squareroot`](#integer_squareroot) + - [`bls_verify`](#bls_verify) + - [`bls_verify_multiple`](#bls_verify_multiple) + - [On startup](#on-startup) + - [Routine for processing deposits](#routine-for-processing-deposits) + - [Routine for updating validator status](#routine-for-updating-validator-status) + - [Per-slot processing](#per-slot-processing) + - [Misc counters](#misc-counters) + - [Block roots](#block-roots) + - [Per-block processing](#per-block-processing) + - [Slot](#slot) + - [Proposer signature](#proposer-signature) + - [RANDAO](#randao) + - [PoW receipt root](#pow-receipt-root) + - [Operations](#operations) + - [Proposer slashings](#proposer-slashings-1) + - [Casper slashings](#casper-slashings-1) + - [Attestations](#attestations-1) + - [Deposits](#deposits-1) + - [Exits](#exits-1) + - [Ejections](#ejections) - [Per-epoch processing](#per-epoch-processing) - [Helpers](#helpers) - [Receipt roots](#receipt-roots) @@ -685,7 +723,7 @@ The hash function is denoted by `hash`. In Phase 0 the beacon chain is deployed Note: We aim to migrate to a S[T/N]ARK-friendly hash function in a future Ethereum 2.0 deployment phase. #### `is_active_validator` - ```python +```python def is_active_validator(validator: ValidatorRecord) -> bool: """ Checks if ``validator`` is active. @@ -1417,7 +1455,7 @@ For each `exit` in `block.body.exits`: * Run `process_ejections(state)`. - ```python +```python def process_ejections(state: BeaconState) -> None: """ Iterate through the validator registry From ab7549e52ec91539d5dbc5af05c04827e7756eae Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Thu, 13 Dec 2018 03:04:10 +0800 Subject: [PATCH 11/68] Move `verify_slashable_vote_data` to the last verification of Casper slashings --- 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 cd63413c0..e69ed9f92 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1375,13 +1375,13 @@ Verify that `len(block.body.casper_slashings) <= MAX_CASPER_SLASHINGS`. For each `casper_slashing` in `block.body.casper_slashings`: -* Verify that `verify_slashable_vote_data(state, casper_slashing.slashable_vote_data_1)`. -* Verify that `verify_slashable_vote_data(state, casper_slashing.slashable_vote_data_2)`. * Verify that `casper_slashing.slashable_vote_data_1.data != casper_slashing.slashable_vote_data_2.data`. * Let `indices(vote) = vote.aggregate_signature_poc_0_indices + vote.aggregate_signature_poc_1_indices`. * Let `intersection = [x for x in indices(casper_slashing.slashable_vote_data_1) if x in indices(casper_slashing.slashable_vote_data_2)]`. * Verify that `len(intersection) >= 1`. * Verify that `casper_slashing.slashable_vote_data_1.data.justified_slot + 1 < casper_slashing.slashable_vote_data_2.data.justified_slot + 1 == casper_slashing.slashable_vote_data_2.data.slot < casper_slashing.slashable_vote_data_1.data.slot` or `casper_slashing.slashable_vote_data_1.data.slot == casper_slashing.slashable_vote_data_2.data.slot`. +* Verify that `verify_slashable_vote_data(state, casper_slashing.slashable_vote_data_1)`. +* Verify that `verify_slashable_vote_data(state, casper_slashing.slashable_vote_data_2)`. * For each [validator](#dfn-validator) index `i` in `intersection`, if `state.validator_registry[i].status` does not equal `EXITED_WITH_PENALTY`, then run `update_validator_status(state, i, new_status=EXITED_WITH_PENALTY)` #### Attestations From 9eeb863ec6c7c29255634275f01b650b31ea0733 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Thu, 13 Dec 2018 03:11:53 +0800 Subject: [PATCH 12/68] Refactor `verify_slashable_vote_data` --- specs/core/0_beacon-chain.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index e69ed9f92..edecfd396 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1014,9 +1014,15 @@ def verify_slashable_vote_data(state: BeaconState, vote_data: SlashableVoteData) aggregate_pubkey([state.validators[i].pubkey for i in vote_data.aggregate_signature_poc_0_indices]), aggregate_pubkey([state.validators[i].pubkey for i in vote_data.aggregate_signature_poc_1_indices]) ] + vote_data_root = hash_tree_root(vote_data) + messages = [ + vote_data_root + bytes1(0), + vote_data_root + bytes1(1) + ] return bls_verify_multiple( pubkeys=pubs, - messages=[hash_tree_root(vote_data)+bytes1(0), hash_tree_root(vote_data)+bytes1(1)],signature=vote_data.aggregate_signature, + messages=messages, + signature=vote_data.aggregate_signature, domain=DOMAIN_ATTESTATION, ) ``` From d5a5e1815cafd1ffdb837a1a3a355db6a3185d73 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Thu, 13 Dec 2018 13:55:34 +0800 Subject: [PATCH 13/68] Rename `LATEST_BLOCK_ROOT_COUNT` -> `LATEST_BLOCK_ROOTS_LENGTH` --- specs/core/0_beacon-chain.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index edecfd396..77ad7d99e 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -160,7 +160,7 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted | `BEACON_CHAIN_SHARD_NUMBER` | `2**64 - 1` | - | | `BLS_WITHDRAWAL_PREFIX_BYTE` | `0x00` | - | | `MAX_CASPER_VOTES` | `2**10` (= 1,024) | votes | -| `LATEST_BLOCK_ROOT_COUNT` | `2**13` (= 8,192) | block roots | +| `LATEST_BLOCK_ROOTS_LENGTH` | `2**13` (= 8,192) | block roots | * For the safety of crosslinks a minimum committee size of 111 is [recommended](https://vitalik.ca/files/Ithaca201807_Sharding.pdf). (Unbiasable randomness with a Verifiable Delay Function (VDF) will improve committee robustness and lower the safe minimum committee size.) The shuffling algorithm generally ensures (assuming sufficient validators) committee sizes at least `TARGET_COMMITTEE_SIZE // 2`. @@ -1111,7 +1111,7 @@ def on_startup(initial_validator_deposits: List[Deposit], # Recent state latest_crosslinks=[CrosslinkRecord(slot=INITIAL_SLOT_NUMBER, shard_block_root=ZERO_HASH) for _ in range(SHARD_COUNT)], - latest_block_roots=[ZERO_HASH for _ in range(LATEST_BLOCK_ROOT_COUNT)], + latest_block_roots=[ZERO_HASH for _ in range(LATEST_BLOCK_ROOTS_LENGTH)], latest_penalized_exit_balances=[], latest_attestations=[], batched_block_roots=[] @@ -1328,7 +1328,7 @@ Below are the processing steps that happen at every slot. * 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]`. -* If `state.slot % LATEST_BLOCK_ROOT_COUNT == 0` append `merkle_root(state.latest_block_roots)` to `state.batched_block_roots`. +* If `state.slot % LATEST_BLOCK_ROOTS_LENGTH == 0` append `merkle_root(state.latest_block_roots)` to `state.batched_block_roots`. ## Per-block processing From c1a3b29145c84c6ac4422314b7b54898ac9f6693 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Thu, 13 Dec 2018 17:55:37 +0800 Subject: [PATCH 14/68] Fix `verify_slashable_vote_data`: use `get_domain` (#306) --- specs/core/0_beacon-chain.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 6f412fcb5..3863a396d 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1023,7 +1023,11 @@ def verify_slashable_vote_data(state: BeaconState, vote_data: SlashableVoteData) pubkeys=pubs, messages=messages, signature=vote_data.aggregate_signature, - domain=DOMAIN_ATTESTATION, + domain=get_domain( + state.fork_data, + state.slot, + DOMAIN_ATTESTATION, + ), ) ``` From 6b6a04c884e186702d31b7075254f39d379b6cea Mon Sep 17 00:00:00 2001 From: Justin Date: Thu, 13 Dec 2018 10:03:50 +0000 Subject: [PATCH 15/68] Bugfix (missing `state.`) --- 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 3863a396d..f12d6646e 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1249,7 +1249,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=validator_registry_delta_chain_tip, + validator_registry_delta_chain_tip=state.validator_registry_delta_chain_tip, index=index, pubkey=validator.pubkey, flag=ACTIVATION, From b5542046883e252dfbb1de2fb2b20c199ae7e598 Mon Sep 17 00:00:00 2001 From: Gregory Markou Date: Thu, 13 Dec 2018 08:08:51 -0500 Subject: [PATCH 16/68] clarified language around start_up (#303) --- specs/core/0_beacon-chain.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index f12d6646e..f2637d2fc 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -592,7 +592,7 @@ Every deposit, of size between `MIN_DEPOSIT` and `MAX_DEPOSIT`, emits an `Eth1De ### `ChainStart` log -When sufficiently many full deposits have been made the deposit contract emits the `ChainStart` log. The beacon chain may then be initialized by calling the `on_startup` function (defined below) where: +When sufficiently many full deposits have been made the deposit contract emits the `ChainStart` log. The beacon chain state may then be initialized by calling the `get_initial_beacon_state` function (defined below) where: * `genesis_time` equals `time` in the `ChainStart` log * `processed_pow_receipt_root` equals `receipt_root` in the `ChainStart` log @@ -1076,12 +1076,12 @@ A valid block with slot `INITIAL_SLOT_NUMBER` (a "genesis block") has the follow } ``` -`STARTUP_STATE_ROOT` is the root of the initial state, computed by running the following code: +`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 `ssz_tree_hash` of `BeaconState`. ```python -def on_startup(initial_validator_deposits: List[Deposit], - genesis_time: int, - processed_pow_receipt_root: Hash32) -> BeaconState: +def get_initial_beacon_state(initial_validator_deposits: List[Deposit], + genesis_time: int, + processed_pow_receipt_root: Hash32) -> BeaconState: state = BeaconState( # Misc slot=INITIAL_SLOT_NUMBER, @@ -1283,7 +1283,7 @@ def exit_validator(state: BeaconState, prev_status = validator.status if prev_status == EXITED_WITH_PENALTY: - return + return validator.status = new_status validator.latest_status_change_slot = state.slot From ddb91adecf68f88830859a2e656f4647029a75b2 Mon Sep 17 00:00:00 2001 From: terence tsao Date: Thu, 13 Dec 2018 06:51:47 -0800 Subject: [PATCH 17/68] quick fix on typo --- 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 f2637d2fc..28b08d119 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1485,7 +1485,7 @@ 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])`. -[Validators](#dfn-Validator) validators attesting during the current epoch: +[Validators](#dfn-Validator) attesting during the current epoch: * Let `this_epoch_attestations = [a for a in state.latest_attestations if state.slot - EPOCH_LENGTH <= a.data.slot < state.slot]`. (Note: this is the set of attestations of slots in the epoch `state.slot-EPOCH_LENGTH...state.slot-1`, _not_ attestations that got included in the chain during the epoch `state.slot-EPOCH_LENGTH...state.slot-1`.) From 1ea887c964557aaaa0e56a7dd9efade613bbdaf1 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Thu, 13 Dec 2018 23:36:57 +0800 Subject: [PATCH 18/68] Deposits: define `DepositData` and rename `DepositParameters` to `DepositInput` (#310) --- specs/core/0_beacon-chain.md | 54 +++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 28b08d119..2b23aa013 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -32,7 +32,8 @@ - [`AttestationData`](#attestationdata) - [Deposits](#deposits) - [`Deposit`](#deposit) - - [`DepositParameters`](#depositparameters) + - [`DepositData`](#depositdata) + - [`DepositInput`](#depositinput) - [Exits](#exits) - [`Exit`](#exit) - [Beacon chain blocks](#beacon-chain-blocks) @@ -344,18 +345,24 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted # Merkle tree index 'merkle_tree_index': 'uint64', # Deposit data - 'deposit_data': { - # Deposit parameters - 'deposit_parameters': DepositParameters, - # Value in Gwei - 'value': 'uint64', - # Timestamp from deposit contract - 'timestamp': 'uint64', - }, + 'deposit_data': DepositData, } ``` -##### `DepositParameters` +##### `DepositData` + +```python +{ + # Deposit parameters + 'deposit_input': DepositInput, + # Value in Gwei + 'value': 'uint64', + # Timestamp from deposit contract + 'timestamp': 'uint64', +} +``` + +##### `DepositInput` ```python { @@ -579,7 +586,7 @@ The initial deployment phases of Ethereum 2.0 are implemented without consensus ### Deposit arguments -The deposit contract has a single `deposit` function which takes as argument a SimpleSerialize'd `DepositParameters`. One of the `DepositParameters` fields is `withdrawal_credentials` which must satisfy: +The deposit contract has a single `deposit` function which takes as argument a SimpleSerialize'd `DepositInput`. One of the `DepositInput` fields is `withdrawal_credentials` which must satisfy: * `withdrawal_credentials[:1] == BLS_WITHDRAWAL_PREFIX_BYTE` * `withdrawal_credentials[1:] == hash(withdrawal_pubkey)[1:]` where `withdrawal_pubkey` is a BLS pubkey @@ -619,14 +626,14 @@ full_deposit_count: uint256 @payable @public -def deposit(deposit_parameters: bytes[2048]): +def deposit(deposit_input: bytes[2048]): assert msg.value >= as_wei_value(MIN_DEPOSIT, "ether") assert msg.value <= as_wei_value(MAX_DEPOSIT, "ether") index: uint256 = self.deposit_count + 2**DEPOSIT_CONTRACT_TREE_DEPTH msg_gwei_bytes8: bytes[8] = slice(concat("", convert(msg.value / GWEI_PER_ETH, bytes32)), start=24, len=8) timestamp_bytes8: bytes[8] = slice(concat("", convert(block.timestamp, bytes32)), start=24, len=8) - deposit_data: bytes[2064] = concat(msg_gwei_bytes8, timestamp_bytes8, deposit_parameters) + deposit_data: bytes[2064] = concat(msg_gwei_bytes8, timestamp_bytes8, deposit_input) log.Eth1Deposit(self.receipt_tree[1], deposit_data, self.deposit_count) @@ -1116,7 +1123,8 @@ def get_initial_beacon_state(initial_validator_deposits: List[Deposit], latest_block_roots=[ZERO_HASH for _ in range(LATEST_BLOCK_ROOTS_LENGTH)], latest_penalized_exit_balances=[], latest_attestations=[], - batched_block_roots=[] + batched_block_roots=[], + # PoW receipt root processed_pow_receipt_root=processed_pow_receipt_root, candidate_pow_receipt_roots=[], @@ -1126,11 +1134,11 @@ def get_initial_beacon_state(initial_validator_deposits: List[Deposit], for deposit in initial_validator_deposits: validator_index = process_deposit( state=state, - pubkey=deposit.deposit_data.deposit_parameters.pubkey, + pubkey=deposit.deposit_data.deposit_input.pubkey, deposit=deposit.deposit_data.value, - proof_of_possession=deposit.deposit_data.deposit_parameters.proof_of_possession, - withdrawal_credentials=deposit.deposit_data.deposit_parameters.withdrawal_credentials, - randao_commitment=deposit.deposit_data.deposit_parameters.randao_commitment + proof_of_possession=deposit.deposit_data.deposit_input.proof_of_possession, + 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) @@ -1418,7 +1426,7 @@ Verify that `len(block.body.deposits) <= MAX_DEPOSITS`. For each `deposit` in `block.body.deposits`: -* Let `serialized_deposit_data` be the serialized form of `deposit.deposit_data`. It should be the `DepositParameters` followed by 8 bytes for `deposit_data.value` and 8 bytes for `deposit_data.timestamp`. That is, it should match `deposit_data` in the [Ethereum 1.0 deposit contract](#ethereum-10-chain-deposit-contract) of which the hash was placed into the Merkle tree. +* Let `serialized_deposit_data` be the serialized form of `deposit.deposit_data`. It should be the `DepositInput` followed by 8 bytes for `deposit_data.value` and 8 bytes for `deposit_data.timestamp`. That is, it should match `deposit_data` in the [Ethereum 1.0 deposit contract](#ethereum-10-deposit-contract) of which the hash was placed into the Merkle tree. * Use the following procedure to verify `deposit.merkle_branch`, setting `leaf=serialized_deposit_data`, `depth=DEPOSIT_CONTRACT_TREE_DEPTH` and `root=state.processed_pow_receipt_root`: ```python @@ -1438,11 +1446,11 @@ def verify_merkle_branch(leaf: Hash32, branch: [Hash32], depth: int, index: int, ```python process_deposit( state=state, - pubkey=deposit.deposit_data.deposit_parameters.pubkey, + pubkey=deposit.deposit_data.deposit_input.pubkey, deposit=deposit.deposit_data.value, - proof_of_possession=deposit.deposit_data.deposit_parameters.proof_of_possession, - withdrawal_credentials=deposit.deposit_data.deposit_parameters.withdrawal_credentials, - randao_commitment=deposit.deposit_data.deposit_parameters.randao_commitment + proof_of_possession=deposit.deposit_data.deposit_input.proof_of_possession, + withdrawal_credentials=deposit.deposit_data.deposit_input.withdrawal_credentials, + randao_commitment=deposit.deposit_data.deposit_input.randao_commitment ) ``` From 9170efee1bf934e9751ed5653f0761a7af39217f Mon Sep 17 00:00:00 2001 From: terence tsao Date: Thu, 13 Dec 2018 08:27:22 -0800 Subject: [PATCH 19/68] removed old comments --- specs/core/0_beacon-chain.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 2b23aa013..f2ffc1a3d 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -400,8 +400,6 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted { ## Header ## 'slot': 'uint64', - # Skip list of ancestor beacon block hashes - # i'th item is the most recent ancestor whose slot is a multiple of 2**i for i = 0, ..., 31 'parent_root': 'hash32', 'state_root': 'hash32', 'randao_reveal': 'hash32', From 923df80b037523f15ed147af5cd6e6eea1c0cdce Mon Sep 17 00:00:00 2001 From: Raul Jordan Date: Thu, 13 Dec 2018 11:26:10 -0600 Subject: [PATCH 20/68] replace shard_block_hash with shard_block_root --- 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 f2ffc1a3d..040d0490c 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1413,7 +1413,7 @@ For each `attestation` in `block.body.attestations`: * 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])`. * 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_hash == ZERO_HASH`. +* [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`. #### Deposits From 7c833fafc5d04278a63ed3e36d4bc5b77e4a33e8 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Thu, 13 Dec 2018 12:09:39 -0600 Subject: [PATCH 21/68] clean up casper slashing with helper functions etc --- specs/core/0_beacon-chain.md | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 040d0490c..15cd4f6e5 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -77,6 +77,8 @@ - [`get_domain`](#get_domain) - [`hash_tree_root`](#hash_tree_root) - [`verify_slashable_vote_data`](#verify_slashable_vote_data) + - [`is_double_vote`](#is_double_vote) + - [`is_surround_vote`](#is_surround_vote) - [`integer_squareroot`](#integer_squareroot) - [`bls_verify`](#bls_verify) - [`bls_verify_multiple`](#bls_verify_multiple) @@ -1036,6 +1038,26 @@ def verify_slashable_vote_data(state: BeaconState, vote_data: SlashableVoteData) ) ``` +#### `is_double_vote` + +```python +def is_double_vote(attestation_data_1: AttestationData, + attestation_data_2: AttestationData) -> bool + return attestation_data_1.slot == attestation_data_2.slot +``` + +#### `is_surround_vote` + +```python +def is_surround_vote(attestation_data_1: AttestationData, + attestation_data_2: AttestationData) -> bool + return ( + (attestation_data_1.justified_slot < attestation_data_2.justified_slot) and + (attestat_data_2.justified_slot + 1 == attestation_data_2.slot) and + (attestation_data_2.slot < attestation_data_1.slot) + ) +``` + #### `integer_squareroot` ```python @@ -1389,13 +1411,15 @@ Verify that `len(block.body.casper_slashings) <= MAX_CASPER_SLASHINGS`. For each `casper_slashing` in `block.body.casper_slashings`: -* Verify that `casper_slashing.slashable_vote_data_1.data != casper_slashing.slashable_vote_data_2.data`. -* Let `indices(vote) = vote.aggregate_signature_poc_0_indices + vote.aggregate_signature_poc_1_indices`. -* Let `intersection = [x for x in indices(casper_slashing.slashable_vote_data_1) if x in indices(casper_slashing.slashable_vote_data_2)]`. +* Let `slashable_vote_data_1 = casper_slashing.slashable_vote_data_1`. +* Let `slashable_vote_data_2 = casper_slashing.slashable_vote_data_2`. +* Let `indices(slashable_vote_data) = slashable_vote_data.aggregate_signature_poc_0_indices + slashable_vote_data.aggregate_signature_poc_1_indices`. +* Let `intersection = [x for x in indices(slashable_vote_data_1) if x in indices(slashable_vote_data_2)]`. * Verify that `len(intersection) >= 1`. -* Verify that `casper_slashing.slashable_vote_data_1.data.justified_slot + 1 < casper_slashing.slashable_vote_data_2.data.justified_slot + 1 == casper_slashing.slashable_vote_data_2.data.slot < casper_slashing.slashable_vote_data_1.data.slot` or `casper_slashing.slashable_vote_data_1.data.slot == casper_slashing.slashable_vote_data_2.data.slot`. -* Verify that `verify_slashable_vote_data(state, casper_slashing.slashable_vote_data_1)`. -* Verify that `verify_slashable_vote_data(state, casper_slashing.slashable_vote_data_2)`. +* Verify that `slashable_vote_data_1.data != slashable_vote_data_2.data`. +* Verify that `is_double_vote(slashable_vote_data_1.data, slashable_vote_data_2.data)` or `is_surround_vote(slashable_vote_data_1.data, slashable_vote_data_2.data)`. +* Verify that `verify_slashable_vote_data(state, slashable_vote_data_1)`. +* Verify that `verify_slashable_vote_data(state, slashable_vote_data_2)`. * For each [validator](#dfn-validator) index `i` in `intersection`, if `state.validator_registry[i].status` does not equal `EXITED_WITH_PENALTY`, then run `update_validator_status(state, i, new_status=EXITED_WITH_PENALTY)` #### Attestations From 697d3c5eb58df26239bea03154db298e171b2ece Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Thu, 13 Dec 2018 12:17:39 -0600 Subject: [PATCH 22/68] add doc string for new slashing helper funtions --- specs/core/0_beacon-chain.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 15cd4f6e5..30fb27c19 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1043,6 +1043,11 @@ def verify_slashable_vote_data(state: BeaconState, vote_data: SlashableVoteData) ```python def is_double_vote(attestation_data_1: AttestationData, attestation_data_2: AttestationData) -> bool + """ + Assumes ``attestation_data_1`` is distinct from ``attestation_data_2``. + Returns True if the provided ``AttestationData`` are slashable + due to a 'double vote'. + """ return attestation_data_1.slot == attestation_data_2.slot ``` @@ -1051,6 +1056,13 @@ def is_double_vote(attestation_data_1: AttestationData, ```python def is_surround_vote(attestation_data_1: AttestationData, attestation_data_2: AttestationData) -> bool + """ + Assumes ``attestation_data_1`` is distinct from ``attestation_data_2``. + Returns True if the provided ``AttestationData`` is slashable + due to a 'surround vote'. + Note: parameter order matters as this function only checks + that ``attestation_data_1`` surrounds ``attestation_data_2``. + """ return ( (attestation_data_1.justified_slot < attestation_data_2.justified_slot) and (attestat_data_2.justified_slot + 1 == attestation_data_2.slot) and From cd9e7ecaeb2f0ccaa3e5cbe4bcd5aa178278b4c7 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Thu, 13 Dec 2018 12:18:29 -0600 Subject: [PATCH 23/68] minor 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 30fb27c19..6f3a02976 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1058,7 +1058,7 @@ def is_surround_vote(attestation_data_1: AttestationData, attestation_data_2: AttestationData) -> bool """ Assumes ``attestation_data_1`` is distinct from ``attestation_data_2``. - Returns True if the provided ``AttestationData`` is slashable + Returns True if the provided ``AttestationData`` are slashable due to a 'surround vote'. Note: parameter order matters as this function only checks that ``attestation_data_1`` surrounds ``attestation_data_2``. From 9e74043a1737b1a792e259ef93c995e0634df086 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Thu, 13 Dec 2018 13:45:08 -0600 Subject: [PATCH 24/68] move ejectiosn to per-epoch. fix a couple bugs in validator status change functions (#314) --- specs/core/0_beacon-chain.md | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 040d0490c..42929bbd6 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -97,7 +97,6 @@ - [Attestations](#attestations-1) - [Deposits](#deposits-1) - [Exits](#exits-1) - - [Ejections](#ejections) - [Per-epoch processing](#per-epoch-processing) - [Helpers](#helpers) - [Receipt roots](#receipt-roots) @@ -108,6 +107,7 @@ - [Justification and finalization](#justification-and-finalization) - [Attestation inclusion](#attestation-inclusion) - [Crosslinks](#crosslinks-1) + - [Ejections](#ejections) - [Validator registry](#validator-registry) - [Proposer reshuffling](#proposer-reshuffling) - [Final updates](#final-updates) @@ -1248,6 +1248,7 @@ def activate_validator(state: BeaconState, Activate the validator with the given ``index``. Note that this function mutates ``state``. """ + validator = state.validator_registry[index] if validator.status != PENDING_ACTIVATION: return @@ -1269,6 +1270,7 @@ def initiate_validator_exit(state: BeaconState, Initiate exit for the validator with the given ``index``. Note that this function mutates ``state``. """ + validator = state.validator_registry[index] if validator.status != ACTIVE: return @@ -1465,21 +1467,6 @@ For each `exit` in `block.body.exits`: * Verify that `bls_verify(pubkey=validator.pubkey, message=ZERO_HASH, signature=exit.signature, domain=get_domain(state.fork_data, exit.slot, DOMAIN_EXIT))`. * Run `update_validator_status(state, validator_index, new_status=ACTIVE_PENDING_EXIT)`. -### Ejections - -* Run `process_ejections(state)`. - -```python -def process_ejections(state: BeaconState) -> None: - """ - Iterate through the validator registry - and eject active validators with balance below ``EJECTION_BALANCE``. - """ - for index, validator in enumerate(state.validator_registry): - if is_active_validator(validor) and validator.balance < EJECTION_BALANCE: - update_validator_status(state, index, new_status=EXITED_WITHOUT_PENALTY) -``` - ## Per-epoch processing The steps below happen when `state.slot % EPOCH_LENGTH == 0`. @@ -1616,6 +1603,21 @@ For every `shard_committee` in `state.shard_committees_at_slots[:EPOCH_LENGTH]` * 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)`. +### Ejections + +* Run `process_ejections(state)`. + +```python +def process_ejections(state: BeaconState) -> None: + """ + Iterate through the validator registry + 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: + update_validator_status(state, index, new_status=EXITED_WITHOUT_PENALTY) +``` + ### Validator registry If the following are satisfied: From f30d40485610c13c0589ae9202fff9bc401b9a78 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Thu, 13 Dec 2018 13:50:50 -0600 Subject: [PATCH 25/68] add ValidatorRegistryDeltaBlock ssz object --- specs/core/0_beacon-chain.md | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 040d0490c..9c77a40fb 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -49,6 +49,7 @@ - [`CandidatePoWReceiptRootRecord`](#candidatepowreceiptrootrecord) - [`PendingAttestationRecord`](#pendingattestationrecord) - [`ForkData`](#forkdata) + - [`ValidatorRegistryDeltaBlock`](#validatorregistrydeltablock) - [Ethereum 1.0 deposit contract](#ethereum-10-deposit-contract) - [Deposit arguments](#deposit-arguments) - [`Eth1Deposit` logs](#eth1deposit-logs) @@ -578,6 +579,17 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted } ``` +#### `ValidatorRegistryDeltaBlock` + +```python +{ + latest_registry_delta_root: 'hash32', + validator_index: 'uint24', + pubkey: 'uint384', + flag: 'uint64', +} +``` + ## Ethereum 1.0 deposit contract The initial deployment phases of Ethereum 2.0 are implemented without consensus changes to Ethereum 1.0. A deposit contract at address `DEPOSIT_CONTRACT_ADDRESS` is added to Ethereum 1.0 for deposits of ETH to the beacon chain. Validator balances will be withdrawable to the shards when the EVM2.0 is deployed and the shards have state. @@ -967,17 +979,19 @@ def get_effective_balance(validator: ValidatorRecord) -> int: ```python def get_new_validator_registry_delta_chain_tip(current_validator_registry_delta_chain_tip: Hash32, - index: int, + validator_index: int, pubkey: int, flag: int) -> Hash32: """ - Compute the next hash in the validator registry delta hash chain. + Compute the next root in the validator registry delta hash chain. """ - return hash( - current_validator_registry_delta_chain_tip + - bytes1(flag) + - bytes3(index) + - bytes48(pubkey) + return tree_hash_root( + ValidatorRegistryDeltaBlock( + current_validator_registry_delta_chain_tip, + validator_index=validator_index, + pubkey=pubkey, + flag=flag, + ) ) ``` @@ -1081,7 +1095,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 `ssz_tree_hash` of `BeaconState`. +`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 `tree_hash_root` of `BeaconState`. ```python def get_initial_beacon_state(initial_validator_deposits: List[Deposit], From 96aade9a2c4d30e579c301baeb216a9f6c6df8ec Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Thu, 13 Dec 2018 14:03:22 -0600 Subject: [PATCH 26/68] add proofofpossessiondata ssz object --- specs/core/0_beacon-chain.md | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 9c77a40fb..0e8f57210 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -34,6 +34,7 @@ - [`Deposit`](#deposit) - [`DepositData`](#depositdata) - [`DepositInput`](#depositinput) + - [`ProofOfPossessionData`](#proofofpossessiondata) - [Exits](#exits) - [`Exit`](#exit) - [Beacon chain blocks](#beacon-chain-blocks) @@ -378,6 +379,16 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted } ``` +#### `ProofOfPossessionData` + +```python +{ + 'pubkey': 'uint384', + 'withdrawal_credentials': 'hash32', + 'randao_commitment': 'hash32', +} +``` + #### Exits ##### `Exit` @@ -985,7 +996,7 @@ def get_new_validator_registry_delta_chain_tip(current_validator_registry_delta_ """ Compute the next root in the validator registry delta hash chain. """ - return tree_hash_root( + return hash_tree_root( ValidatorRegistryDeltaBlock( current_validator_registry_delta_chain_tip, validator_index=validator_index, @@ -1095,7 +1106,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 `tree_hash_root` of `BeaconState`. +`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], @@ -1192,9 +1203,15 @@ def process_deposit(state: BeaconState, Process a deposit from Ethereum 1.0. Note that this function mutates ``state``. """ + proof_of_possession_data = ProofOfPossessionData( + pubkey=pubkey, + withdrawal_credentials=withdrawal_credentials, + randao_commitment=randao_commitment, + ) + assert bls_verify( pubkey=pubkey, - message=hash(bytes32(pubkey) + withdrawal_credentials + randao_commitment), + message=hash_tree_root(proof_of_possession_data), signature=proof_of_possession, domain=get_domain( state.fork_data, @@ -1348,7 +1365,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. +* Let `previous_block_root` be the `hash_tree_root` of the previous beacon block processed in the chain. * Set `state.latest_block_roots = state.latest_block_roots[1:] + [previous_block_root]`. * If `state.slot % LATEST_BLOCK_ROOTS_LENGTH == 0` append `merkle_root(state.latest_block_roots)` to `state.batched_block_roots`. From add628d26bcb0b55d7f1a4b4c3031f4241922c66 Mon Sep 17 00:00:00 2001 From: vbuterin Date: Thu, 13 Dec 2018 19:06:07 -0500 Subject: [PATCH 27/68] 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 28/68] 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 29/68] 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 c43724132b06086ae51a11001794dce802c74644 Mon Sep 17 00:00:00 2001 From: vbuterin Date: Thu, 13 Dec 2018 23:01:32 -0500 Subject: [PATCH 30/68] Clarify block hash -> block root --- specs/core/0_beacon-chain.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 42929bbd6..485069d25 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -140,6 +140,7 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted * **Attester** - a [validator](#dfn-validator) that is part of a committee that needs to sign off on a beacon chain block while simultaneously creating a link (crosslink) to a recent shard block on a particular shard chain. * **Beacon chain** - the central PoS chain that is the base of the sharding system. * **Shard chain** - one of the chains on which user transactions take place and account data is stored. +* **Block root** - a 32-byte Merkle root of a beacon chain block or shard chain block. Previously called "block hash". * **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 @@ -508,7 +509,7 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted { # Slot number 'slot': 'uint64', - # Shard block hash + # Shard block root 'shard_block_root': 'hash32', } ``` @@ -894,7 +895,7 @@ def get_shard_committees_at_slot(state: BeaconState, def get_block_root(state: BeaconState, slot: int) -> Hash32: """ - Returns the block hash at a recent ``slot``. + Returns the block root at a recent ``slot``. """ earliest_slot_in_array = state.slot - len(state.latest_block_roots) assert earliest_slot_in_array <= slot < state.slot From 221874efcb47bebb4708e35785914220af82fa6f Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 14 Dec 2018 09:29:49 -0600 Subject: [PATCH 31/68] pr feedback --- specs/core/0_beacon-chain.md | 40 +++++++++++++++--------------------- 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 0e8f57210..b75f8a014 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -61,6 +61,7 @@ - [Beacon chain state transition function](#beacon-chain-state-transition-function) - [Helper functions](#helper-functions) - [`hash`](#hash) + - [`hash_tree_root`](#hash_tree_root) - [`is_active_validator`](#is_active_validator) - [`get_active_validator_indices`](#get_active_validator_indices) - [`shuffle`](#shuffle) @@ -77,7 +78,6 @@ - [`get_new_validator_registry_delta_chain_tip`](#get_new_validator_registry_delta_chain_tip) - [`get_fork_version`](#get_fork_version) - [`get_domain`](#get_domain) - - [`hash_tree_root`](#hash_tree_root) - [`verify_slashable_vote_data`](#verify_slashable_vote_data) - [`integer_squareroot`](#integer_squareroot) - [`bls_verify`](#bls_verify) @@ -164,6 +164,7 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted | `BLS_WITHDRAWAL_PREFIX_BYTE` | `0x00` | - | | `MAX_CASPER_VOTES` | `2**10` (= 1,024) | votes | | `LATEST_BLOCK_ROOTS_LENGTH` | `2**13` (= 8,192) | block roots | +| `EMPTY_SIGNATURE` | `[bytes48(0), bytes48(0)]` | - | * For the safety of crosslinks a minimum committee size of 111 is [recommended](https://vitalik.ca/files/Ithaca201807_Sharding.pdf). (Unbiasable randomness with a Verifiable Delay Function (VDF) will improve committee robustness and lower the safe minimum committee size.) The shuffling algorithm generally ensures (assuming sufficient validators) committee sizes at least `TARGET_COMMITTEE_SIZE // 2`. @@ -370,22 +371,12 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted { # BLS pubkey 'pubkey': 'uint384', - # BLS proof of possession (a BLS signature) - 'proof_of_possession': ['uint384'], # Withdrawal credentials 'withdrawal_credentials': 'hash32', # Initial RANDAO commitment 'randao_commitment': 'hash32', -} -``` - -#### `ProofOfPossessionData` - -```python -{ - 'pubkey': 'uint384', - 'withdrawal_credentials': 'hash32', - 'randao_commitment': 'hash32', + # a BLS signature of this ``DepositInput`` + 'proof_of_possession': ['uint384'], } ``` @@ -750,6 +741,10 @@ The hash function is denoted by `hash`. In Phase 0 the beacon chain is deployed Note: We aim to migrate to a S[T/N]ARK-friendly hash function in a future Ethereum 2.0 deployment phase. +#### `hash_tree_root` + +`hash_tree_root` is a function for hashing objects into a single root utilizing a hash tree structure. `hash_tree_root` is defined in the [SimpleSerialize spec](https://github.com/ethereum/eth2.0-specs/blob/master/specs/simple-serialize.md#tree-hash). + #### `is_active_validator` ```python def is_active_validator(validator: ValidatorRecord) -> bool: @@ -994,11 +989,11 @@ def get_new_validator_registry_delta_chain_tip(current_validator_registry_delta_ pubkey: int, flag: int) -> Hash32: """ - Compute the next root in the validator registry delta hash chain. + Compute the next root in the validator registry delta chain. """ return hash_tree_root( ValidatorRegistryDeltaBlock( - current_validator_registry_delta_chain_tip, + validator_registry_delta_chain_tip=current_validator_registry_delta_chain_tip, validator_index=validator_index, pubkey=pubkey, flag=flag, @@ -1029,10 +1024,6 @@ def get_domain(fork_data: ForkData, ) * 2**32 + domain_type ``` -#### `hash_tree_root` - -`hash_tree_root` is a function for hashing objects into a single root utilizing a hash tree structure. `hash_tree_root` is defined in the [SimpleSerialize spec](https://github.com/ethereum/eth2.0-specs/blob/master/specs/simple-serialize.md#tree-hash). - #### `verify_slashable_vote_data` ```python @@ -1095,7 +1086,7 @@ 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=[0, 0], + proposer_signature=EMPTY_SIGNATURE, 'body': BeaconBlockBody( proposer_slashings=[], casper_slashings=[], @@ -1203,10 +1194,11 @@ def process_deposit(state: BeaconState, Process a deposit from Ethereum 1.0. Note that this function mutates ``state``. """ - proof_of_possession_data = ProofOfPossessionData( + proof_of_possession_data = DepositInput( pubkey=pubkey, withdrawal_credentials=withdrawal_credentials, randao_commitment=randao_commitment, + proof_of_possession=EMPTY_SIGNATURE, ) assert bls_verify( @@ -1287,7 +1279,7 @@ def activate_validator(state: BeaconState, 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, - index=index, + validator_index=index, pubkey=validator.pubkey, flag=ACTIVATION, ) @@ -1341,7 +1333,7 @@ def exit_validator(state: BeaconState, 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, - index=index, + validator_index=index, pubkey=validator.pubkey, flag=EXIT ) @@ -1379,7 +1371,7 @@ Below are the processing steps that happen at every `block`. ### Proposer signature -* Let `block_without_signature_root` be the `hash_tree_root` of `block` where `block.signature` is set to `[0, 0]`. +* Let `block_without_signature_root` be the `hash_tree_root` of `block` where `block.signature` is set to `EMPTY_SIGNATURE`. * Let `proposal_root = hash_tree_root(ProposalSignedData(state.slot, BEACON_CHAIN_SHARD_NUMBER, block_without_signature_root))`. * Verify that `bls_verify(pubkey=state.validator_registry[get_beacon_proposer_index(state, state.slot)].pubkey, data=proposal_root, signature=block.signature, domain=get_domain(state.fork_data, state.slot, DOMAIN_PROPOSAL))`. From 7b4c4f299da3ce19ec84f2344ada723ea4a5d4a9 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 14 Dec 2018 09:39:14 -0600 Subject: [PATCH 32/68] 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 179352dbfefe7708758d61d3544fceb54e97930f Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 14 Dec 2018 15:20:21 -0600 Subject: [PATCH 33/68] remove ProofOfPossessionData --- specs/core/0_beacon-chain.md | 1 - 1 file changed, 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 198c4872a..d8d0290b3 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -34,7 +34,6 @@ - [`Deposit`](#deposit) - [`DepositData`](#depositdata) - [`DepositInput`](#depositinput) - - [`ProofOfPossessionData`](#proofofpossessiondata) - [Exits](#exits) - [`Exit`](#exit) - [Beacon chain blocks](#beacon-chain-blocks) From 62b95fbe334d915910ed838935d1136e48a8b2da Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 14 Dec 2018 15:21:32 -0600 Subject: [PATCH 34/68] fix process_deposit function signature --- specs/core/0_beacon-chain.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index d8d0290b3..2097f6a0e 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1222,8 +1222,7 @@ def process_deposit(state: BeaconState, deposit: int, proof_of_possession: bytes, withdrawal_credentials: Hash32, - randao_commitment: Hash32, - status: int) -> int: + randao_commitment: Hash32) -> int: """ Process a deposit from Ethereum 1.0. Note that this function mutates ``state``. From 829911c0fdd0d2337fda320a6c333ae053eaa3d0 Mon Sep 17 00:00:00 2001 From: vbuterin Date: Fri, 14 Dec 2018 19:55:05 -0500 Subject: [PATCH 35/68] 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 36/68] 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 37/68] 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 425f7d51c96f5b14a994267b668abacff4836ecd Mon Sep 17 00:00:00 2001 From: vbuterin Date: Sat, 15 Dec 2018 05:10:31 -0500 Subject: [PATCH 38/68] Keep randao mixes in the state Response to #295 Also a simplification, as two special cases get replaced: `state.randao_mix` -> `state.latest_randao_mixes[-1]`, and `state.next_seed` -> `state.latest_randao_mixes[-CYCLE_LENGTH-1]`. --- specs/core/0_beacon-chain.md | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 2097f6a0e..8d9f88d86 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -459,8 +459,7 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted 'validator_registry_delta_chain_tip': 'hash32', # For light clients to track deltas # Randomness and committees - 'randao_mix': 'hash32', - 'next_seed': 'hash32', + 'latest_randao_mixes': ['hash32'], 'shard_committees_at_slots': [[ShardCommittee]], 'persistent_committees': [['uint24']], 'persistent_committee_reassignments': [ShardReassignmentRecord], @@ -1154,8 +1153,7 @@ def get_initial_beacon_state(initial_validator_deposits: List[Deposit], validator_registry_delta_chain_tip=ZERO_HASH, # Randomness and committees - randao_mix=ZERO_HASH, - next_seed=ZERO_HASH, + latest_randao_mixes=[ZERO_HASH for _ in range(LATEST_BLOCK_ROOTS_LENGTH)], shard_committees_at_slots=[], persistent_committees=[], persistent_committee_reassignments=[], @@ -1415,7 +1413,7 @@ Below are the processing steps that happen at every `block`. * Let `repeat_hash(x, n) = x if n == 0 else repeat_hash(hash(x), n-1)`. * Let `proposer = state.validator_registry[get_beacon_proposer_index(state, state.slot)]`. * Verify that `repeat_hash(block.randao_reveal, proposer.randao_layers) == proposer.randao_commitment`. -* Set `state.randao_mix = xor(state.randao_mix, block.randao_reveal)`. +* Set `state.latest_randao_mixes = state.latest_randao_mixes[1:] + [xor(state.latest_randao_mixes[-1], block.randao_reveal)] * Set `proposer.randao_commitment = block.randao_reveal`. * Set `proposer.randao_layers = 0`. @@ -1749,15 +1747,14 @@ Also perform the following updates: * Set `state.validator_registry_latest_change_slot = state.slot`. * Set `state.shard_committees_at_slots[:EPOCH_LENGTH] = state.shard_committees_at_slots[EPOCH_LENGTH:]`. -* Set `state.shard_committees_at_slots[EPOCH_LENGTH:] = get_new_shuffling(state.next_seed, state.validator_registry, next_start_shard)` where `next_start_shard = (state.shard_committees_at_slots[-1][-1].shard + 1) % SHARD_COUNT`. -* Set `state.next_seed = state.randao_mix`. +* Set `state.shard_committees_at_slots[EPOCH_LENGTH:] = get_new_shuffling(state.latest_randao_mixes[-CYCLE_LENGTH-1], state.validator_registry, next_start_shard)` where `next_start_shard = (state.shard_committees_at_slots[-1][-1].shard + 1) % SHARD_COUNT`. If a validator registry update does _not_ happen do the following: * Set `state.shard_committees_at_slots[:EPOCH_LENGTH] = state.shard_committees_at_slots[EPOCH_LENGTH:]`. * Let `slots_since_finality = state.slot - state.validator_registry_latest_change_slot`. * Let `start_shard = state.shard_committees_at_slots[0][0].shard`. -* If `slots_since_finality * EPOCH_LENGTH <= MIN_VALIDATOR_REGISTRY_CHANGE_INTERVAL` or `slots_since_finality` is an exact power of 2, set `state.shard_committees_at_slots[EPOCH_LENGTH:] = get_new_shuffling(state.next_seed, state.validator_registry, start_shard)` and set `state.next_seed = state.randao_mix`. Note that `start_shard` is not changed from the last epoch. +* If `slots_since_finality * EPOCH_LENGTH <= MIN_VALIDATOR_REGISTRY_CHANGE_INTERVAL` or `slots_since_finality` is an exact power of 2, set `state.shard_committees_at_slots[EPOCH_LENGTH:] = get_new_shuffling(state.latest_randao_mixes[-CYCLE_LENGTH-1], state.validator_registry, start_shard)`. Note that `start_shard` is not changed from the last epoch. ### Proposer reshuffling @@ -1769,8 +1766,8 @@ num_validators_to_reshuffle = len(active_validator_indices) // SHARD_PERSISTENT_ for i in range(num_validators_to_reshuffle): # Multiplying i to 2 to ensure we have different input to all the required hashes in the shuffling # and none of the hashes used for entropy in this loop will be the same - validator_index = active_validator_indices[hash(state.randao_mix + bytes8(i * 2)) % len(active_validator_indices)] - new_shard = hash(state.randao_mix + bytes8(i * 2 + 1)) % SHARD_COUNT + validator_index = active_validator_indices[hash(state.latest_randao_mixes[-1] + bytes8(i * 2)) % len(active_validator_indices)] + new_shard = hash(state.latest_randao_mixes[-1] + bytes8(i * 2 + 1)) % SHARD_COUNT shard_reassignment_record = ShardReassignmentRecord( validator_index=validator_index, shard=new_shard, From 9e6c1a6244a60e678d4738f20d90a8552a9329ca Mon Sep 17 00:00:00 2001 From: vbuterin Date: Sat, 15 Dec 2018 06:44:18 -0500 Subject: [PATCH 39/68] 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 40/68] 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 41/68] 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 d1aa3b4cd61f1e7ae00400eaa0002edf15025b5b Mon Sep 17 00:00:00 2001 From: vbuterin Date: Mon, 17 Dec 2018 04:44:49 -0500 Subject: [PATCH 42/68] Editing randao_mixes in place instead of as a queue Saves having to re-Merkelize an entire 8192-item list every block. --- specs/core/0_beacon-chain.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 8d9f88d86..e2748214d 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1413,7 +1413,7 @@ Below are the processing steps that happen at every `block`. * Let `repeat_hash(x, n) = x if n == 0 else repeat_hash(hash(x), n-1)`. * Let `proposer = state.validator_registry[get_beacon_proposer_index(state, state.slot)]`. * Verify that `repeat_hash(block.randao_reveal, proposer.randao_layers) == proposer.randao_commitment`. -* Set `state.latest_randao_mixes = state.latest_randao_mixes[1:] + [xor(state.latest_randao_mixes[-1], block.randao_reveal)] +* Set `state.latest_randao_mixes[block.slot % LATEST_BLOCK_ROOTS_LENGTH] = xor(state.latest_randao_mixes[(block.slot - 1) % LATEST_BLOCK_ROOTS_LENGTH], block.randao_reveal)` * Set `proposer.randao_commitment = block.randao_reveal`. * Set `proposer.randao_layers = 0`. @@ -1747,14 +1747,14 @@ Also perform the following updates: * Set `state.validator_registry_latest_change_slot = state.slot`. * Set `state.shard_committees_at_slots[:EPOCH_LENGTH] = state.shard_committees_at_slots[EPOCH_LENGTH:]`. -* Set `state.shard_committees_at_slots[EPOCH_LENGTH:] = get_new_shuffling(state.latest_randao_mixes[-CYCLE_LENGTH-1], state.validator_registry, next_start_shard)` where `next_start_shard = (state.shard_committees_at_slots[-1][-1].shard + 1) % SHARD_COUNT`. +* Set `state.shard_committees_at_slots[EPOCH_LENGTH:] = get_new_shuffling(state.latest_randao_mixes[(block.slot - CYCLE_LENGTH) % LATEST_BLOCK_ROOTS_LENGTH], state.validator_registry, next_start_shard)` where `next_start_shard = (state.shard_committees_at_slots[-1][-1].shard + 1) % SHARD_COUNT`. If a validator registry update does _not_ happen do the following: * Set `state.shard_committees_at_slots[:EPOCH_LENGTH] = state.shard_committees_at_slots[EPOCH_LENGTH:]`. * Let `slots_since_finality = state.slot - state.validator_registry_latest_change_slot`. * Let `start_shard = state.shard_committees_at_slots[0][0].shard`. -* If `slots_since_finality * EPOCH_LENGTH <= MIN_VALIDATOR_REGISTRY_CHANGE_INTERVAL` or `slots_since_finality` is an exact power of 2, set `state.shard_committees_at_slots[EPOCH_LENGTH:] = get_new_shuffling(state.latest_randao_mixes[-CYCLE_LENGTH-1], state.validator_registry, start_shard)`. Note that `start_shard` is not changed from the last epoch. +* If `slots_since_finality * EPOCH_LENGTH <= MIN_VALIDATOR_REGISTRY_CHANGE_INTERVAL` or `slots_since_finality` is an exact power of 2, set `state.shard_committees_at_slots[EPOCH_LENGTH:] = get_new_shuffling(state.latest_randao_mixes[(block.slot - CYCLE_LENGTH) % LATEST_BLOCK_ROOTS_LENGTH], state.validator_registry, start_shard)`. Note that `start_shard` is not changed from the last epoch. ### Proposer reshuffling From 365437d4c20c2db686ab7d11d5c6417ef263ae2b Mon Sep 17 00:00:00 2001 From: vbuterin Date: Mon, 17 Dec 2018 04:46:28 -0500 Subject: [PATCH 43/68] Forgot to update randao mixes in one place --- 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 e2748214d..ee5c3ff2f 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1766,8 +1766,8 @@ num_validators_to_reshuffle = len(active_validator_indices) // SHARD_PERSISTENT_ for i in range(num_validators_to_reshuffle): # Multiplying i to 2 to ensure we have different input to all the required hashes in the shuffling # and none of the hashes used for entropy in this loop will be the same - validator_index = active_validator_indices[hash(state.latest_randao_mixes[-1] + bytes8(i * 2)) % len(active_validator_indices)] - new_shard = hash(state.latest_randao_mixes[-1] + bytes8(i * 2 + 1)) % SHARD_COUNT + validator_index = active_validator_indices[hash(state.latest_randao_mixes[block.slot % LATEST_BLOCK_ROOTS_LENGTH] + bytes8(i * 2)) % len(active_validator_indices)] + new_shard = hash(state.latest_randao_mixes[block.slot % LATEST_BLOCK_ROOTS_LENGTH] + bytes8(i * 2 + 1)) % SHARD_COUNT shard_reassignment_record = ShardReassignmentRecord( validator_index=validator_index, shard=new_shard, From e9f986971ed1d990a3954ad576165ee909cd5837 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Mon, 17 Dec 2018 09:08:13 -0500 Subject: [PATCH 44/68] 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 45/68] 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 46/68] 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 47/68] 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 48/68] 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 49/68] 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 50/68] 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 51/68] 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 52/68] 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 9c620d3853832d9b3b2ac8522239d0d318bc3eb2 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Mon, 17 Dec 2018 13:53:04 -0500 Subject: [PATCH 53/68] 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 ee5c3ff2f..01e30a488 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1747,7 +1747,7 @@ Also perform the following updates: * Set `state.validator_registry_latest_change_slot = state.slot`. * Set `state.shard_committees_at_slots[:EPOCH_LENGTH] = state.shard_committees_at_slots[EPOCH_LENGTH:]`. -* Set `state.shard_committees_at_slots[EPOCH_LENGTH:] = get_new_shuffling(state.latest_randao_mixes[(block.slot - CYCLE_LENGTH) % LATEST_BLOCK_ROOTS_LENGTH], state.validator_registry, next_start_shard)` where `next_start_shard = (state.shard_committees_at_slots[-1][-1].shard + 1) % SHARD_COUNT`. +* Set `state.shard_committees_at_slots[EPOCH_LENGTH:] = get_new_shuffling(state.latest_randao_mixes[(state.slot - CYCLE_LENGTH) % LATEST_BLOCK_ROOTS_LENGTH], state.validator_registry, next_start_shard)` where `next_start_shard = (state.shard_committees_at_slots[-1][-1].shard + 1) % SHARD_COUNT`. If a validator registry update does _not_ happen do the following: From eee26d7b69d611f7e142a4e28231d9439e8cf8ae Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Mon, 17 Dec 2018 13:53:17 -0500 Subject: [PATCH 54/68] 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 01e30a488..fdea52488 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1766,7 +1766,7 @@ num_validators_to_reshuffle = len(active_validator_indices) // SHARD_PERSISTENT_ for i in range(num_validators_to_reshuffle): # Multiplying i to 2 to ensure we have different input to all the required hashes in the shuffling # and none of the hashes used for entropy in this loop will be the same - validator_index = active_validator_indices[hash(state.latest_randao_mixes[block.slot % LATEST_BLOCK_ROOTS_LENGTH] + bytes8(i * 2)) % len(active_validator_indices)] + validator_index = active_validator_indices[hash(state.latest_randao_mixes[state.slot % LATEST_BLOCK_ROOTS_LENGTH] + bytes8(i * 2)) % len(active_validator_indices)] new_shard = hash(state.latest_randao_mixes[block.slot % LATEST_BLOCK_ROOTS_LENGTH] + bytes8(i * 2 + 1)) % SHARD_COUNT shard_reassignment_record = ShardReassignmentRecord( validator_index=validator_index, From e16c98b8540c0b23b609de3abbe7158d38430940 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Mon, 17 Dec 2018 13:53:35 -0500 Subject: [PATCH 55/68] 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 fdea52488..50adee4ed 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1754,7 +1754,7 @@ If a validator registry update does _not_ happen do the following: * Set `state.shard_committees_at_slots[:EPOCH_LENGTH] = state.shard_committees_at_slots[EPOCH_LENGTH:]`. * Let `slots_since_finality = state.slot - state.validator_registry_latest_change_slot`. * Let `start_shard = state.shard_committees_at_slots[0][0].shard`. -* If `slots_since_finality * EPOCH_LENGTH <= MIN_VALIDATOR_REGISTRY_CHANGE_INTERVAL` or `slots_since_finality` is an exact power of 2, set `state.shard_committees_at_slots[EPOCH_LENGTH:] = get_new_shuffling(state.latest_randao_mixes[(block.slot - CYCLE_LENGTH) % LATEST_BLOCK_ROOTS_LENGTH], state.validator_registry, start_shard)`. Note that `start_shard` is not changed from the last epoch. +* If `slots_since_finality * EPOCH_LENGTH <= MIN_VALIDATOR_REGISTRY_CHANGE_INTERVAL` or `slots_since_finality` is an exact power of 2, set `state.shard_committees_at_slots[EPOCH_LENGTH:] = get_new_shuffling(state.latest_randao_mixes[(state.slot - CYCLE_LENGTH) % LATEST_BLOCK_ROOTS_LENGTH], state.validator_registry, start_shard)`. Note that `start_shard` is not changed from the last epoch. ### Proposer reshuffling From 49ce718cc2e1ba4d56743b9fa593c53a8cad6f54 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Mon, 17 Dec 2018 13:53:42 -0500 Subject: [PATCH 56/68] 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 50adee4ed..afd39a0ec 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1767,7 +1767,7 @@ for i in range(num_validators_to_reshuffle): # Multiplying i to 2 to ensure we have different input to all the required hashes in the shuffling # and none of the hashes used for entropy in this loop will be the same validator_index = active_validator_indices[hash(state.latest_randao_mixes[state.slot % LATEST_BLOCK_ROOTS_LENGTH] + bytes8(i * 2)) % len(active_validator_indices)] - new_shard = hash(state.latest_randao_mixes[block.slot % LATEST_BLOCK_ROOTS_LENGTH] + bytes8(i * 2 + 1)) % SHARD_COUNT + new_shard = hash(state.latest_randao_mixes[state.slot % LATEST_BLOCK_ROOTS_LENGTH] + bytes8(i * 2 + 1)) % SHARD_COUNT shard_reassignment_record = ShardReassignmentRecord( validator_index=validator_index, shard=new_shard, From cc5cef52cb36ab84791c9d4fd1b3e577ab9bc538 Mon Sep 17 00:00:00 2001 From: vbuterin Date: Mon, 17 Dec 2018 14:04:04 -0500 Subject: [PATCH 57/68] Separated block roots and randao mixes length, and fixed per-slot randao updates --- specs/core/0_beacon-chain.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index afd39a0ec..1c9206a7f 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -166,6 +166,7 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted | `BLS_WITHDRAWAL_PREFIX_BYTE` | `0x00` | - | | `MAX_CASPER_VOTES` | `2**10` (= 1,024) | votes | | `LATEST_BLOCK_ROOTS_LENGTH` | `2**13` (= 8,192) | block roots | +| `LATEST_RANDAO_MIXES_LENGTH` | `2**13` (= 8,192) | block roots | | `EMPTY_SIGNATURE` | `[bytes48(0), bytes48(0)]` | - | * For the safety of crosslinks a minimum committee size of 111 is [recommended](https://vitalik.ca/files/Ithaca201807_Sharding.pdf). (Unbiasable randomness with a Verifiable Delay Function (VDF) will improve committee robustness and lower the safe minimum committee size.) The shuffling algorithm generally ensures (assuming sufficient validators) committee sizes at least `TARGET_COMMITTEE_SIZE // 2`. @@ -1153,7 +1154,7 @@ def get_initial_beacon_state(initial_validator_deposits: List[Deposit], validator_registry_delta_chain_tip=ZERO_HASH, # Randomness and committees - latest_randao_mixes=[ZERO_HASH for _ in range(LATEST_BLOCK_ROOTS_LENGTH)], + latest_randao_mixes=[ZERO_HASH for _ in range(LATEST_RANDAO_MIXES_LENGTH)], shard_committees_at_slots=[], persistent_committees=[], persistent_committee_reassignments=[], @@ -1387,11 +1388,12 @@ Below are the processing steps that happen at every slot. * Set `state.slot += 1`. * Set `state.validator_registry[get_beacon_proposer_index(state, state.slot)].randao_layers += 1`. +* Set `state.latest_randao_mixes = state.latest_randao_mixes[(block.slot - 1) % LATEST_RANDAO_MIXES_LENGTH]` ### Block roots * Let `previous_block_root` be the `hash_tree_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[(block.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 @@ -1413,7 +1415,7 @@ Below are the processing steps that happen at every `block`. * Let `repeat_hash(x, n) = x if n == 0 else repeat_hash(hash(x), n-1)`. * Let `proposer = state.validator_registry[get_beacon_proposer_index(state, state.slot)]`. * Verify that `repeat_hash(block.randao_reveal, proposer.randao_layers) == proposer.randao_commitment`. -* Set `state.latest_randao_mixes[block.slot % LATEST_BLOCK_ROOTS_LENGTH] = xor(state.latest_randao_mixes[(block.slot - 1) % LATEST_BLOCK_ROOTS_LENGTH], block.randao_reveal)` +* Set `state.latest_randao_mixes[block.slot % LATEST_RANDAO_MIXES_LENGTH] = xor(state.latest_randao_mixes[block.slot % LATEST_RANDAO_MIXES_LENGTH], block.randao_reveal)` * Set `proposer.randao_commitment = block.randao_reveal`. * Set `proposer.randao_layers = 0`. @@ -1747,14 +1749,14 @@ Also perform the following updates: * Set `state.validator_registry_latest_change_slot = state.slot`. * Set `state.shard_committees_at_slots[:EPOCH_LENGTH] = state.shard_committees_at_slots[EPOCH_LENGTH:]`. -* Set `state.shard_committees_at_slots[EPOCH_LENGTH:] = get_new_shuffling(state.latest_randao_mixes[(state.slot - CYCLE_LENGTH) % LATEST_BLOCK_ROOTS_LENGTH], state.validator_registry, next_start_shard)` where `next_start_shard = (state.shard_committees_at_slots[-1][-1].shard + 1) % SHARD_COUNT`. +* Set `state.shard_committees_at_slots[EPOCH_LENGTH:] = get_new_shuffling(state.latest_randao_mixes[(state.slot - EPOCH_LENGTH) % LATEST_RANDAO_MIXES_LENGTH], state.validator_registry, next_start_shard)` where `next_start_shard = (state.shard_committees_at_slots[-1][-1].shard + 1) % SHARD_COUNT`. If a validator registry update does _not_ happen do the following: * Set `state.shard_committees_at_slots[:EPOCH_LENGTH] = state.shard_committees_at_slots[EPOCH_LENGTH:]`. * Let `slots_since_finality = state.slot - state.validator_registry_latest_change_slot`. * Let `start_shard = state.shard_committees_at_slots[0][0].shard`. -* If `slots_since_finality * EPOCH_LENGTH <= MIN_VALIDATOR_REGISTRY_CHANGE_INTERVAL` or `slots_since_finality` is an exact power of 2, set `state.shard_committees_at_slots[EPOCH_LENGTH:] = get_new_shuffling(state.latest_randao_mixes[(state.slot - CYCLE_LENGTH) % LATEST_BLOCK_ROOTS_LENGTH], state.validator_registry, start_shard)`. Note that `start_shard` is not changed from the last epoch. +* If `slots_since_finality * EPOCH_LENGTH <= MIN_VALIDATOR_REGISTRY_CHANGE_INTERVAL` or `slots_since_finality` is an exact power of 2, set `state.shard_committees_at_slots[EPOCH_LENGTH:] = get_new_shuffling(state.latest_randao_mixes[(state.slot - CYCLE_LENGTH) % LATEST_RANDAO_MIXES_LENGTH], state.validator_registry, start_shard)`. Note that `start_shard` is not changed from the last epoch. ### Proposer reshuffling @@ -1766,8 +1768,8 @@ num_validators_to_reshuffle = len(active_validator_indices) // SHARD_PERSISTENT_ for i in range(num_validators_to_reshuffle): # Multiplying i to 2 to ensure we have different input to all the required hashes in the shuffling # and none of the hashes used for entropy in this loop will be the same - validator_index = active_validator_indices[hash(state.latest_randao_mixes[state.slot % LATEST_BLOCK_ROOTS_LENGTH] + bytes8(i * 2)) % len(active_validator_indices)] - new_shard = hash(state.latest_randao_mixes[state.slot % LATEST_BLOCK_ROOTS_LENGTH] + bytes8(i * 2 + 1)) % SHARD_COUNT + validator_index = active_validator_indices[hash(state.latest_randao_mixes[state.slot % LATEST_RANDAO_MIXES_LENGTH] + bytes8(i * 2)) % len(active_validator_indices)] + new_shard = hash(state.latest_randao_mixes[state.slot % LATEST_RANDAO_MIXES_LENGTH] + bytes8(i * 2 + 1)) % SHARD_COUNT shard_reassignment_record = ShardReassignmentRecord( validator_index=validator_index, shard=new_shard, From d505aa28fe4a3c258fe7be835a394367cd34b94a Mon Sep 17 00:00:00 2001 From: Dan Burnett Date: Mon, 17 Dec 2018 15:15:37 -0500 Subject: [PATCH 58/68] 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 59/68] 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 60/68] 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 261118011960bf636296dfd5fd79df5cfd111e03 Mon Sep 17 00:00:00 2001 From: vbuterin Date: Tue, 18 Dec 2018 05:33:03 -0500 Subject: [PATCH 61/68] Fixes as per Danny's comments --- specs/core/0_beacon-chain.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 1c9206a7f..75a96b48c 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -166,7 +166,7 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted | `BLS_WITHDRAWAL_PREFIX_BYTE` | `0x00` | - | | `MAX_CASPER_VOTES` | `2**10` (= 1,024) | votes | | `LATEST_BLOCK_ROOTS_LENGTH` | `2**13` (= 8,192) | block roots | -| `LATEST_RANDAO_MIXES_LENGTH` | `2**13` (= 8,192) | block roots | +| `LATEST_RANDAO_MIXES_LENGTH` | `2**13` (= 8,192) | randao mixes | | `EMPTY_SIGNATURE` | `[bytes48(0), bytes48(0)]` | - | * For the safety of crosslinks a minimum committee size of 111 is [recommended](https://vitalik.ca/files/Ithaca201807_Sharding.pdf). (Unbiasable randomness with a Verifiable Delay Function (VDF) will improve committee robustness and lower the safe minimum committee size.) The shuffling algorithm generally ensures (assuming sufficient validators) committee sizes at least `TARGET_COMMITTEE_SIZE // 2`. @@ -916,9 +916,8 @@ def get_block_root(state: BeaconState, """ Returns the block root at a recent ``slot``. """ - earliest_slot_in_array = state.slot - len(state.latest_block_roots) - assert earliest_slot_in_array <= slot < state.slot - return state.latest_block_roots[slot - earliest_slot_in_array] + assert slot > state.slot - LATEST_BLOCK_ROOTS_LENGTH + return state.latest_block_roots[slot % LATEST_BLOCK_ROOTS_LENGTH] ``` `get_block_root(_, s)` should always return `hash_tree_root` of the block in the beacon chain at slot `s`, and `get_shard_committees_at_slot(_, s)` should not change unless the [validator](#dfn-validator) registry changes. @@ -1388,12 +1387,12 @@ Below are the processing steps that happen at every slot. * Set `state.slot += 1`. * Set `state.validator_registry[get_beacon_proposer_index(state, state.slot)].randao_layers += 1`. -* Set `state.latest_randao_mixes = state.latest_randao_mixes[(block.slot - 1) % LATEST_RANDAO_MIXES_LENGTH]` +* Set `state.latest_randao_mixes[state.slot % LATEST_RANDAO_MIXES_LENGTH] = state.latest_randao_mixes[(state.slot - 1) % LATEST_RANDAO_MIXES_LENGTH]` ### Block roots * Let `previous_block_root` be the `hash_tree_root` of the previous beacon block processed in the chain. -* Set `state.latest_block_roots[(block.slot - 1) % LATEST_BLOCK_ROOTS_LENGTH] = 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 @@ -1415,7 +1414,7 @@ Below are the processing steps that happen at every `block`. * Let `repeat_hash(x, n) = x if n == 0 else repeat_hash(hash(x), n-1)`. * Let `proposer = state.validator_registry[get_beacon_proposer_index(state, state.slot)]`. * Verify that `repeat_hash(block.randao_reveal, proposer.randao_layers) == proposer.randao_commitment`. -* Set `state.latest_randao_mixes[block.slot % LATEST_RANDAO_MIXES_LENGTH] = xor(state.latest_randao_mixes[block.slot % LATEST_RANDAO_MIXES_LENGTH], block.randao_reveal)` +* Set `state.latest_randao_mixes[state.slot % LATEST_RANDAO_MIXES_LENGTH] = xor(state.latest_randao_mixes[state.slot % LATEST_RANDAO_MIXES_LENGTH], block.randao_reveal)` * Set `proposer.randao_commitment = block.randao_reveal`. * Set `proposer.randao_layers = 0`. From 49f3746dc79208c23bd46da017b24894efaa32fb Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Tue, 18 Dec 2018 18:58:59 +0800 Subject: [PATCH 62/68] 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 63/68] 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 64/68] 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 65/68] 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 66/68] 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) ``` From 36e26c86a37734b73a0fe503ac8f1d0acc9b9515 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Tue, 18 Dec 2018 12:53:48 -0600 Subject: [PATCH 67/68] fix assert conditions in get_block_hash --- 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 d934ccc98..fa6ae338b 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -902,7 +902,8 @@ def get_block_root(state: BeaconState, """ Returns the block root at a recent ``slot``. """ - assert slot > state.slot - LATEST_BLOCK_ROOTS_LENGTH + assert state.slot <= slot + LATEST_BLOCK_ROOTS_LENGTH + assert slot < state.slot return state.latest_block_roots[slot % LATEST_BLOCK_ROOTS_LENGTH] ``` From 257c83cc2388fce04a06dfb73080cb72ebd26eda Mon Sep 17 00:00:00 2001 From: Anirudha Bose Date: Wed, 19 Dec 2018 12:47:37 +0100 Subject: [PATCH 68/68] Fix typos in the beacon chain spec --- 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 ce2472ace..03786a560 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1057,7 +1057,7 @@ def is_double_vote(attestation_data_1: AttestationData, ```python def is_surround_vote(attestation_data_1: AttestationData, - attestation_data_2: AttestationData) -> bool + attestation_data_2: AttestationData) -> bool: """ Assumes ``attestation_data_1`` is distinct from ``attestation_data_2``. Returns True if the provided ``AttestationData`` are slashable @@ -1067,7 +1067,7 @@ def is_surround_vote(attestation_data_1: AttestationData, """ return ( (attestation_data_1.justified_slot < attestation_data_2.justified_slot) and - (attestat_data_2.justified_slot + 1 == attestation_data_2.slot) and + (attestation_data_2.justified_slot + 1 == attestation_data_2.slot) and (attestation_data_2.slot < attestation_data_1.slot) ) ```