From b2c53045fcb4879d6f7b01ab2cf72946bae0ee15 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Tue, 26 Feb 2019 15:55:27 -0700 Subject: [PATCH 01/10] make get_beacon_proposer_index safe for next epoch --- specs/core/0_beacon-chain.md | 12 ++++++++++-- specs/validator/0_beacon-chain-validator.md | 3 +-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 6bff0f705..0592919e4 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -967,11 +967,19 @@ def generate_seed(state: BeaconState, ```python def get_beacon_proposer_index(state: BeaconState, - slot: Slot) -> ValidatorIndex: + slot: Slot, + registry_change: bool=False)) -> ValidatorIndex: """ Return the beacon proposer index for the ``slot``. """ - first_committee, _ = get_crosslink_committees_at_slot(state, slot)[0] + epoch = slot_to_epoch(slot) + current_epoch = get_current_epoch(state) + previous_epoch = get_previous_epoch(state) + next_epoch = current_epoch + 1 + + assert previous_epoch <= epoch <= next_epoch + + first_committee, _ = get_crosslink_committees_at_slot(state, slot, registry_change)[0] return first_committee[slot % len(first_committee)] ``` diff --git a/specs/validator/0_beacon-chain-validator.md b/specs/validator/0_beacon-chain-validator.md index 1523fa507..949a5e429 100644 --- a/specs/validator/0_beacon-chain-validator.md +++ b/specs/validator/0_beacon-chain-validator.md @@ -371,8 +371,7 @@ def get_committee_assignment( if len(selected_committees) > 0: validators = selected_committees[0][0] shard = selected_committees[0][1] - first_committee_at_slot = crosslink_committees[0][0] # List[ValidatorIndex] - is_proposer = first_committee_at_slot[slot % len(first_committee_at_slot)] == validator_index + is_proposer = validator_index == get_beacon_proposer_index(state, slot, registry_change) assignment = (validators, shard, slot, is_proposer) return assignment From 34091d70ec9bc2fae0eda3256b9bad3e30dff841 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Thu, 28 Feb 2019 16:30:46 +0800 Subject: [PATCH 02/10] Fix typo --- specs/core/0_beacon-chain.md | 3 ++- specs/validator/0_beacon-chain-validator.md | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 0592919e4..ba22c716b 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -55,6 +55,7 @@ - [Helper functions](#helper-functions) - [`hash`](#hash) - [`hash_tree_root`](#hash_tree_root) + - [`signed_root`](#signed_root) - [`slot_to_epoch`](#slot_to_epoch) - [`get_previous_epoch`](#get_previous_epoch) - [`get_current_epoch`](#get_current_epoch) @@ -968,7 +969,7 @@ def generate_seed(state: BeaconState, ```python def get_beacon_proposer_index(state: BeaconState, slot: Slot, - registry_change: bool=False)) -> ValidatorIndex: + registry_change: bool=False) -> ValidatorIndex: """ Return the beacon proposer index for the ``slot``. """ diff --git a/specs/validator/0_beacon-chain-validator.md b/specs/validator/0_beacon-chain-validator.md index 949a5e429..e1083c5c5 100644 --- a/specs/validator/0_beacon-chain-validator.md +++ b/specs/validator/0_beacon-chain-validator.md @@ -50,7 +50,7 @@ __NOTICE__: This document is a work-in-progress for researchers and implementers - [Aggregation bitfield](#aggregation-bitfield) - [Custody bitfield](#custody-bitfield) - [Aggregate signature](#aggregate-signature) - - [Validator assigments](#validator-assignments) + - [Validator assignments](#validator-assignments) - [Lookahead](#lookahead) - [How to avoid slashing](#how-to-avoid-slashing) - [Proposer slashing](#proposer-slashing) @@ -371,7 +371,7 @@ def get_committee_assignment( if len(selected_committees) > 0: validators = selected_committees[0][0] shard = selected_committees[0][1] - is_proposer = validator_index == get_beacon_proposer_index(state, slot, registry_change) + is_proposer = validator_index == get_beacon_proposer_index(state, slot, registry_change=registry_change) assignment = (validators, shard, slot, is_proposer) return assignment From 80ac62606cdfe5ed00b001a48eaef00093dc4edb Mon Sep 17 00:00:00 2001 From: vbuterin Date: Thu, 28 Feb 2019 21:07:10 -0600 Subject: [PATCH 03/10] Unified deposit processing between genesis and transaction --- specs/core/0_beacon-chain.md | 77 +++++++++++++++++++++--------------- 1 file changed, 46 insertions(+), 31 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 3ea4d4101..dd6f440d6 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -76,6 +76,7 @@ - [`generate_seed`](#generate_seed) - [`get_beacon_proposer_index`](#get_beacon_proposer_index) - [`merkle_root`](#merkle_root) + - [`verify_merkle_branch`](#verify_merkle_branch) - [`get_attestation_participants`](#get_attestation_participants) - [`is_power_of_two`](#is_power_of_two) - [`int_to_bytes1`, `int_to_bytes2`, ...](#int_to_bytes1-int_to_bytes2-) @@ -990,6 +991,22 @@ def merkle_root(values: List[Bytes32]) -> Bytes32: return o[1] ``` +### `verify_merkle_branch` + +```python +def verify_merkle_branch(leaf: Bytes32, branch: List[Bytes32], depth: int, index: int, root: Bytes32) -> bool: + """ + Verify that the given ``leaf`` is on the merkle branch ``branch``. + """ + value = leaf + for i in range(depth): + if index // (2**i) % 2: + value = hash(branch[i] + value) + else: + value = hash(value + branch[i]) + return value == root +``` + ### `get_attestation_participants` ```python @@ -1236,6 +1253,32 @@ def process_deposit(state: BeaconState, deposit: Deposit) -> None: """ deposit_input = deposit.deposit_data.deposit_input + # Should equal 8 bytes for deposit_data.amount + + # 8 bytes for deposit_data.timestamp + + # 176 bytes for deposit_data.deposit_input + # It should match the deposit_data in the eth1.0 deposit contract + serialized_deposit_data = ssz_serialize(deposit.deposit_data) + # Deposits must be processed in order + assert deposit.index == state.deposit_index + + # Verify the Merkle branch + merkle_branch_is_valid = verify_merkle_branch( + leaf=hash(serialized_deposit_data), + branch=deposit.branch, + depth=DEPOSIT_CONTRACT_TREE_DEPTH, + index=deposit.index, + root=state.latest_eth1_data.deposit_root + ) + if not merkle_branch_is_valid: + return + + # Increment the next deposit index we are expecting. Note that this + # needs to be done here because while the deposit contract will never + # create an invalid Merkle branch, it may admit an invalid deposit + # object, and we need to be able to skip over it + state.deposit_index += 1 + + # Verify the proof of possession proof_is_valid = bls_verify( pubkey=deposit_input.pubkey, message_hash=signed_root(deposit_input, "proof_of_possession"), @@ -1247,7 +1290,7 @@ def process_deposit(state: BeaconState, deposit: Deposit) -> None: ) ) - if not proof_is_valid: + if not not proof_is_valid: return validator_pubkeys = [v.pubkey for v in state.validator_registry] @@ -1476,7 +1519,7 @@ def get_genesis_beacon_state(genesis_validator_deposits: List[Deposit], # Ethereum 1.0 chain data latest_eth1_data=latest_eth1_data, eth1_data_votes=[], - deposit_index=len(genesis_validator_deposits) + deposit_index=0, ) # Process genesis deposits @@ -1707,35 +1750,7 @@ For each `attestation` in `block.body.attestations`: Verify that `len(block.body.deposits) <= MAX_DEPOSITS`. -[TODO: update the call to `verify_merkle_branch` below if it needs to change after we process deposits in order] - -For each `deposit` in `block.body.deposits`: - -* Let `serialized_deposit_data` be the serialized form of `deposit.deposit_data`. It should be 8 bytes for `deposit_data.amount` followed by 8 bytes for `deposit_data.timestamp` and then the `DepositInput` bytes. 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. -* Verify that `deposit.index == state.deposit_index`. -* Verify that `verify_merkle_branch(hash(serialized_deposit_data), deposit.branch, DEPOSIT_CONTRACT_TREE_DEPTH, deposit.index, state.latest_eth1_data.deposit_root)` is `True`. - -```python -def verify_merkle_branch(leaf: Bytes32, branch: List[Bytes32], depth: int, index: int, root: Bytes32) -> bool: - """ - Verify that the given ``leaf`` is on the merkle branch ``branch``. - """ - value = leaf - for i in range(depth): - if index // (2**i) % 2: - value = hash(branch[i] + value) - else: - value = hash(value + branch[i]) - return value == root -``` - -* Run the following: - -```python -process_deposit(state, deposit) -``` - -* Set `state.deposit_index += 1`. +For each `deposit` in `block.body.deposits`, run `process_deposit(state, deposit)` ##### Voluntary exits From 087576a7bba6ebae69a0372adf7c38b1a6e97429 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 1 Mar 2019 00:12:45 -0600 Subject: [PATCH 04/10] 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 dd6f440d6..87d48a225 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1257,7 +1257,7 @@ def process_deposit(state: BeaconState, deposit: Deposit) -> None: # 8 bytes for deposit_data.timestamp + # 176 bytes for deposit_data.deposit_input # It should match the deposit_data in the eth1.0 deposit contract - serialized_deposit_data = ssz_serialize(deposit.deposit_data) + serialized_deposit_data = serialize(deposit.deposit_data) # Deposits must be processed in order assert deposit.index == state.deposit_index From 19c3189c1c4e81fd996b2acf8d99ec6c7df50031 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 1 Mar 2019 00:13:22 -0600 Subject: [PATCH 05/10] 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 87d48a225..629fdc041 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1750,7 +1750,7 @@ For each `attestation` in `block.body.attestations`: Verify that `len(block.body.deposits) <= MAX_DEPOSITS`. -For each `deposit` in `block.body.deposits`, run `process_deposit(state, deposit)` +For each `deposit` in `block.body.deposits`, run `process_deposit(state, deposit)`. ##### Voluntary exits From a9be1018d3d83d73873ea9bea2ddd55e7def69d0 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 1 Mar 2019 00:13:32 -0600 Subject: [PATCH 06/10] 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 629fdc041..3f8223520 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1290,7 +1290,7 @@ def process_deposit(state: BeaconState, deposit: Deposit) -> None: ) ) - if not not proof_is_valid: + if not proof_is_valid: return validator_pubkeys = [v.pubkey for v in state.validator_registry] From 236298a8e4f783a7b3fdb3338b4e1c0123d5b575 Mon Sep 17 00:00:00 2001 From: vbuterin Date: Fri, 1 Mar 2019 03:58:18 -0600 Subject: [PATCH 07/10] Hard assert that the Merkle branch is valid --- 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 3f8223520..aea187730 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1269,8 +1269,7 @@ def process_deposit(state: BeaconState, deposit: Deposit) -> None: index=deposit.index, root=state.latest_eth1_data.deposit_root ) - if not merkle_branch_is_valid: - return + assert merkle_branch_is_valid # Increment the next deposit index we are expecting. Note that this # needs to be done here because while the deposit contract will never From 0c24ca9bb0ee023214a99d8f4f62a861f5680635 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 1 Mar 2019 18:59:55 -0600 Subject: [PATCH 08/10] 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 aea187730..f146fff5b 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1267,7 +1267,7 @@ def process_deposit(state: BeaconState, deposit: Deposit) -> None: branch=deposit.branch, depth=DEPOSIT_CONTRACT_TREE_DEPTH, index=deposit.index, - root=state.latest_eth1_data.deposit_root + root=state.latest_eth1_data.deposit_root, ) assert merkle_branch_is_valid From 26179ede5f873c0bde8df390a12246b33d0a4610 Mon Sep 17 00:00:00 2001 From: vbuterin Date: Fri, 1 Mar 2019 19:01:40 -0600 Subject: [PATCH 09/10] branch -> proof --- specs/core/0_beacon-chain.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index f146fff5b..8d0f55505 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -387,7 +387,7 @@ The following data structures are defined as [SimpleSerialize (SSZ)](https://git ```python { # Branch in the deposit tree - 'branch': ['bytes32'], + 'proof': ['bytes32'], # Index in the deposit tree 'index': 'uint64', # Data @@ -994,16 +994,17 @@ def merkle_root(values: List[Bytes32]) -> Bytes32: ### `verify_merkle_branch` ```python -def verify_merkle_branch(leaf: Bytes32, branch: List[Bytes32], depth: int, index: int, root: Bytes32) -> bool: +def verify_merkle_branch(leaf: Bytes32, proof: List[Bytes32], depth: int, index: int, root: Bytes32) -> bool: """ - Verify that the given ``leaf`` is on the merkle branch ``branch``. + Verify that the given ``leaf`` is on the merkle branch ``proof`` + starting with the given ``root``. """ value = leaf for i in range(depth): if index // (2**i) % 2: - value = hash(branch[i] + value) + value = hash(proof[i] + value) else: - value = hash(value + branch[i]) + value = hash(value + proof[i]) return value == root ``` @@ -1264,7 +1265,7 @@ def process_deposit(state: BeaconState, deposit: Deposit) -> None: # Verify the Merkle branch merkle_branch_is_valid = verify_merkle_branch( leaf=hash(serialized_deposit_data), - branch=deposit.branch, + proof=deposit.proof, depth=DEPOSIT_CONTRACT_TREE_DEPTH, index=deposit.index, root=state.latest_eth1_data.deposit_root, From e2ce0d95831a92c91ea86cced387dc51815eec92 Mon Sep 17 00:00:00 2001 From: terence tsao Date: Mon, 4 Mar 2019 06:45:55 -0800 Subject: [PATCH 10/10] Update 0_beacon-chain.md --- 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 0fc48f090..c701f57d1 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1063,7 +1063,7 @@ def get_effective_balance(state: State, index: ValidatorIndex) -> Gwei: ```python def get_total_balance(state: BeaconState, validators: List[ValidatorIndex]) -> Gwei: """ - Return the combined effective balance of an array of validators. + Return the combined effective balance of an array of ``validators``. """ return sum([get_effective_balance(state, i) for i in validators]) ```