From 5f19622f86de8c858fd689692a40b01cccd80230 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Wed, 2 Jan 2019 20:29:42 -0600 Subject: [PATCH 1/9] Add clarifying comment about where this index is coming from --- specs/core/0_beacon-chain.md | 1 + 1 file changed, 1 insertion(+) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 2f5b1b3f92..fc1ad33235 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -358,6 +358,7 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted # Receipt Merkle branch 'merkle_branch': '[hash32]', # Merkle tree index + # referred to as `deposit_count` in the Ethereum 1.0 deposit contract 'merkle_tree_index': 'uint64', # Deposit data 'deposit_data': DepositData, From dff84c00b0fa7a4ff583f9414f10522d744910a7 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Wed, 2 Jan 2019 20:37:41 -0600 Subject: [PATCH 2/9] Fixes bugs with description of deposit verification. 1. The order of the `deposit_data` serialization does not match the current Vyper contract. The description now matches that serialization. 2. The `deposit.merkle_tree_index` was not being used (at least explicitly) so the text now reflects which inputs are to be used for which parameters in the pseudocode spec that follows. 3. There seems to be a bug where we want the initial leaf to be the `hash` of the `DepositData`, not the data itself. The text now reflects this requirement. --- 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 fc1ad33235..a0887f1405 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1474,8 +1474,8 @@ 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 `DepositInput` followed by 8 bytes for `deposit_data.amount` 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.latest_deposit_root`: +* Let `serialized_deposit_data` be the serialized form of `deposit.deposit_data`. It should be 8 bytes for `deposit_data.value` 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. +* Use the following procedure to verify `deposit.merkle_branch`, setting `leaf=hash(serialized_deposit_data)`, `branch=deposit.merkle_branch`, `depth=DEPOSIT_CONTRACT_TREE_DEPTH`, `index=deposit.merkle_tree_index`, and `root=state.processed_pow_receipt_root`: ```python def verify_merkle_branch(leaf: Hash32, branch: [Hash32], depth: int, index: int, root: Hash32) -> bool: From 4ea430207b6ff4fe0f753948498f1bfae2299f2c Mon Sep 17 00:00:00 2001 From: Justin Date: Fri, 4 Jan 2019 16:52:25 +0000 Subject: [PATCH 3/9] Update 0_beacon-chain.md --- specs/core/0_beacon-chain.md | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index a0887f1405..15ae02edaa 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -355,12 +355,11 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted ```python { - # Receipt Merkle branch - 'merkle_branch': '[hash32]', - # Merkle tree index - # referred to as `deposit_count` in the Ethereum 1.0 deposit contract - 'merkle_tree_index': 'uint64', - # Deposit data + # Branch in the deposit tree + 'branch': '[hash32]', + # Index in the deposit tree + 'index': 'uint64', + # Data 'deposit_data': DepositData, } ``` @@ -667,7 +666,7 @@ 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 + TWO_TO_POWER_OF_TREE_DEPTH + index: uint256 = self.deposit_tree_index + TWO_TO_POWER_OF_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_input) @@ -680,7 +679,7 @@ def deposit(deposit_input: bytes[2048]): index /= 2 self.deposit_tree[index] = sha3(concat(self.deposit_tree[index * 2], self.deposit_tree[index * 2 + 1])) - self.deposit_count += 1 + self.deposit_tree_index += 1 if msg.value == as_wei_value(MAX_DEPOSIT, "ether"): self.full_deposit_count += 1 if self.full_deposit_count == CHAIN_START_FULL_DEPOSIT_THRESHOLD: @@ -1475,7 +1474,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 8 bytes for `deposit_data.value` 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. -* Use the following procedure to verify `deposit.merkle_branch`, setting `leaf=hash(serialized_deposit_data)`, `branch=deposit.merkle_branch`, `depth=DEPOSIT_CONTRACT_TREE_DEPTH`, `index=deposit.merkle_tree_index`, and `root=state.processed_pow_receipt_root`: +* Verify that `verify_merkle_branch(hash(serialized_deposit_data), deposit.branch, DEPOSIT_CONTRACT_TREE_DEPTH, deposit.index)` is `True`. ```python def verify_merkle_branch(leaf: Hash32, branch: [Hash32], depth: int, index: int, root: Hash32) -> bool: From 6f5a8655088914f197fa4233853ca83418ae3f85 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Wed, 9 Jan 2019 14:35:26 -0600 Subject: [PATCH 4/9] Reorder type so the ssz serialization matches other uses There is an order based on the Vyper deposit contract which should be maintained here. There is also a reference to it when processing `Deposit` messages. This commit corrects the order here so all serializations will match. --- 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 15ae02edaa..c9257620da 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -368,12 +368,12 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted ```python { - # Deposit input - 'deposit_input': DepositInput, # Amount in Gwei 'amount': 'uint64', # Timestamp from deposit contract 'timestamp': 'uint64', + # Deposit input + 'deposit_input': DepositInput, } ``` From c5de2fe710ac82870f3e7fa14c7be4c41872d828 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Wed, 9 Jan 2019 14:37:51 -0600 Subject: [PATCH 5/9] Add missing deposit root when performing Merkle verification --- 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 c9257620da..3cb62fdc79 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1470,11 +1470,12 @@ For each `attestation` in `block.body.attestations`: Verify that `len(block.body.deposits) <= MAX_DEPOSITS`. [TODO: add logic to ensure that deposits from 1.0 chain are processed in order] +[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.value` 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 `verify_merkle_branch(hash(serialized_deposit_data), deposit.branch, DEPOSIT_CONTRACT_TREE_DEPTH, deposit.index)` is `True`. +* Verify that `verify_merkle_branch(hash(serialized_deposit_data), deposit.branch, DEPOSIT_CONTRACT_TREE_DEPTH, deposit.index, state.latest_deposit_root)` is `True`. ```python def verify_merkle_branch(leaf: Hash32, branch: [Hash32], depth: int, index: int, root: Hash32) -> bool: From f49f7eddf99ed200af2897068b655e735159d439 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Wed, 9 Jan 2019 14:44:06 -0600 Subject: [PATCH 6/9] Use the correct name for the `amount` field --- 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 3cb62fdc79..b7cdae1684 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1474,7 +1474,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 8 bytes for `deposit_data.value` 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. +* 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 `verify_merkle_branch(hash(serialized_deposit_data), deposit.branch, DEPOSIT_CONTRACT_TREE_DEPTH, deposit.index, state.latest_deposit_root)` is `True`. ```python From 7a6854aab97a3969b8da76ce3406cd2d637186fd Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Wed, 9 Jan 2019 16:52:43 -0600 Subject: [PATCH 7/9] Fix variable name that was lost in botched rebase --- 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 b7cdae1684..dfe7f3fa33 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -666,7 +666,7 @@ 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_tree_index + TWO_TO_POWER_OF_TREE_DEPTH + index: uint256 = self.deposit_count + TWO_TO_POWER_OF_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_input) @@ -679,7 +679,7 @@ def deposit(deposit_input: bytes[2048]): index /= 2 self.deposit_tree[index] = sha3(concat(self.deposit_tree[index * 2], self.deposit_tree[index * 2 + 1])) - self.deposit_tree_index += 1 + self.deposit_count += 1 if msg.value == as_wei_value(MAX_DEPOSIT, "ether"): self.full_deposit_count += 1 if self.full_deposit_count == CHAIN_START_FULL_DEPOSIT_THRESHOLD: From d62834654f192115fb66868efe002e5c837edbf6 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Wed, 9 Jan 2019 17:02:19 -0600 Subject: [PATCH 8/9] Broadcast `merkle_tree_index` in lieu of the deposit count --- 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 dfe7f3fa33..f7b7247f6f 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -653,7 +653,7 @@ DEPOSIT_CONTRACT_TREE_DEPTH: constant(uint256) = 32 TWO_TO_POWER_OF_TREE_DEPTH: constant(uint256) = 4294967296 # 2**32 SECONDS_PER_DAY: constant(uint256) = 86400 -Deposit: event({previous_deposit_root: bytes32, data: bytes[2064], deposit_count: uint256}) +Deposit: event({previous_deposit_root: bytes32, data: bytes[2064], merkle_tree_index: uint256}) ChainStart: event({deposit_root: bytes32, time: bytes[8]}) deposit_tree: map(uint256, bytes32) @@ -666,18 +666,18 @@ 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 + TWO_TO_POWER_OF_TREE_DEPTH + merkle_tree_index: uint256 = self.deposit_count + TWO_TO_POWER_OF_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_input) - log.Deposit(self.deposit_tree[1], deposit_data, self.deposit_count) + log.Deposit(self.deposit_tree[1], deposit_data, merkle_tree_index) # add deposit to merkle tree - self.deposit_tree[index] = sha3(deposit_data) + self.deposit_tree[merkle_tree_index] = sha3(deposit_data) for i in range(DEPOSIT_CONTRACT_TREE_DEPTH): - index /= 2 - self.deposit_tree[index] = sha3(concat(self.deposit_tree[index * 2], self.deposit_tree[index * 2 + 1])) + merkle_tree_index /= 2 + self.deposit_tree[merkle_tree_index] = sha3(concat(self.deposit_tree[merkle_tree_index * 2], self.deposit_tree[merkle_tree_index * 2 + 1])) self.deposit_count += 1 if msg.value == as_wei_value(MAX_DEPOSIT, "ether"): From 4cf06d908adf1b5a438623d3e90182cee5f501f2 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Wed, 9 Jan 2019 17:18:15 -0600 Subject: [PATCH 9/9] Truncate the index into the Merkle tree to bytes[8] The beacon chain expects a `uint64` in part to avoid big-int computation. This commit updates the `Deposit` log so that it broadcasts data of the appropriate size. --- specs/core/0_beacon-chain.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index f7b7247f6f..5648d20ed7 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -653,7 +653,7 @@ DEPOSIT_CONTRACT_TREE_DEPTH: constant(uint256) = 32 TWO_TO_POWER_OF_TREE_DEPTH: constant(uint256) = 4294967296 # 2**32 SECONDS_PER_DAY: constant(uint256) = 86400 -Deposit: event({previous_deposit_root: bytes32, data: bytes[2064], merkle_tree_index: uint256}) +Deposit: event({previous_deposit_root: bytes32, data: bytes[2064], merkle_tree_index: bytes[8]}) ChainStart: event({deposit_root: bytes32, time: bytes[8]}) deposit_tree: map(uint256, bytes32) @@ -666,18 +666,19 @@ def deposit(deposit_input: bytes[2048]): assert msg.value >= as_wei_value(MIN_DEPOSIT, "ether") assert msg.value <= as_wei_value(MAX_DEPOSIT, "ether") - merkle_tree_index: uint256 = self.deposit_count + TWO_TO_POWER_OF_TREE_DEPTH + index: uint256 = self.deposit_count + TWO_TO_POWER_OF_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_input) + merkle_tree_index: bytes[8] = slice(concat("", convert(index, bytes32)), start=24, len=8) log.Deposit(self.deposit_tree[1], deposit_data, merkle_tree_index) # add deposit to merkle tree - self.deposit_tree[merkle_tree_index] = sha3(deposit_data) + self.deposit_tree[index] = sha3(deposit_data) for i in range(DEPOSIT_CONTRACT_TREE_DEPTH): - merkle_tree_index /= 2 - self.deposit_tree[merkle_tree_index] = sha3(concat(self.deposit_tree[merkle_tree_index * 2], self.deposit_tree[merkle_tree_index * 2 + 1])) + index /= 2 + self.deposit_tree[index] = sha3(concat(self.deposit_tree[index * 2], self.deposit_tree[index * 2 + 1])) self.deposit_count += 1 if msg.value == as_wei_value(MAX_DEPOSIT, "ether"):