From 80ac62606cdfe5ed00b001a48eaef00093dc4edb Mon Sep 17 00:00:00 2001 From: vbuterin Date: Thu, 28 Feb 2019 21:07:10 -0600 Subject: [PATCH 1/7] 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 2/7] 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 3/7] 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 4/7] 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 5/7] 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 6/7] 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 7/7] 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,