From 7f39f79b2e72654920b2e12127cfdfe6ad0088c6 Mon Sep 17 00:00:00 2001 From: Justin Date: Thu, 31 Jan 2019 07:55:27 -0800 Subject: [PATCH 01/46] Use 2*63 for the genesis slot --- 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 d93cb21d7..952f0f9d0 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -199,7 +199,7 @@ Code snippets appearing in `this style` are to be interpreted as Python code. Be | Name | Value | | - | - | | `GENESIS_FORK_VERSION` | `0` | -| `GENESIS_SLOT` | `2**19` | +| `GENESIS_SLOT` | `2**63` | | `GENESIS_EPOCH` | `slot_to_epoch(GENESIS_SLOT)` | | `GENESIS_START_SHARD` | `0` | | `FAR_FUTURE_EPOCH` | `2**64 - 1` | From 5488e7b6a4d20e88072953e4ca2432f3c206e72c Mon Sep 17 00:00:00 2001 From: vbuterin Date: Thu, 31 Jan 2019 10:12:43 -0600 Subject: [PATCH 02/46] SSZ list Merkle hashing change The current spec is arguably inconsistent, in that if a set of N values gets chunked into M chunks where M is not an exact power of 2, the chunks between M and next_power_of_2(M) are filled with SSZ_CHUNK_SIZE zero bytes each, but the last chunk is not padded, and could be arbitrarily short (eg. if the values are 4 bytes and there are 257 of them, then that gets serialized into eight chunks chunks where the first four are 64 values each, the fifth is 4 bytes corresponding to the last value, and the last three chunks are SSZ_CHUNK_SIZE zero bytes). This PR fills every chunk up to exactly SSZ_CHUNK_SIZE bytes for consistency. --- specs/simple-serialize.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/specs/simple-serialize.md b/specs/simple-serialize.md index 13cc47299..2296a47c1 100644 --- a/specs/simple-serialize.md +++ b/specs/simple-serialize.md @@ -385,7 +385,7 @@ Return the hash of the serialization of the value. #### List/Vectors -First, we define some helpers and then the Merkle tree function. +First, we define some helpers and then the Merkle tree function. `zpad(input: bytes, length: int) -> bytes` is a helper that extends the given `bytes` value to the desired `length` by adding zero bytes on the right. ```python # Merkle tree hash of a list of homogenous, non-empty items @@ -401,7 +401,7 @@ def merkle_hash(lst): items_per_chunk = SSZ_CHUNK_SIZE // len(lst[0]) # Build a list of chunks based on the number of items in the chunk - chunkz = [b''.join(lst[i:i+items_per_chunk]) for i in range(0, len(lst), items_per_chunk)] + chunkz = [zpad(b''.join(lst[i:i+items_per_chunk]), SSZ_CHUNK_SIZE) for i in range(0, len(lst), items_per_chunk)] else: # Leave large items alone chunkz = lst From 9271e6e31878682888bb051ced9a3c8920d1fb1c Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Thu, 31 Jan 2019 17:47:09 -0600 Subject: [PATCH 03/46] Update specs/simple-serialize.md Co-Authored-By: vbuterin --- specs/simple-serialize.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/specs/simple-serialize.md b/specs/simple-serialize.md index 2296a47c1..2838c876c 100644 --- a/specs/simple-serialize.md +++ b/specs/simple-serialize.md @@ -401,7 +401,10 @@ def merkle_hash(lst): items_per_chunk = SSZ_CHUNK_SIZE // len(lst[0]) # Build a list of chunks based on the number of items in the chunk - chunkz = [zpad(b''.join(lst[i:i+items_per_chunk]), SSZ_CHUNK_SIZE) for i in range(0, len(lst), items_per_chunk)] + chunkz = [ + zpad(b''.join(lst[i:i + items_per_chunk]), SSZ_CHUNK_SIZE) + for i in range(0, len(lst), items_per_chunk) + ] else: # Leave large items alone chunkz = lst From acb432ef3ac77dde854f89949ca8b4e9320de490 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Thu, 31 Jan 2019 17:49:51 -0600 Subject: [PATCH 04/46] Update specs/simple-serialize.md Co-Authored-By: vbuterin --- specs/simple-serialize.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/simple-serialize.md b/specs/simple-serialize.md index 2838c876c..1820768b3 100644 --- a/specs/simple-serialize.md +++ b/specs/simple-serialize.md @@ -385,7 +385,7 @@ Return the hash of the serialization of the value. #### List/Vectors -First, we define some helpers and then the Merkle tree function. `zpad(input: bytes, length: int) -> bytes` is a helper that extends the given `bytes` value to the desired `length` by adding zero bytes on the right. +First, we define some helpers and then the Merkle tree function. `def zpad(input: bytes, length: int) -> bytes: return input + b'\x00' * (length - len(input))` is a helper that extends the given `bytes` value to the desired `length` by adding zero bytes on the right. ```python # Merkle tree hash of a list of homogenous, non-empty items From 8ffd9adcaffbb0176471ee5664e62e6fe2d4eaf7 Mon Sep 17 00:00:00 2001 From: vbuterin Date: Thu, 31 Jan 2019 18:03:23 -0600 Subject: [PATCH 05/46] Hash_tree_root -> hash_tree_root_internal Clarifies the distinction between "internal" hash roots (may be < 32 bytes for trivial objects) and "external" ones (zpadded to 32). --- specs/simple-serialize.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/specs/simple-serialize.md b/specs/simple-serialize.md index 13cc47299..d37441ebe 100644 --- a/specs/simple-serialize.md +++ b/specs/simple-serialize.md @@ -371,7 +371,12 @@ return typ(**values), item_index ### Tree Hash -The below `hash_tree_root` algorithm is defined recursively in the case of lists and containers, and it outputs a value equal to or less than 32 bytes in size. For the final output only (ie. not intermediate outputs), if the output is less than 32 bytes, right-zero-pad it to 32 bytes. The goal is collision resistance *within* each type, not between types. +The below `hash_tree_root_internal` algorithm is defined recursively in the case of lists and containers, and it outputs a value equal to or less than 32 bytes in size. For use as a "final output" (eg. for signing), use `hash_tree_root(x) = zpad(hash_tree_root_internal(x), 32)`, where `zpad` is a helper that extends the given `bytes` value to the desired `length` by adding zero bytes on the right: + +``` +def zpad(input: bytes, length: int) -> bytes: + return input + b'\x00' * (length - len(input))` +``` Refer to [the helper function `hash`](https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#hash) of Phase 0 of the [Eth2.0 specs](https://github.com/ethereum/eth2.0-specs) for a definition of the hash function used below, `hash(x)`. @@ -416,20 +421,20 @@ def merkle_hash(lst): return hash(chunkz[0] + datalen) ``` -To `hash_tree_root` a list, we simply do: +To `hash_tree_root_internal` a list, we simply do: ```python -return merkle_hash([hash_tree_root(item) for item in value]) +return merkle_hash([hash_tree_root_internal(item) for item in value]) ``` -Where the inner `hash_tree_root` is a recursive application of the tree-hashing function (returning less than 32 bytes for short single values). +Where the inner `hash_tree_root_internal` is a recursive application of the tree-hashing function (returning less than 32 bytes for short single values). #### Container Recursively tree hash the values in the container in the same order as the fields, and return the hash of the concatenation of the results. ```python -return hash(b''.join([hash_tree_root(getattr(x, field)) for field in value.fields])) +return hash(b''.join([hash_tree_root_internal(getattr(x, field)) for field in value.fields])) ``` ## Implementations From dd197e46a6a2e147b1760a5f4a8730a4c56f0d18 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 1 Feb 2019 22:31:00 +0800 Subject: [PATCH 06/46] Fix `zpad` --- specs/simple-serialize.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/specs/simple-serialize.md b/specs/simple-serialize.md index d37441ebe..b609aa100 100644 --- a/specs/simple-serialize.md +++ b/specs/simple-serialize.md @@ -373,9 +373,9 @@ return typ(**values), item_index The below `hash_tree_root_internal` algorithm is defined recursively in the case of lists and containers, and it outputs a value equal to or less than 32 bytes in size. For use as a "final output" (eg. for signing), use `hash_tree_root(x) = zpad(hash_tree_root_internal(x), 32)`, where `zpad` is a helper that extends the given `bytes` value to the desired `length` by adding zero bytes on the right: -``` +```python def zpad(input: bytes, length: int) -> bytes: - return input + b'\x00' * (length - len(input))` + return input + b'\x00' * (length - len(input)) ``` Refer to [the helper function `hash`](https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#hash) of Phase 0 of the [Eth2.0 specs](https://github.com/ethereum/eth2.0-specs) for a definition of the hash function used below, `hash(x)`. From e0867c030f65e18781fddf6295b879d958aecb88 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 1 Feb 2019 22:34:10 +0800 Subject: [PATCH 07/46] Fix 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 d93cb21d7..1404f5190 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1660,7 +1660,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.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`. From 378e1ba9a681be900e86fd87e9729c657aceb8cf Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Sat, 2 Feb 2019 02:06:53 +0800 Subject: [PATCH 08/46] Misc fixes of `get_next_epoch_crosslink_committees` --- specs/core/0_beacon-chain.md | 2 +- specs/validator/0_beacon-chain-validator.md | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index d93cb21d7..dbc8db0e9 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -833,7 +833,7 @@ def get_next_epoch_committee_count(state: BeaconState) -> int: ```python def get_crosslink_committees_at_slot(state: BeaconState, slot: SlotNumber, - registry_change=False: bool) -> List[Tuple[List[ValidatorIndex], ShardNumber]]: + registry_change: bool=False) -> List[Tuple[List[ValidatorIndex], ShardNumber]]: """ Return the list of ``(committee, shard)`` tuples for the ``slot``. diff --git a/specs/validator/0_beacon-chain-validator.md b/specs/validator/0_beacon-chain-validator.md index b01e7a3af..3df3d758d 100644 --- a/specs/validator/0_beacon-chain-validator.md +++ b/specs/validator/0_beacon-chain-validator.md @@ -345,15 +345,23 @@ Either (2) or (3) occurs if (1) fails. The choice between (2) and (3) is determi ```python def get_next_epoch_crosslink_committees(state: BeaconState, - validator_index: ValidatorIndex) -> List[Tuple[ValidatorIndex], ShardNumber]: + validator_index: ValidatorIndex) -> List[Tuple[List[ValidatorIndex], ShardNumber]]: current_epoch = get_current_epoch(state) next_epoch = current_epoch + 1 next_epoch_start_slot = get_epoch_start_slot(next_epoch) potential_committees = [] - for validator_registry in [False, True]: + for registry_change in [False, True]: for slot in range(next_epoch_start_slot, next_epoch_start_slot + EPOCH_LENGTH): - shard_committees = get_crosslink_committees_at_slot(state, slot, validator_registry) - selected_committees = [committee for committee in shard_committees if validator_index in committee[0]] + crosslink_committees = get_crosslink_committees_at_slot( + state, + slot, + registry_change=registry_change, + ) + selected_committees = [ + committee # type: Tuple[List[ValidatorIndex], ShardNumber] + for committee in crosslink_committees + if validator_index in committee[0] + ] if len(selected_committees) > 0: potential_assignments.append(selected_committees) break From 7e7e5e27956556afceb01970ac9e8393a4ee930f Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Fri, 1 Feb 2019 17:06:04 -0800 Subject: [PATCH 09/46] Removes the source of the Vyper contract from the spec. This change allows for easier maintenance of the code and the spec by uncoupling them. Before any edit to either document resulted in having to synchronize the other. By adding a reference to the canonical repo for the code we avoid having to maintain a duplicate copy here. --- specs/core/0_beacon-chain.md | 85 +++--------------------------------- 1 file changed, 7 insertions(+), 78 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 8a83149ff..ad904332b 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1378,87 +1378,16 @@ When sufficiently many full deposits have been made the deposit contract emits t ### Vyper code -```python -## compiled with v0.1.0-beta.6 ## - -MIN_DEPOSIT_AMOUNT: constant(uint256) = 1000000000 # Gwei -MAX_DEPOSIT_AMOUNT: constant(uint256) = 32000000000 # Gwei -GWEI_PER_ETH: constant(uint256) = 1000000000 # 10**9 -CHAIN_START_FULL_DEPOSIT_THRESHOLD: constant(uint256) = 16384 # 2**14 -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({deposit_root: bytes32, data: bytes[528], merkle_tree_index: bytes[8], branch: bytes32[32]}) -ChainStart: event({deposit_root: bytes32, time: bytes[8]}) - -zerohashes: bytes32[32] -branch: bytes32[32] -deposit_count: uint256 -full_deposit_count: uint256 -chainStarted: public(bool) - -@public -def __init__(): - for i in range(31): - self.zerohashes[i+1] = sha3(concat(self.zerohashes[i], self.zerohashes[i])) - self.branch[i+1] = self.zerohashes[i+1] - -@public -@constant -def get_deposit_root() -> bytes32: - root:bytes32 = 0x0000000000000000000000000000000000000000000000000000000000000000 - size:uint256 = self.deposit_count - for h in range(32): - if size % 2 == 1: - root = sha3(concat(self.branch[h], root)) - else: - root = sha3(concat(root, self.zerohashes[h])) - size /= 2 - return root - -@payable -@public -def deposit(deposit_input: bytes[512]): - assert msg.value >= as_wei_value(MIN_DEPOSIT_AMOUNT, "gwei") - assert msg.value <= as_wei_value(MAX_DEPOSIT_AMOUNT, "gwei") - - index: uint256 = self.deposit_count - deposit_amount: bytes[8] = slice(concat("", convert(msg.value / GWEI_PER_ETH, bytes32)), start=24, len=8) - deposit_timestamp: bytes[8] = slice(concat("", convert(block.timestamp, bytes32)), start=24, len=8) - deposit_data: bytes[528] = concat(deposit_amount, deposit_timestamp, deposit_input) - merkle_tree_index: bytes[8] = slice(concat("", convert(index, bytes32)), start=24, len=8) - - # add deposit to merkle tree - i: int128 = 0 - power_of_two: uint256 = 2 - for _ in range(32): - if (index+1) % power_of_two != 0: - break - i += 1 - power_of_two *= 2 - value:bytes32 = sha3(deposit_data) - for j in range(32): - if j < i: - value = sha3(concat(self.branch[j], value)) - self.branch[i] = value - - self.deposit_count += 1 - - new_deposit_root:bytes32 = self.get_deposit_root() - log.Deposit(new_deposit_root, deposit_data, merkle_tree_index, self.branch) - - if msg.value == as_wei_value(MAX_DEPOSIT_AMOUNT, "gwei"): - self.full_deposit_count += 1 - if self.full_deposit_count == CHAIN_START_FULL_DEPOSIT_THRESHOLD: - timestamp_day_boundary: uint256 = as_unitless_number(block.timestamp) - as_unitless_number(block.timestamp) % SECONDS_PER_DAY + SECONDS_PER_DAY - chainstart_time: bytes[8] = slice(concat("", convert(timestamp_day_boundary, bytes32)), start=24, len=8) - log.ChainStart(new_deposit_root, chainstart_time) - self.chainStarted = True -``` +The source for the Vyper contract lives in a separate repository at [https://github.com/ethereum/deposit_contract](https://github.com/ethereum/deposit_contract). Note: to save ~10x on gas this contract uses a somewhat unintuitive progressive Merkle root calculation algo that requires only O(log(n)) storage. See https://github.com/ethereum/research/blob/master/beacon_chain_impl/progressive_merkle_tree.py for an implementation of the same algo in python tested for correctness. +For convenience, we provide the interface to the contract here: + +* `__init__()`: initializes the contract +* `get_deposit_root() -> bytes32`: returns the current root of the deposit tree +* `deposit(bytes[512])`: adds a deposit instance to the deposit tree, incorporating the input argument and the value transferred in the given call. + ## On startup A valid block with slot `GENESIS_SLOT` (a "genesis block") has the following values. Other validity rules (e.g. requiring a signature) do not apply. From 8d82ee8ce7ea1d3d3bb166683cd497e115cc852b Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 1 Feb 2019 21:02:09 -0800 Subject: [PATCH 10/46] do not mix in epoch to seed in get_shuffling. add epoch to generate_seed --- 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 8a83149ff..1ee3596e8 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -778,7 +778,6 @@ def get_shuffling(seed: Bytes32, committees_per_epoch = get_epoch_committee_count(len(active_validator_indices)) # Shuffle - seed = xor(seed, int_to_bytes32(epoch)) shuffled_active_validator_indices = shuffle(active_validator_indices, seed) # Split the shuffled list into committees_per_epoch pieces @@ -942,7 +941,8 @@ def generate_seed(state: BeaconState, """ return hash( get_randao_mix(state, epoch - SEED_LOOKAHEAD) + - get_active_index_root(state, epoch) + get_active_index_root(state, epoch) + + int_to_bytes32(epoch) ) ``` From 650f4a20dfa25c6aa85a64dfe21aca5de75f8eeb Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Sat, 2 Feb 2019 13:16:39 -0800 Subject: [PATCH 11/46] clarify eth1 that there will be at most 1 --- 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 caaac363f..1c7573453 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1688,7 +1688,7 @@ Below are the processing steps that happen at every `block`. #### Eth1 data -* If `block.eth1_data` equals `eth1_data_vote.eth1_data` for some `eth1_data_vote` in `state.eth1_data_votes`, set `eth1_data_vote.vote_count += 1`. +* If there exists an `eth1_data_vote` in `states.eth1_data_votes` for which `eth1_data_vote.eth1_data == block.eth1_data` (there will be at most one), set `eth1_data_vote.vote_count += 1`. * Otherwise, append to `state.eth1_data_votes` a new `Eth1DataVote(eth1_data=block.eth1_data, vote_count=1)`. #### Operations From e4c4c04e52bde69edf85d36726cbfa3b9aa9fae7 Mon Sep 17 00:00:00 2001 From: terence tsao Date: Sun, 3 Feb 2019 10:36:21 +0100 Subject: [PATCH 12/46] Update 0_beacon-chain.md --- specs/core/0_beacon-chain.md | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 48075c8d4..5c1d158b5 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -54,6 +54,7 @@ - [`hash`](#hash) - [`hash_tree_root`](#hash_tree_root) - [`slot_to_epoch`](#slot_to_epoch) + - [`get_previous_epoch`](#get_previous_epoch) - [`get_current_epoch`](#get_current_epoch) - [`get_epoch_start_slot`](#get_epoch_start_slot) - [`is_active_validator`](#is_active_validator) @@ -639,6 +640,18 @@ def slot_to_epoch(slot: SlotNumber) -> EpochNumber: return slot // EPOCH_LENGTH ``` +### `get_previous_epoch` + +```python +def get_previous_epoch(state: BeaconState) -> EpochNumber: + """` + Return the previous epoch of the given ``state``. + """ + if slot_to_epoch(state.slot) > GENESIS_EPOCH: + return slot_to_epoch(state.slot) - 1 + return slot_to_epoch(state.slot) +``` + ### `get_current_epoch` ```python @@ -844,7 +857,7 @@ def get_crosslink_committees_at_slot(state: BeaconState, """ epoch = slot_to_epoch(slot) current_epoch = get_current_epoch(state) - previous_epoch = current_epoch - 1 if current_epoch > GENESIS_EPOCH else current_epoch + previous_epoch = get_previous_epoch(state) next_epoch = current_epoch + 1 assert previous_epoch <= epoch <= next_epoch @@ -1827,7 +1840,7 @@ The steps below happen when `(state.slot + 1) % EPOCH_LENGTH == 0`. #### Helpers * Let `current_epoch = get_current_epoch(state)`. -* Let `previous_epoch = current_epoch - 1 if current_epoch > GENESIS_EPOCH else current_epoch`. +* Let `previous_epoch = get_previous_epoch(state)`. * Let `next_epoch = current_epoch + 1`. [Validators](#dfn-Validator) attesting during the current epoch: From 969896b0a83bed0e1f412556ff4027f85983fb01 Mon Sep 17 00:00:00 2001 From: Dean Eigenmann Date: Sun, 3 Feb 2019 11:14:02 +0100 Subject: [PATCH 13/46] Update 0_beacon-chain.md --- specs/core/0_beacon-chain.md | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 48075c8d4..b6c4d51f3 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -76,6 +76,7 @@ - [`is_power_of_two`](#is_power_of_two) - [`int_to_bytes1`, `int_to_bytes2`, ...](#int_to_bytes1-int_to_bytes2-) - [`get_effective_balance`](#get_effective_balance) + - [`total_balance`](#total_balance) - [`get_fork_version`](#get_fork_version) - [`get_domain`](#get_domain) - [`get_bitfield_bit`](#get_bitfield_bit) @@ -1027,6 +1028,16 @@ def get_effective_balance(state: State, index: ValidatorIndex) -> Gwei: return min(state.validator_balances[index], MAX_DEPOSIT_AMOUNT) ``` +### `total_balance` + +```python +def total_balance(state: State, validators: [ValidatorIndex]) -> Gwei: + """ + Return the combined effective balance of an array of validators. + """ + sum([get_effective_balance(state, i) for i in validators]) +``` + ### `get_fork_version` ```python @@ -1832,31 +1843,31 @@ The steps below happen when `(state.slot + 1) % EPOCH_LENGTH == 0`. [Validators](#dfn-Validator) attesting during the current epoch: -* Let `current_total_balance = sum([get_effective_balance(state, i) for i in get_active_validator_indices(state.validator_registry, current_epoch)])`. +* Let `current_total_balance = total_balance(state, get_active_validator_indices(state.validator_registry, current_epoch))`. * Let `current_epoch_attestations = [a for a in state.latest_attestations if current_epoch == slot_to_epoch(a.data.slot)]`. (Note: this is the set of attestations of slots in the epoch `current_epoch`, _not_ attestations that got included in the chain during the epoch `current_epoch`.) * Validators justifying the epoch boundary block at the start of the current epoch: * Let `current_epoch_boundary_attestations = [a for a in current_epoch_attestations if a.data.epoch_boundary_root == get_block_root(state, get_epoch_start_slot(current_epoch)) and a.data.justified_epoch == state.justified_epoch]`. * Let `current_epoch_boundary_attester_indices` be the union of the [validator](#dfn-validator) index sets given by `[get_attestation_participants(state, a.data, a.aggregation_bitfield) for a in current_epoch_boundary_attestations]`. - * Let `current_epoch_boundary_attesting_balance = sum([get_effective_balance(state, i) for i in current_epoch_boundary_attester_indices])`. + * Let `current_epoch_boundary_attesting_balance = total_balance(state, current_epoch_boundary_attester_indices)`. [Validators](#dfn-Validator) attesting during the previous epoch: -* Let `previous_total_balance = sum([get_effective_balance(state, i) for i in get_active_validator_indices(state.validator_registry, previous_epoch)])`. +* Let `previous_total_balance = total_balance(state, get_active_validator_indices(state.validator_registry, previous_epoch))`. * Validators that made an attestation during the previous epoch: * Let `previous_epoch_attestations = [a for a in state.latest_attestations if previous_epoch == slot_to_epoch(a.data.slot)]`. * Let `previous_epoch_attester_indices` be the union of the validator index sets given by `[get_attestation_participants(state, a.data, a.aggregation_bitfield) for a in previous_epoch_attestations]`. * Validators targeting the previous justified slot: * Let `previous_epoch_justified_attestations = [a for a in current_epoch_attestations + previous_epoch_attestations if a.data.justified_epoch == state.previous_justified_epoch]`. * Let `previous_epoch_justified_attester_indices` be the union of the validator index sets given by `[get_attestation_participants(state, a.data, a.aggregation_bitfield) for a in previous_epoch_justified_attestations]`. - * Let `previous_epoch_justified_attesting_balance = sum([get_effective_balance(state, i) for i in previous_epoch_justified_attester_indices])`. + * Let `previous_epoch_justified_attesting_balance = total_balance(state, 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.data.epoch_boundary_root == get_block_root(state, get_epoch_start_slot(previous_epoch))]`. * Let `previous_epoch_boundary_attester_indices` be the union of the validator index sets given by `[get_attestation_participants(state, a.data, a.aggregation_bitfield) for a in previous_epoch_boundary_attestations]`. - * Let `previous_epoch_boundary_attesting_balance = sum([get_effective_balance(state, i) for i in previous_epoch_boundary_attester_indices])`. + * Let `previous_epoch_boundary_attesting_balance = total_balance(state, 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.data.beacon_block_root == get_block_root(state, a.data.slot)]`. * Let `previous_epoch_head_attester_indices` be the union of the validator index sets given by `[get_attestation_participants(state, a.data, a.aggregation_bitfield) for a in previous_epoch_head_attestations]`. - * Let `previous_epoch_head_attesting_balance = sum([get_effective_balance(state, i) for i in previous_epoch_head_attester_indices])`. + * Let `previous_epoch_head_attesting_balance = total_balance(state, previous_epoch_head_attester_indices)`. **Note**: `previous_total_balance` and `previous_epoch_boundary_attesting_balance` balance might be marginally different than the actual balances during 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. @@ -1864,10 +1875,9 @@ For every `slot in range(get_epoch_start_slot(previous_epoch), get_epoch_start_s * Let `shard_block_root` be `state.latest_crosslinks[shard].shard_block_root` * Let `attesting_validator_indices(crosslink_committee, shard_block_root)` be the union of the [validator](#dfn-validator) index sets given by `[get_attestation_participants(state, a.data, a.aggregation_bitfield) for a in current_epoch_attestations + previous_epoch_attestations if a.data.shard == shard and a.data.shard_block_root == shard_block_root]`. -* Let `winning_root(crosslink_committee)` be equal to the value of `shard_block_root` such that `sum([get_effective_balance(state, i) for i in attesting_validator_indices(crosslink_committee, shard_block_root)])` is maximized (ties broken by favoring lower `shard_block_root` values). +* Let `winning_root(crosslink_committee)` be equal to the value of `shard_block_root` such that `total_balance(state, attesting_validator_indices(crosslink_committee, shard_block_root))` is maximized (ties broken by favoring lower `shard_block_root` values). * Let `attesting_validators(crosslink_committee)` be equal to `attesting_validator_indices(crosslink_committee, winning_root(crosslink_committee))` for convenience. -* Let `total_attesting_balance(crosslink_committee) = sum([get_effective_balance(state, i) for i in attesting_validators(crosslink_committee)])`. -* Let `total_balance(crosslink_committee) = sum([get_effective_balance(state, i) for i in crosslink_committee])`. +* Let `total_attesting_balance(crosslink_committee) = total_balance(state, attesting_validators(crosslink_committee))`. Define the following helpers to process attestation inclusion rewards and inclusion distance reward/penalty. For every attestation `a` in `previous_epoch_attestations`: @@ -1997,7 +2007,7 @@ def update_validator_registry(state: BeaconState) -> None: # The active validators active_validator_indices = get_active_validator_indices(state.validator_registry, current_epoch) # The total effective balance of active validators - total_balance = sum([get_effective_balance(state, i) for i in active_validator_indices]) + total_balance = total_balance(state, active_validator_indices) # The maximum balance churn in Gwei (for deposits and exits separately) max_balance_churn = max( From 8e16d122be108af8b92f31ca5a014bb9ae99fa97 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Sun, 3 Feb 2019 11:42:12 +0100 Subject: [PATCH 14/46] Update specs/core/0_beacon-chain.md Co-Authored-By: decanus --- 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 b6c4d51f3..e838b23c1 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1031,7 +1031,7 @@ def get_effective_balance(state: State, index: ValidatorIndex) -> Gwei: ### `total_balance` ```python -def total_balance(state: State, validators: [ValidatorIndex]) -> Gwei: +def total_balance(state: BeaconState, validators: List[ValidatorIndex]) -> Gwei: """ Return the combined effective balance of an array of validators. """ From 5c56751cc9cf51e37329c33a5a9c0bd4d87bbfbf Mon Sep 17 00:00:00 2001 From: Dean Eigenmann Date: Sun, 3 Feb 2019 11:43:33 +0100 Subject: [PATCH 15/46] Update 0_beacon-chain.md --- specs/core/0_beacon-chain.md | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index e838b23c1..71426790e 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -76,7 +76,7 @@ - [`is_power_of_two`](#is_power_of_two) - [`int_to_bytes1`, `int_to_bytes2`, ...](#int_to_bytes1-int_to_bytes2-) - [`get_effective_balance`](#get_effective_balance) - - [`total_balance`](#total_balance) + - [`get_total_balance`](#get_total_balance) - [`get_fork_version`](#get_fork_version) - [`get_domain`](#get_domain) - [`get_bitfield_bit`](#get_bitfield_bit) @@ -1028,10 +1028,10 @@ def get_effective_balance(state: State, index: ValidatorIndex) -> Gwei: return min(state.validator_balances[index], MAX_DEPOSIT_AMOUNT) ``` -### `total_balance` +### `get_total_balance` ```python -def total_balance(state: BeaconState, validators: List[ValidatorIndex]) -> Gwei: +def get_total_balance(state: BeaconState, validators: List[ValidatorIndex]) -> Gwei: """ Return the combined effective balance of an array of validators. """ @@ -1843,31 +1843,31 @@ The steps below happen when `(state.slot + 1) % EPOCH_LENGTH == 0`. [Validators](#dfn-Validator) attesting during the current epoch: -* Let `current_total_balance = total_balance(state, get_active_validator_indices(state.validator_registry, current_epoch))`. +* Let `current_total_balance = get_total_balance(state, get_active_validator_indices(state.validator_registry, current_epoch))`. * Let `current_epoch_attestations = [a for a in state.latest_attestations if current_epoch == slot_to_epoch(a.data.slot)]`. (Note: this is the set of attestations of slots in the epoch `current_epoch`, _not_ attestations that got included in the chain during the epoch `current_epoch`.) * Validators justifying the epoch boundary block at the start of the current epoch: * Let `current_epoch_boundary_attestations = [a for a in current_epoch_attestations if a.data.epoch_boundary_root == get_block_root(state, get_epoch_start_slot(current_epoch)) and a.data.justified_epoch == state.justified_epoch]`. * Let `current_epoch_boundary_attester_indices` be the union of the [validator](#dfn-validator) index sets given by `[get_attestation_participants(state, a.data, a.aggregation_bitfield) for a in current_epoch_boundary_attestations]`. - * Let `current_epoch_boundary_attesting_balance = total_balance(state, current_epoch_boundary_attester_indices)`. + * Let `current_epoch_boundary_attesting_balance = get_total_balance(state, current_epoch_boundary_attester_indices)`. [Validators](#dfn-Validator) attesting during the previous epoch: -* Let `previous_total_balance = total_balance(state, get_active_validator_indices(state.validator_registry, previous_epoch))`. +* Let `previous_total_balance = get_total_balance(state, get_active_validator_indices(state.validator_registry, previous_epoch))`. * Validators that made an attestation during the previous epoch: * Let `previous_epoch_attestations = [a for a in state.latest_attestations if previous_epoch == slot_to_epoch(a.data.slot)]`. * Let `previous_epoch_attester_indices` be the union of the validator index sets given by `[get_attestation_participants(state, a.data, a.aggregation_bitfield) for a in previous_epoch_attestations]`. * Validators targeting the previous justified slot: * Let `previous_epoch_justified_attestations = [a for a in current_epoch_attestations + previous_epoch_attestations if a.data.justified_epoch == state.previous_justified_epoch]`. * Let `previous_epoch_justified_attester_indices` be the union of the validator index sets given by `[get_attestation_participants(state, a.data, a.aggregation_bitfield) for a in previous_epoch_justified_attestations]`. - * Let `previous_epoch_justified_attesting_balance = total_balance(state, previous_epoch_justified_attester_indices)`. + * Let `previous_epoch_justified_attesting_balance = get_total_balance(state, 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.data.epoch_boundary_root == get_block_root(state, get_epoch_start_slot(previous_epoch))]`. * Let `previous_epoch_boundary_attester_indices` be the union of the validator index sets given by `[get_attestation_participants(state, a.data, a.aggregation_bitfield) for a in previous_epoch_boundary_attestations]`. - * Let `previous_epoch_boundary_attesting_balance = total_balance(state, previous_epoch_boundary_attester_indices)`. + * Let `previous_epoch_boundary_attesting_balance = get_total_balance(state, 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.data.beacon_block_root == get_block_root(state, a.data.slot)]`. * Let `previous_epoch_head_attester_indices` be the union of the validator index sets given by `[get_attestation_participants(state, a.data, a.aggregation_bitfield) for a in previous_epoch_head_attestations]`. - * Let `previous_epoch_head_attesting_balance = total_balance(state, previous_epoch_head_attester_indices)`. + * Let `previous_epoch_head_attesting_balance = get_total_balance(state, previous_epoch_head_attester_indices)`. **Note**: `previous_total_balance` and `previous_epoch_boundary_attesting_balance` balance might be marginally different than the actual balances during 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. @@ -1875,9 +1875,9 @@ For every `slot in range(get_epoch_start_slot(previous_epoch), get_epoch_start_s * Let `shard_block_root` be `state.latest_crosslinks[shard].shard_block_root` * Let `attesting_validator_indices(crosslink_committee, shard_block_root)` be the union of the [validator](#dfn-validator) index sets given by `[get_attestation_participants(state, a.data, a.aggregation_bitfield) for a in current_epoch_attestations + previous_epoch_attestations if a.data.shard == shard and a.data.shard_block_root == shard_block_root]`. -* Let `winning_root(crosslink_committee)` be equal to the value of `shard_block_root` such that `total_balance(state, attesting_validator_indices(crosslink_committee, shard_block_root))` is maximized (ties broken by favoring lower `shard_block_root` values). +* Let `winning_root(crosslink_committee)` be equal to the value of `shard_block_root` such that `get_total_balance(state, attesting_validator_indices(crosslink_committee, shard_block_root))` is maximized (ties broken by favoring lower `shard_block_root` values). * Let `attesting_validators(crosslink_committee)` be equal to `attesting_validator_indices(crosslink_committee, winning_root(crosslink_committee))` for convenience. -* Let `total_attesting_balance(crosslink_committee) = total_balance(state, attesting_validators(crosslink_committee))`. +* Let `total_attesting_balance(crosslink_committee) = get_total_balance(state, attesting_validators(crosslink_committee))`. Define the following helpers to process attestation inclusion rewards and inclusion distance reward/penalty. For every attestation `a` in `previous_epoch_attestations`: @@ -1916,7 +1916,7 @@ Finally, update the following: For every `slot in range(get_epoch_start_slot(previous_epoch), get_epoch_start_slot(next_epoch))`, let `crosslink_committees_at_slot = get_crosslink_committees_at_slot(state, slot)`. For every `(crosslink_committee, shard)` in `crosslink_committees_at_slot`, compute: -* Set `state.latest_crosslinks[shard] = Crosslink(epoch=current_epoch, shard_block_root=winning_root(crosslink_committee))` if `3 * total_attesting_balance(crosslink_committee) >= 2 * total_balance(crosslink_committee)`. +* Set `state.latest_crosslinks[shard] = Crosslink(epoch=current_epoch, shard_block_root=winning_root(crosslink_committee))` if `3 * total_attesting_balance(crosslink_committee) >= 2 * get_total_balance(crosslink_committee)`. #### Rewards and penalties @@ -1964,7 +1964,7 @@ For every `slot in range(get_epoch_start_slot(previous_epoch), get_epoch_start_s * Let `crosslink_committees_at_slot = get_crosslink_committees_at_slot(state, slot)`. * For every `(crosslink_committee, shard)` in `crosslink_committees_at_slot`: - * If `index in attesting_validators(crosslink_committee)`, `state.validator_balances[index] += base_reward(state, index) * total_attesting_balance(crosslink_committee) // total_balance(crosslink_committee))`. + * If `index in attesting_validators(crosslink_committee)`, `state.validator_balances[index] += base_reward(state, index) * total_attesting_balance(crosslink_committee) // get_total_balance(state, crosslink_committee))`. * If `index not in attesting_validators(crosslink_committee)`, `state.validator_balances[index] -= base_reward(state, index)`. #### Ejections @@ -2007,7 +2007,7 @@ def update_validator_registry(state: BeaconState) -> None: # The active validators active_validator_indices = get_active_validator_indices(state.validator_registry, current_epoch) # The total effective balance of active validators - total_balance = total_balance(state, active_validator_indices) + total_balance = get_total_balance(state, active_validator_indices) # The maximum balance churn in Gwei (for deposits and exits separately) max_balance_churn = max( From 3a6da9839a64a7edc951bef541b47a65554bfed8 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Sun, 3 Feb 2019 14:27:09 +0100 Subject: [PATCH 16/46] Added a note for underflow. Thanks Hsiao Wei! : ) Co-Authored-By: terenc3t --- 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 5c1d158b5..b8815388d 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -646,6 +646,7 @@ def slot_to_epoch(slot: SlotNumber) -> EpochNumber: def get_previous_epoch(state: BeaconState) -> EpochNumber: """` Return the previous epoch of the given ``state``. + If the current epoch is ``GENESIS_EPOCH``, return ``GENESIS_EPOCH``. """ if slot_to_epoch(state.slot) > GENESIS_EPOCH: return slot_to_epoch(state.slot) - 1 From 197fa188936fb21289e86a7e4c88ff5b61815e93 Mon Sep 17 00:00:00 2001 From: vbuterin Date: Sun, 3 Feb 2019 14:26:07 -0600 Subject: [PATCH 17/46] Zpad is already in #543 --- specs/simple-serialize.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/simple-serialize.md b/specs/simple-serialize.md index 1820768b3..6976e9cbe 100644 --- a/specs/simple-serialize.md +++ b/specs/simple-serialize.md @@ -385,7 +385,7 @@ Return the hash of the serialization of the value. #### List/Vectors -First, we define some helpers and then the Merkle tree function. `def zpad(input: bytes, length: int) -> bytes: return input + b'\x00' * (length - len(input))` is a helper that extends the given `bytes` value to the desired `length` by adding zero bytes on the right. +First, we define the Merkle tree function. ```python # Merkle tree hash of a list of homogenous, non-empty items From 8c5868cbe8603c61b54126599aa1fcdbf7243f52 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Sun, 3 Feb 2019 15:20:49 -0800 Subject: [PATCH 18/46] Extend `deposit` API with note about bounds on acceptable values --- 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 ad904332b..02804ab6f 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1386,7 +1386,7 @@ For convenience, we provide the interface to the contract here: * `__init__()`: initializes the contract * `get_deposit_root() -> bytes32`: returns the current root of the deposit tree -* `deposit(bytes[512])`: adds a deposit instance to the deposit tree, incorporating the input argument and the value transferred in the given call. +* `deposit(bytes[512])`: adds a deposit instance to the deposit tree, incorporating the input argument and the value transferred in the given call. Note: the amount of value transferred *must* be within `MIN_DEPOSIT_AMOUNT` and `MAX_DEPOSIT_AMOUNT`, inclusive. Each of these constants are specified in units of Gwei. ## On startup From 8755dc34d51ac88c3cd35b76cc8ef9544abb294c Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Sun, 3 Feb 2019 15:22:03 -0800 Subject: [PATCH 19/46] Add direct link to validator registration contract --- 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 02804ab6f..016d773e4 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1378,7 +1378,7 @@ When sufficiently many full deposits have been made the deposit contract emits t ### Vyper code -The source for the Vyper contract lives in a separate repository at [https://github.com/ethereum/deposit_contract](https://github.com/ethereum/deposit_contract). +The source for the Vyper contract lives in a [separate repository](https://github.com/ethereum/deposit_contract) at [https://github.com/ethereum/deposit_contract/blob/master/deposit_contract/contracts/validator_registration.v.py](https://github.com/ethereum/deposit_contract/blob/master/deposit_contract/contracts/validator_registration.v.py). Note: to save ~10x on gas this contract uses a somewhat unintuitive progressive Merkle root calculation algo that requires only O(log(n)) storage. See https://github.com/ethereum/research/blob/master/beacon_chain_impl/progressive_merkle_tree.py for an implementation of the same algo in python tested for correctness. From 147ee2f991f513c0962f5b610f431f86b92a0f88 Mon Sep 17 00:00:00 2001 From: Taras Bobrovytsky Date: Mon, 4 Feb 2019 01:49:16 -0600 Subject: [PATCH 20/46] Fix get_total_balance() --- 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 788876689..cc78c8b71 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1049,7 +1049,7 @@ def get_total_balance(state: BeaconState, validators: List[ValidatorIndex]) -> G """ Return the combined effective balance of an array of validators. """ - sum([get_effective_balance(state, i) for i in validators]) + return sum([get_effective_balance(state, i) for i in validators]) ``` ### `get_fork_version` From 867dea3473733946d0eb51b8e3132eb3ccacfb2c Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Tue, 5 Feb 2019 19:16:10 +0800 Subject: [PATCH 21/46] Fix `verify_bitfield` --- specs/core/0_beacon-chain.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index cc78c8b71..ed5d1b3b3 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1099,9 +1099,11 @@ def verify_bitfield(bitfield: bytes, committee_size: int) -> bool: if len(bitfield) != (committee_size + 7) // 8: return False - for i in range(committee_size + 1, committee_size - committee_size % 8 + 8): - if get_bitfield_bit(bitfield, i) == 0b1: - return False + # Check if `bitfield` has padding zeros + if committee_size % 8 != 0: + for i in range(committee_size, committee_size - committee_size % 8 + 8): + if get_bitfield_bit(bitfield, i) == 0b1: + return False return True ``` From e5788f5751a9a0be34d02ed72ab26ad3dddd12f6 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Wed, 6 Feb 2019 01:11:00 +0800 Subject: [PATCH 22/46] Fix typo: it's `bls_verify_multiple` in `verify_slashable_attestation` (#574) --- specs/core/0_beacon-chain.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index cc78c8b71..ccc9bf3af 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1137,7 +1137,7 @@ def verify_slashable_attestation(state: BeaconState, slashable_attestation: Slas else: custody_bit_1_indices.append(validator_index) - return bls_verify( + return bls_verify_multiple( pubkeys=[ bls_aggregate_pubkeys([state.validator_registry[i].pubkey for i in custody_bit_0_indices]), bls_aggregate_pubkeys([state.validator_registry[i].pubkey for i in custody_bit_1_indices]), @@ -1147,11 +1147,7 @@ def verify_slashable_attestation(state: BeaconState, slashable_attestation: Slas hash_tree_root(AttestationDataAndCustodyBit(data=slashable_attestation.data, custody_bit=0b1)), ], signature=slashable_attestation.aggregate_signature, - domain=get_domain( - state.fork, - slot_to_epoch(vote_data.data.slot), - DOMAIN_ATTESTATION, - ), + domain=get_domain(state.fork, slot_to_epoch(vote_data.data.slot), DOMAIN_ATTESTATION), ) ``` From 1d76ad65ec4dcde8666d57344057d9060ed30b7f Mon Sep 17 00:00:00 2001 From: Justin Date: Tue, 5 Feb 2019 11:49:52 -0800 Subject: [PATCH 23/46] Update 0_beacon-chain.md --- specs/core/0_beacon-chain.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index ed5d1b3b3..6b41e6c8a 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1100,10 +1100,9 @@ def verify_bitfield(bitfield: bytes, committee_size: int) -> bool: return False # Check if `bitfield` has padding zeros - if committee_size % 8 != 0: - for i in range(committee_size, committee_size - committee_size % 8 + 8): - if get_bitfield_bit(bitfield, i) == 0b1: - return False + for i in range(committee_size, len(bitfield) * 8): + if get_bitfield_bit(bitfield, i) == 0b1: + return False return True ``` From 180c8a0e728cf2f3c21e2ea10a0d439efa9fd792 Mon Sep 17 00:00:00 2001 From: Justin Date: Tue, 5 Feb 2019 11:51:06 -0800 Subject: [PATCH 24/46] 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 6b41e6c8a..77196312b 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1099,7 +1099,7 @@ def verify_bitfield(bitfield: bytes, committee_size: int) -> bool: if len(bitfield) != (committee_size + 7) // 8: return False - # Check if `bitfield` has padding zeros + # Check `bitfield` is padded with zero bits only for i in range(committee_size, len(bitfield) * 8): if get_bitfield_bit(bitfield, i) == 0b1: return False From c58410e6ce9904c6619cd925b64fbd04c00b9a89 Mon Sep 17 00:00:00 2001 From: vbuterin Date: Wed, 6 Feb 2019 06:48:46 -0600 Subject: [PATCH 25/46] Introduce swap-or-not shuffle See #563 for discussion. --- specs/core/0_beacon-chain.md | 61 +++++++++--------------------------- 1 file changed, 15 insertions(+), 46 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 44b88d126..3cb1b459f 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -697,53 +697,22 @@ def get_active_validator_indices(validators: List[Validator], epoch: EpochNumber ```python def shuffle(values: List[Any], seed: Bytes32) -> List[Any]: - """ - Return the shuffled ``values`` with ``seed`` as entropy. - """ - values_count = len(values) + indices = list(range(len(values))) + for round in range(90): + hashvalues = b''.join([ + hash(seed + round.to_bytes(1, 'big') + i.to_bytes(4, 'big')) + for i in range((n + 255) // 256) + ]) + pivot = int.from_bytes(hash(seed + round.to_bytes(1, 'big')), 'big') % n + + def permute(pos): + flip = (pivot - pos) % n + maxpos = max(pos, flip) + bit = (hashvalues[maxpos // 8] >> (maxpos % 8)) % 2 + return flip if bit else pos - # Entropy is consumed from the seed in 3-byte (24 bit) chunks. - rand_bytes = 3 - # The highest possible result of the RNG. - rand_max = 2 ** (rand_bytes * 8) - 1 - - # The range of the RNG places an upper-bound on the size of the list that - # may be shuffled. It is a logic error to supply an oversized list. - assert values_count < rand_max - - output = [x for x in values] - source = seed - index = 0 - while index < values_count - 1: - # Re-hash the `source` to obtain a new pattern of bytes. - source = hash(source) - # Iterate through the `source` bytes in 3-byte chunks. - for position in range(0, 32 - (32 % rand_bytes), rand_bytes): - # Determine the number of indices remaining in `values` and exit - # once the last index is reached. - remaining = values_count - index - if remaining == 1: - break - - # Read 3-bytes of `source` as a 24-bit big-endian integer. - sample_from_source = int.from_bytes(source[position:position + rand_bytes], 'big') - - # Sample values greater than or equal to `sample_max` will cause - # modulo bias when mapped into the `remaining` range. - sample_max = rand_max - rand_max % remaining - - # Perform a swap if the consumed entropy will not cause modulo bias. - if sample_from_source < sample_max: - # Select a replacement index for the current index. - replacement_position = (sample_from_source % remaining) + index - # Swap the current index with the replacement index. - output[index], output[replacement_position] = output[replacement_position], output[index] - index += 1 - else: - # The sample causes modulo bias. A new sample should be read. - pass - - return output + indices = [permute(v) for v in indices] + return [v[index] for index in indices] ``` ### `split` From 8f37c5c0f8804d37dde2e513e6eeaa91b8b7879e Mon Sep 17 00:00:00 2001 From: vbuterin Date: Wed, 6 Feb 2019 10:34:19 -0600 Subject: [PATCH 26/46] Update fork choice rule (#571) --- specs/core/0_beacon-chain.md | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 44b88d126..9015a4970 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -13,6 +13,7 @@ - [Constants](#constants) - [Misc](#misc) - [Deposit contract](#deposit-contract) + - [Gwei values](#gwei-values) - [Initial values](#initial-values) - [Time parameters](#time-parameters) - [State list lengths](#state-list-lengths) @@ -179,7 +180,6 @@ Code snippets appearing in `this style` are to be interpreted as Python code. Be | - | - | :-: | | `SHARD_COUNT` | `2**10` (= 1,024) | shards | | `TARGET_COMMITTEE_SIZE` | `2**7` (= 128) | [validators](#dfn-validator) | -| `EJECTION_BALANCE` | `2**4 * 1e9` (= 16,000,000,000) | Gwei | | `MAX_BALANCE_CHURN_QUOTIENT` | `2**5` (= 32) | - | | `BEACON_CHAIN_SHARD_NUMBER` | `2**64 - 1` | - | | `MAX_INDICES_PER_SLASHABLE_VOTE` | `2**12` (= 4,096) | votes | @@ -189,12 +189,19 @@ Code snippets appearing in `this style` are to be interpreted as Python code. Be ### Deposit contract +| Name | Value | +| - | - | +| `DEPOSIT_CONTRACT_ADDRESS` | **TBD** | +| `DEPOSIT_CONTRACT_TREE_DEPTH` | `2**5` (= 32) | + +### Gwei values + | Name | Value | Unit | | - | - | :-: | -| `DEPOSIT_CONTRACT_ADDRESS` | **TBD** | -| `DEPOSIT_CONTRACT_TREE_DEPTH` | `2**5` (= 32) | - | | `MIN_DEPOSIT_AMOUNT` | `2**0 * 1e9` (= 1,000,000,000) | Gwei | | `MAX_DEPOSIT_AMOUNT` | `2**5 * 1e9` (= 32,000,000,000) | Gwei | +| `FORK_CHOICE_BALANCE_INCREMENT` | `2**0 * 1e9` (= 1,000,000,000) | Gwei | +| `EJECTION_BALANCE` | `2**4 * 1e9` (= 16,000,000,000) | Gwei | ### Initial values @@ -1555,8 +1562,8 @@ def get_ancestor(store: Store, block: BeaconBlock, slot: SlotNumber) -> BeaconBl return get_ancestor(store, store.get_parent(block), slot) ``` -* Let `get_latest_attestation(store: Store, validator: Validator) -> Attestation` be the attestation with the highest slot number in `store` from `validator`. If several such attestations exist, use the one the [validator](#dfn-validator) `v` observed first. -* Let `get_latest_attestation_target(store: Store, validator: Validator) -> BeaconBlock` be the target block in the attestation `get_latest_attestation(store, validator)`. +* Let `get_latest_attestation(store: Store, validator_index: ValidatorIndex) -> Attestation` be the attestation with the highest slot number in `store` from the validator with the given `validator_index`. If several such attestations exist, use the one the [validator](#dfn-validator) `v` observed first. +* Let `get_latest_attestation_target(store: Store, validator_index: ValidatorIndex) -> BeaconBlock` be the target block in the attestation `get_latest_attestation(store, validator_index)`. * Let `get_children(store: Store, block: BeaconBlock) -> List[BeaconBlock]` returns the child blocks of the given `block`. * Let `justified_head_state` be the resulting `BeaconState` object from processing the chain up to the `justified_head`. * The `head` is `lmd_ghost(store, justified_head_state, justified_head)` where the function `lmd_ghost` is defined below. Note that the implementation below is suboptimal; there are implementations that compute the head in time logarithmic in slot count. @@ -1567,21 +1574,18 @@ def lmd_ghost(store: Store, start_state: BeaconState, start_block: BeaconBlock) Execute the LMD-GHOST algorithm to find the head ``BeaconBlock``. """ validators = start_state.validator_registry - active_validators = [ - validators[i] - for i in get_active_validator_indices(validators, start_state.slot) - ] + active_validator_indices = get_active_validator_indices(validators, start_state.slot) attestation_targets = [ - get_latest_attestation_target(store, validator) - for validator in active_validators + (validator_index, get_latest_attestation_target(store, validator_index)) + for validator_index in active_validator_indices ] def get_vote_count(block: BeaconBlock) -> int: - return len([ - target - for target in attestation_targets + return sum( + get_effective_balance(start_state.validator_balances[validator_index]) // FORK_CHOICE_BALANCE_INCREMENT + for validator_index, target in attestation_targets if get_ancestor(store, target, block.slot) == block - ]) + ) head = start_block while 1: From 37b41a2ce645b644a56c473cba2ded3a49689139 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Wed, 6 Feb 2019 18:33:11 -0600 Subject: [PATCH 27/46] Update specs/core/0_beacon-chain.md Co-Authored-By: vbuterin --- 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 3cb1b459f..5471d76a1 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -704,7 +704,6 @@ def shuffle(values: List[Any], seed: Bytes32) -> List[Any]: for i in range((n + 255) // 256) ]) pivot = int.from_bytes(hash(seed + round.to_bytes(1, 'big')), 'big') % n - def permute(pos): flip = (pivot - pos) % n maxpos = max(pos, flip) From 4ec721f3b7d4459c3db601d9a3bd53511a1dfd31 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Wed, 6 Feb 2019 18:33:22 -0600 Subject: [PATCH 28/46] Update specs/core/0_beacon-chain.md Co-Authored-By: vbuterin --- specs/core/0_beacon-chain.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 5471d76a1..2e453b061 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -697,6 +697,13 @@ def get_active_validator_indices(validators: List[Validator], epoch: EpochNumber ```python def shuffle(values: List[Any], seed: Bytes32) -> List[Any]: + """ + Return the shuffled ``values`` with ``seed`` as entropy. + + Utilizes 'swap or not' shuffling found in + https://link.springer.com/content/pdf/10.1007%2F978-3-642-32009-5_1.pdf + See the 'generalized domain' algorithm on page 3. + """ indices = list(range(len(values))) for round in range(90): hashvalues = b''.join([ From 6a5b7540da501c976d1e0ec76b44725bb96f7f37 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Wed, 6 Feb 2019 18:33:29 -0600 Subject: [PATCH 29/46] 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 2e453b061..1426bb4e8 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -718,7 +718,7 @@ def shuffle(values: List[Any], seed: Bytes32) -> List[Any]: return flip if bit else pos indices = [permute(v) for v in indices] - return [v[index] for index in indices] + return [values[index] for index in indices] ``` ### `split` From 47b00f38dda4336ada69b166f8f288b840c628d3 Mon Sep 17 00:00:00 2001 From: vbuterin Date: Wed, 6 Feb 2019 18:34:05 -0600 Subject: [PATCH 30/46] n -> len(values) --- 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 1426bb4e8..60bacba63 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -708,7 +708,7 @@ def shuffle(values: List[Any], seed: Bytes32) -> List[Any]: for round in range(90): hashvalues = b''.join([ hash(seed + round.to_bytes(1, 'big') + i.to_bytes(4, 'big')) - for i in range((n + 255) // 256) + for i in range((len(values) + 255) // 256) ]) pivot = int.from_bytes(hash(seed + round.to_bytes(1, 'big')), 'big') % n def permute(pos): From b3db7b03942d2c666952fb94fe01774d15089105 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Wed, 6 Feb 2019 20:32:05 -0800 Subject: [PATCH 31/46] big to little in shuffle --- 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 60bacba63..641ad02ca 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -707,10 +707,10 @@ def shuffle(values: List[Any], seed: Bytes32) -> List[Any]: indices = list(range(len(values))) for round in range(90): hashvalues = b''.join([ - hash(seed + round.to_bytes(1, 'big') + i.to_bytes(4, 'big')) + hash(seed + round.to_bytes(1, 'little') + i.to_bytes(4, 'little')) for i in range((len(values) + 255) // 256) ]) - pivot = int.from_bytes(hash(seed + round.to_bytes(1, 'big')), 'big') % n + pivot = int.from_bytes(hash(seed + round.to_bytes(1, 'little')), 'little') % n def permute(pos): flip = (pivot - pos) % n maxpos = max(pos, flip) From 65255e53c46ac8d2ee520f2845e9869193ae783c Mon Sep 17 00:00:00 2001 From: vbuterin Date: Wed, 6 Feb 2019 23:29:24 -0600 Subject: [PATCH 32/46] shuffle -> get_permuted_index --- specs/core/0_beacon-chain.md | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 641ad02ca..dd58482b3 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -59,7 +59,7 @@ - [`get_epoch_start_slot`](#get_epoch_start_slot) - [`is_active_validator`](#is_active_validator) - [`get_active_validator_indices`](#get_active_validator_indices) - - [`shuffle`](#shuffle) + - [`get_permuted_index`](#get_permuted_index) - [`split`](#split) - [`get_epoch_committee_count`](#get_epoch_committee_count) - [`get_shuffling`](#get_shuffling) @@ -693,32 +693,27 @@ def get_active_validator_indices(validators: List[Validator], epoch: EpochNumber return [i for i, v in enumerate(validators) if is_active_validator(v, epoch)] ``` -### `shuffle` +### `get_permuted_index` ```python -def shuffle(values: List[Any], seed: Bytes32) -> List[Any]: +def get_permuted_index(index: int, list_size: int, seed: Bytes32) -> int: """ - Return the shuffled ``values`` with ``seed`` as entropy. + Return a pseudorandom permutation of `0...list_size-1` with ``seed`` as entropy. Utilizes 'swap or not' shuffling found in https://link.springer.com/content/pdf/10.1007%2F978-3-642-32009-5_1.pdf See the 'generalized domain' algorithm on page 3. """ - indices = list(range(len(values))) for round in range(90): - hashvalues = b''.join([ - hash(seed + round.to_bytes(1, 'little') + i.to_bytes(4, 'little')) - for i in range((len(values) + 255) // 256) - ]) - pivot = int.from_bytes(hash(seed + round.to_bytes(1, 'little')), 'little') % n - def permute(pos): - flip = (pivot - pos) % n - maxpos = max(pos, flip) - bit = (hashvalues[maxpos // 8] >> (maxpos % 8)) % 2 - return flip if bit else pos - - indices = [permute(v) for v in indices] - return [values[index] for index in indices] + pivot = int.from_bytes(hash(seed + round.to_bytes(1, 'little')), 'little') % list_size + + flip = (pivot - index) % list_size + hash_pos = max(index, flip) + h = hash(seed + round.to_bytes(1, 'little') + (hash_pos // 256).to_bytes(4, 'little')) + byte = h[(hash_pos % 256) // 8] + bit = (byte >> (hash_pos % 8)) % 2 + index = flip if bit else index + return index ``` ### `split` @@ -768,7 +763,10 @@ def get_shuffling(seed: Bytes32, committees_per_epoch = get_epoch_committee_count(len(active_validator_indices)) # Shuffle - shuffled_active_validator_indices = shuffle(active_validator_indices, seed) + shuffled_active_validator_indices = [ + active_validator_indices[get_permuted_index(i, len(active_validator_indices), seed)] + for i in active_validator_indices + ] # Split the shuffled list into committees_per_epoch pieces return split(shuffled_active_validator_indices, committees_per_epoch) From 92514716fb77de05637a560ec3f62a0ed5209dc6 Mon Sep 17 00:00:00 2001 From: vbuterin Date: Wed, 6 Feb 2019 23:32:20 -0600 Subject: [PATCH 33/46] 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 dd58482b3..2c0fce8c5 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -698,7 +698,7 @@ def get_active_validator_indices(validators: List[Validator], epoch: EpochNumber ```python def get_permuted_index(index: int, list_size: int, seed: Bytes32) -> int: """ - Return a pseudorandom permutation of `0...list_size-1` with ``seed`` as entropy. + Return `p(index)` in a pseudorandom permutation `p` of `0...list_size-1` with ``seed`` as entropy. Utilizes 'swap or not' shuffling found in https://link.springer.com/content/pdf/10.1007%2F978-3-642-32009-5_1.pdf From 70e482be28a10ca0d37de34fb3a0b5cd94108ad3 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Thu, 7 Feb 2019 19:14:58 +0800 Subject: [PATCH 34/46] Add vbuterin's optimization and some formatting --- specs/core/0_beacon-chain.md | 44 +++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 2c0fce8c5..3da520300 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -59,7 +59,7 @@ - [`get_epoch_start_slot`](#get_epoch_start_slot) - [`is_active_validator`](#is_active_validator) - [`get_active_validator_indices`](#get_active_validator_indices) - - [`get_permuted_index`](#get_permuted_index) + - [`shuffle`](#shuffle) - [`split`](#split) - [`get_epoch_committee_count`](#get_epoch_committee_count) - [`get_shuffling`](#get_shuffling) @@ -693,27 +693,38 @@ def get_active_validator_indices(validators: List[Validator], epoch: EpochNumber return [i for i, v in enumerate(validators) if is_active_validator(v, epoch)] ``` -### `get_permuted_index` +### `shuffle` ```python -def get_permuted_index(index: int, list_size: int, seed: Bytes32) -> int: +def shuffle(list_size: int, seed: Bytes32) -> List[int]: """ - Return `p(index)` in a pseudorandom permutation `p` of `0...list_size-1` with ``seed`` as entropy. - + Return shuffled indices in a pseudorandom permutation `0...list_size-1` with ``seed`` as entropy. + Utilizes 'swap or not' shuffling found in https://link.springer.com/content/pdf/10.1007%2F978-3-642-32009-5_1.pdf See the 'generalized domain' algorithm on page 3. """ + indices = list(range(list_size)) + power_of_two_numbers = [1, 2, 4, 8, 16, 32, 64, 128] for round in range(90): - pivot = int.from_bytes(hash(seed + round.to_bytes(1, 'little')), 'little') % list_size - - flip = (pivot - index) % list_size - hash_pos = max(index, flip) - h = hash(seed + round.to_bytes(1, 'little') + (hash_pos // 256).to_bytes(4, 'little')) - byte = h[(hash_pos % 256) // 8] - bit = (byte >> (hash_pos % 8)) % 2 - index = flip if bit else index - return index + hash_bytes = b''.join([ + hash(seed + int_to_bytes1(round) + int_to_bytes4(i)) + for i in range((list_size + 255) // 256) + ]) + + pivot = int.from_bytes(hash(seed + int_to_bytes1(round)), 'little') % list_size + for i in range(list_size): + flip = (pivot - indices[i]) % list_size + hash_position = indices[i] if indices[i] > flip else flip + byte = hash_bytes[hash_position // 8] + mask = power_of_two_numbers[hash_position % 8] + if byte & mask: + indices[i] = flip + else: + # not swap + pass + + return indices ``` ### `split` @@ -763,9 +774,10 @@ def get_shuffling(seed: Bytes32, committees_per_epoch = get_epoch_committee_count(len(active_validator_indices)) # Shuffle + shuffled_indices = shuffle(len(active_validator_indices), seed) shuffled_active_validator_indices = [ - active_validator_indices[get_permuted_index(i, len(active_validator_indices), seed)] - for i in active_validator_indices + active_validator_indices[i] + for i in shuffle(len(active_validator_indices), seed) ] # Split the shuffled list into committees_per_epoch pieces From aa9f9fc9be337ad072e855e5a4132735eea7636b Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Thu, 7 Feb 2019 19:18:39 +0800 Subject: [PATCH 35/46] amend --- 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 3da520300..6a4ac6ce5 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -774,7 +774,6 @@ def get_shuffling(seed: Bytes32, committees_per_epoch = get_epoch_committee_count(len(active_validator_indices)) # Shuffle - shuffled_indices = shuffle(len(active_validator_indices), seed) shuffled_active_validator_indices = [ active_validator_indices[i] for i in shuffle(len(active_validator_indices), seed) From 3f3472087af00ddb54210feb7f82cc7f6e22d966 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Thu, 7 Feb 2019 10:37:01 -0800 Subject: [PATCH 36/46] change message to message_hash in bls spec addresses #572 --- specs/bls_signature.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/specs/bls_signature.md b/specs/bls_signature.md index fd9bae58e..b0490b7ae 100644 --- a/specs/bls_signature.md +++ b/specs/bls_signature.md @@ -69,10 +69,10 @@ We require: G2_cofactor = 305502333931268344200999753193121504214466019254188142667664032982267604182971884026507427359259977847832272839041616661285803823378372096355777062779109 q = 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787 -def hash_to_G2(message: bytes32, domain: uint64) -> [uint384]: +def hash_to_G2(message_hash: Bytes32, domain: uint64) -> [uint384]: # Initial candidate x coordinate - x_re = int.from_bytes(hash(message + bytes8(domain) + b'\x01'), 'big') - x_im = int.from_bytes(hash(message + bytes8(domain) + b'\x02'), 'big') + x_re = int.from_bytes(hash(message_hash + bytes8(domain) + b'\x01'), 'big') + x_im = int.from_bytes(hash(message_hash + bytes8(domain) + b'\x02'), 'big') x_coordinate = Fq2([x_re, x_im]) # x = x_re + i * x_im # Test candidate y coordinates until a one is found @@ -128,17 +128,17 @@ g = Fq2([g_x, g_y]) ### `bls_verify` -Let `bls_verify(pubkey: Bytes48, message: Bytes32, signature: Bytes96, domain: uint64) -> bool`: +Let `bls_verify(pubkey: Bytes48, message_hash: Bytes32, signature: Bytes96, domain: uint64) -> bool`: * Verify that `pubkey` is a valid G1 point. * Verify that `signature` is a valid G2 point. -* Verify that `e(pubkey, hash_to_G2(message, domain)) == e(g, signature)`. +* Verify that `e(pubkey, hash_to_G2(message_hash, domain)) == e(g, signature)`. ### `bls_verify_multiple` -Let `bls_verify_multiple(pubkeys: List[Bytes48], messages: List[Bytes32], signature: Bytes96, domain: uint64) -> bool`: +Let `bls_verify_multiple(pubkeys: List[Bytes48], message_hashes: List[Bytes32], signature: Bytes96, domain: uint64) -> bool`: * Verify that each `pubkey` in `pubkeys` is a valid G1 point. * Verify that `signature` is a valid G2 point. -* Verify that `len(pubkeys)` equals `len(messages)` and denote the length `L`. -* Verify that `e(pubkeys[0], hash_to_G2(messages[0], domain)) * ... * e(pubkeys[L-1], hash_to_G2(messages[L-1], domain)) == e(g, signature)`. +* Verify that `len(pubkeys)` equals `len(message_hashes)` and denote the length `L`. +* Verify that `e(pubkeys[0], hash_to_G2(message_hashes[0], domain)) * ... * e(pubkeys[L-1], hash_to_G2(message_hashes[L-1], domain)) == e(g, signature)`. From d4901be1984e44a61d410bda9d4592caa25cf470 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Thu, 7 Feb 2019 11:48:36 -0700 Subject: [PATCH 37/46] get_next_epoch_committee_assignments returns slot and is_proposer --- specs/validator/0_beacon-chain-validator.md | 26 +++++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/specs/validator/0_beacon-chain-validator.md b/specs/validator/0_beacon-chain-validator.md index 3df3d758d..093f29f5b 100644 --- a/specs/validator/0_beacon-chain-validator.md +++ b/specs/validator/0_beacon-chain-validator.md @@ -344,12 +344,22 @@ Either (2) or (3) occurs if (1) fails. The choice between (2) and (3) is determi `get_crosslink_committees_at_slot` is designed to be able to query slots in the next epoch. When querying slots in the next epoch there are two options -- with and without a `registry_change` -- which is the optional third parameter of the function. The following helper can be used to get the potential crosslink committees in the next epoch for a given `validator_index`. This function returns a list of 2 shard committee tuples. ```python -def get_next_epoch_crosslink_committees(state: BeaconState, - validator_index: ValidatorIndex) -> List[Tuple[List[ValidatorIndex], ShardNumber]]: +def get_next_epoch_committee_assignments( + state: BeaconState, + validator_index: ValidatorIndex) -> List[Tuple[List[ValidatorIndex], ShardNumber, SlotNumber, bool]]: + """ + Return a list of the two possible committee assignments for ``validator_index`` at the next epoch. + Possible committee ``assignment`` is of the form (List[ValidatorIndex], ShardNumber, SlotNumber, bool). + * ``assignment[0]`` is the list of validators in the committee + * ``assignment[1]`` is the shard to which the committee is assigned + * ``assignment[2]`` is the slot at which the committee is assigned + * ``assignment[3]`` is a bool signalling if the validator is expected to propose + a beacon block at the assigned slot. + """ current_epoch = get_current_epoch(state) next_epoch = current_epoch + 1 next_epoch_start_slot = get_epoch_start_slot(next_epoch) - potential_committees = [] + potential_assignments = [] for registry_change in [False, True]: for slot in range(next_epoch_start_slot, next_epoch_start_slot + EPOCH_LENGTH): crosslink_committees = get_crosslink_committees_at_slot( @@ -363,13 +373,19 @@ def get_next_epoch_crosslink_committees(state: BeaconState, if validator_index in committee[0] ] if len(selected_committees) > 0: - potential_assignments.append(selected_committees) + assignment = selected_committees[0] + assignment += (slot,) + first_committee_at_slot = crosslink_committees[0] + is_proposer = first_committee_at_slot[slot % len(first_committee_at_slot)] == validator_index + assignment += (is_proposer,) + + potential_assignments.append(assignment) break return potential_assignments ``` -`get_next_epoch_crosslink_committees` should be called at the beginning of each epoch to plan for the next epoch. A validator should always plan for both values of `registry_change` as a possibility unless the validator can concretely eliminate one of the options. Planning for a future shuffling involves noting at which slot one might have to attest and propose and also which shard one should begin syncing (in phase 1+). +`get_next_epoch_committee_assignments` should be called at the beginning of each epoch to plan for the next epoch. A validator should always plan for both values of `registry_change` as a possibility unless the validator can concretely eliminate one of the options. Planning for a future shuffling involves noting at which slot one might have to attest and propose and also which shard one should begin syncing (in phase 1+). ## How to avoid slashing From e4f5efadb79dcfe6f83b71a3bf339fd11b224f0a Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 8 Feb 2019 04:03:13 +0800 Subject: [PATCH 38/46] Fix `first_committee_at_slot` --- specs/validator/0_beacon-chain-validator.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/specs/validator/0_beacon-chain-validator.md b/specs/validator/0_beacon-chain-validator.md index 093f29f5b..4d8d5eadf 100644 --- a/specs/validator/0_beacon-chain-validator.md +++ b/specs/validator/0_beacon-chain-validator.md @@ -368,14 +368,14 @@ def get_next_epoch_committee_assignments( registry_change=registry_change, ) selected_committees = [ - committee # type: Tuple[List[ValidatorIndex], ShardNumber] + committee # Tuple[List[ValidatorIndex], ShardNumber] for committee in crosslink_committees if validator_index in committee[0] ] if len(selected_committees) > 0: assignment = selected_committees[0] assignment += (slot,) - first_committee_at_slot = crosslink_committees[0] + first_committee_at_slot = crosslink_committees[0][0] # List[ValidatorIndex] is_proposer = first_committee_at_slot[slot % len(first_committee_at_slot)] == validator_index assignment += (is_proposer,) From 859bf6248467eb8f5a23c28ac721f605185ccfaf Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 8 Feb 2019 05:08:25 +0800 Subject: [PATCH 39/46] Revert and refactor --- specs/core/0_beacon-chain.md | 41 ++++++++++++++---------------------- 1 file changed, 16 insertions(+), 25 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 6a4ac6ce5..38d233b23 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -59,7 +59,7 @@ - [`get_epoch_start_slot`](#get_epoch_start_slot) - [`is_active_validator`](#is_active_validator) - [`get_active_validator_indices`](#get_active_validator_indices) - - [`shuffle`](#shuffle) + - [`get_permuted_index`](#get_permuted_index) - [`split`](#split) - [`get_epoch_committee_count`](#get_epoch_committee_count) - [`get_shuffling`](#get_shuffling) @@ -693,38 +693,29 @@ def get_active_validator_indices(validators: List[Validator], epoch: EpochNumber return [i for i, v in enumerate(validators) if is_active_validator(v, epoch)] ``` -### `shuffle` +### `get_permuted_index` ```python -def shuffle(list_size: int, seed: Bytes32) -> List[int]: +def get_permuted_index(index: int, list_size: int, seed: Bytes32, round_count: int=90) -> List[int]: """ - Return shuffled indices in a pseudorandom permutation `0...list_size-1` with ``seed`` as entropy. + Return `p(index)` in a pseudorandom permutation `p` of `0...list_size-1` with ``seed`` as entropy. + + Note that ``round_count`` is ``90`` in protocol and parameterized for the shuffling tests. Utilizes 'swap or not' shuffling found in https://link.springer.com/content/pdf/10.1007%2F978-3-642-32009-5_1.pdf See the 'generalized domain' algorithm on page 3. """ - indices = list(range(list_size)) - power_of_two_numbers = [1, 2, 4, 8, 16, 32, 64, 128] - for round in range(90): - hash_bytes = b''.join([ - hash(seed + int_to_bytes1(round) + int_to_bytes4(i)) - for i in range((list_size + 255) // 256) - ]) - + for round in range(round_count): pivot = int.from_bytes(hash(seed + int_to_bytes1(round)), 'little') % list_size - for i in range(list_size): - flip = (pivot - indices[i]) % list_size - hash_position = indices[i] if indices[i] > flip else flip - byte = hash_bytes[hash_position // 8] - mask = power_of_two_numbers[hash_position % 8] - if byte & mask: - indices[i] = flip - else: - # not swap - pass + flip = (pivot - index) % list_size + position = max(index, flip) + source = hash(seed + int_to_bytes1(round) + int_to_bytes4(position // 256)) + byte = source[(position % 256) // 8] + bit = (byte >> (position % 8)) % 2 + index = flip if bit else index - return indices + return index ``` ### `split` @@ -775,8 +766,8 @@ def get_shuffling(seed: Bytes32, # Shuffle shuffled_active_validator_indices = [ - active_validator_indices[i] - for i in shuffle(len(active_validator_indices), seed) + active_validator_indices[get_permuted_index(i, len(active_validator_indices), seed)] + for i in active_validator_indices ] # Split the shuffled list into committees_per_epoch pieces From cf7ebe9ad31d1b4831f8a26353ac70c1fd60d27c Mon Sep 17 00:00:00 2001 From: mratsim Date: Thu, 7 Feb 2019 22:09:41 +0100 Subject: [PATCH 40/46] `message` to `message_hash` in the rest of the spec (followup https://github.com/ethereum/eth2.0-specs/pull/580) --- specs/core/0_beacon-chain.md | 280 ++++++++++---------- specs/validator/0_beacon-chain-validator.md | 102 +++---- 2 files changed, 191 insertions(+), 191 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index b0433ce04..e6cf019f4 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -6,139 +6,139 @@ - [Ethereum 2.0 Phase 0 -- The Beacon Chain](#ethereum-20-phase-0----the-beacon-chain) - - [Table of contents](#table-of-contents) - - [Introduction](#introduction) - - [Notation](#notation) - - [Terminology](#terminology) - - [Constants](#constants) - - [Misc](#misc) - - [Deposit contract](#deposit-contract) - - [Gwei values](#gwei-values) - - [Initial values](#initial-values) - - [Time parameters](#time-parameters) - - [State list lengths](#state-list-lengths) - - [Reward and penalty quotients](#reward-and-penalty-quotients) - - [Status flags](#status-flags) - - [Max operations per block](#max-operations-per-block) - - [Signature domains](#signature-domains) - - [Data structures](#data-structures) - - [Beacon chain operations](#beacon-chain-operations) - - [Proposer slashings](#proposer-slashings) - - [`ProposerSlashing`](#proposerslashing) - - [Attester slashings](#attester-slashings) - - [`AttesterSlashing`](#attesterslashing) - - [`SlashableAttestation`](#slashableattestation) - - [Attestations](#attestations) - - [`Attestation`](#attestation) - - [`AttestationData`](#attestationdata) - - [`AttestationDataAndCustodyBit`](#attestationdataandcustodybit) - - [Deposits](#deposits) - - [`Deposit`](#deposit) - - [`DepositData`](#depositdata) - - [`DepositInput`](#depositinput) - - [Exits](#exits) - - [`Exit`](#exit) - - [Beacon chain blocks](#beacon-chain-blocks) - - [`BeaconBlock`](#beaconblock) - - [`BeaconBlockBody`](#beaconblockbody) - - [`ProposalSignedData`](#proposalsigneddata) - - [Beacon chain state](#beacon-chain-state) - - [`BeaconState`](#beaconstate) - - [`Validator`](#validator) - - [`Crosslink`](#crosslink) - - [`PendingAttestation`](#pendingattestation) - - [`Fork`](#fork) - - [`Eth1Data`](#eth1data) - - [`Eth1DataVote`](#eth1datavote) - - [Custom Types](#custom-types) - - [Helper functions](#helper-functions) - - [`hash`](#hash) - - [`hash_tree_root`](#hash_tree_root) - - [`slot_to_epoch`](#slot_to_epoch) - - [`get_previous_epoch`](#get_previous_epoch) - - [`get_current_epoch`](#get_current_epoch) - - [`get_epoch_start_slot`](#get_epoch_start_slot) - - [`is_active_validator`](#is_active_validator) - - [`get_active_validator_indices`](#get_active_validator_indices) - - [`shuffle`](#shuffle) - - [`split`](#split) - - [`get_epoch_committee_count`](#get_epoch_committee_count) - - [`get_shuffling`](#get_shuffling) - - [`get_previous_epoch_committee_count`](#get_previous_epoch_committee_count) - - [`get_current_epoch_committee_count`](#get_current_epoch_committee_count) - - [`get_next_epoch_committee_count`](#get_next_epoch_committee_count) - - [`get_crosslink_committees_at_slot`](#get_crosslink_committees_at_slot) - - [`get_block_root`](#get_block_root) - - [`get_randao_mix`](#get_randao_mix) - - [`get_active_index_root`](#get_active_index_root) - - [`generate_seed`](#generate_seed) - - [`get_beacon_proposer_index`](#get_beacon_proposer_index) - - [`merkle_root`](#merkle_root) - - [`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-) - - [`get_effective_balance`](#get_effective_balance) - - [`get_total_balance`](#get_total_balance) - - [`get_fork_version`](#get_fork_version) - - [`get_domain`](#get_domain) - - [`get_bitfield_bit`](#get_bitfield_bit) - - [`verify_bitfield`](#verify_bitfield) - - [`verify_slashable_attestation`](#verify_slashable_attestation) - - [`is_double_vote`](#is_double_vote) - - [`is_surround_vote`](#is_surround_vote) - - [`integer_squareroot`](#integer_squareroot) - - [`get_entry_exit_effect_epoch`](#get_entry_exit_effect_epoch) - - [`bls_verify`](#bls_verify) - - [`bls_verify_multiple`](#bls_verify_multiple) - - [`bls_aggregate_pubkeys`](#bls_aggregate_pubkeys) - - [`validate_proof_of_possession`](#validate_proof_of_possession) - - [`process_deposit`](#process_deposit) - - [Routines for updating validator status](#routines-for-updating-validator-status) - - [`activate_validator`](#activate_validator) - - [`initiate_validator_exit`](#initiate_validator_exit) - - [`exit_validator`](#exit_validator) - - [`penalize_validator`](#penalize_validator) - - [`prepare_validator_for_withdrawal`](#prepare_validator_for_withdrawal) - - [Ethereum 1.0 deposit contract](#ethereum-10-deposit-contract) - - [Deposit arguments](#deposit-arguments) - - [Withdrawal credentials](#withdrawal-credentials) - - [`Deposit` logs](#deposit-logs) - - [`ChainStart` log](#chainstart-log) - - [Vyper code](#vyper-code) - - [On startup](#on-startup) - - [Beacon chain processing](#beacon-chain-processing) - - [Beacon chain fork choice rule](#beacon-chain-fork-choice-rule) - - [Beacon chain state transition function](#beacon-chain-state-transition-function) - - [Per-slot processing](#per-slot-processing) - - [Slot](#slot) - - [Block roots](#block-roots) - - [Per-block processing](#per-block-processing) - - [Slot](#slot-1) - - [Proposer signature](#proposer-signature) - - [RANDAO](#randao) - - [Eth1 data](#eth1-data) - - [Operations](#operations) - - [Proposer slashings](#proposer-slashings-1) - - [Attester slashings](#attester-slashings-1) - - [Attestations](#attestations-1) - - [Deposits](#deposits-1) - - [Exits](#exits-1) - - [Per-epoch processing](#per-epoch-processing) - - [Helpers](#helpers) - - [Eth1 data](#eth1-data-1) - - [Justification](#justification) - - [Crosslinks](#crosslinks) - - [Rewards and penalties](#rewards-and-penalties) - - [Justification and finalization](#justification-and-finalization) - - [Attestation inclusion](#attestation-inclusion) - - [Crosslinks](#crosslinks-1) - - [Ejections](#ejections) - - [Validator registry and shuffling seed data](#validator-registry-and-shuffling-seed-data) - - [Final updates](#final-updates) - - [State root verification](#state-root-verification) + - [Table of contents](#table-of-contents) + - [Introduction](#introduction) + - [Notation](#notation) + - [Terminology](#terminology) + - [Constants](#constants) + - [Misc](#misc) + - [Deposit contract](#deposit-contract) + - [Gwei values](#gwei-values) + - [Initial values](#initial-values) + - [Time parameters](#time-parameters) + - [State list lengths](#state-list-lengths) + - [Reward and penalty quotients](#reward-and-penalty-quotients) + - [Status flags](#status-flags) + - [Max operations per block](#max-operations-per-block) + - [Signature domains](#signature-domains) + - [Data structures](#data-structures) + - [Beacon chain operations](#beacon-chain-operations) + - [Proposer slashings](#proposer-slashings) + - [`ProposerSlashing`](#proposerslashing) + - [Attester slashings](#attester-slashings) + - [`AttesterSlashing`](#attesterslashing) + - [`SlashableAttestation`](#slashableattestation) + - [Attestations](#attestations) + - [`Attestation`](#attestation) + - [`AttestationData`](#attestationdata) + - [`AttestationDataAndCustodyBit`](#attestationdataandcustodybit) + - [Deposits](#deposits) + - [`Deposit`](#deposit) + - [`DepositData`](#depositdata) + - [`DepositInput`](#depositinput) + - [Exits](#exits) + - [`Exit`](#exit) + - [Beacon chain blocks](#beacon-chain-blocks) + - [`BeaconBlock`](#beaconblock) + - [`BeaconBlockBody`](#beaconblockbody) + - [`ProposalSignedData`](#proposalsigneddata) + - [Beacon chain state](#beacon-chain-state) + - [`BeaconState`](#beaconstate) + - [`Validator`](#validator) + - [`Crosslink`](#crosslink) + - [`PendingAttestation`](#pendingattestation) + - [`Fork`](#fork) + - [`Eth1Data`](#eth1data) + - [`Eth1DataVote`](#eth1datavote) + - [Custom Types](#custom-types) + - [Helper functions](#helper-functions) + - [`hash`](#hash) + - [`hash_tree_root`](#hashtreeroot) + - [`slot_to_epoch`](#slottoepoch) + - [`get_previous_epoch`](#getpreviousepoch) + - [`get_current_epoch`](#getcurrentepoch) + - [`get_epoch_start_slot`](#getepochstartslot) + - [`is_active_validator`](#isactivevalidator) + - [`get_active_validator_indices`](#getactivevalidatorindices) + - [`shuffle`](#shuffle) + - [`split`](#split) + - [`get_epoch_committee_count`](#getepochcommitteecount) + - [`get_shuffling`](#getshuffling) + - [`get_previous_epoch_committee_count`](#getpreviousepochcommitteecount) + - [`get_current_epoch_committee_count`](#getcurrentepochcommitteecount) + - [`get_next_epoch_committee_count`](#getnextepochcommitteecount) + - [`get_crosslink_committees_at_slot`](#getcrosslinkcommitteesatslot) + - [`get_block_root`](#getblockroot) + - [`get_randao_mix`](#getrandaomix) + - [`get_active_index_root`](#getactiveindexroot) + - [`generate_seed`](#generateseed) + - [`get_beacon_proposer_index`](#getbeaconproposerindex) + - [`merkle_root`](#merkleroot) + - [`get_attestation_participants`](#getattestationparticipants) + - [`is_power_of_two`](#ispoweroftwo) + - [`int_to_bytes1`, `int_to_bytes2`, ...](#inttobytes1-inttobytes2) + - [`get_effective_balance`](#geteffectivebalance) + - [`get_total_balance`](#gettotalbalance) + - [`get_fork_version`](#getforkversion) + - [`get_domain`](#getdomain) + - [`get_bitfield_bit`](#getbitfieldbit) + - [`verify_bitfield`](#verifybitfield) + - [`verify_slashable_attestation`](#verifyslashableattestation) + - [`is_double_vote`](#isdoublevote) + - [`is_surround_vote`](#issurroundvote) + - [`integer_squareroot`](#integersquareroot) + - [`get_entry_exit_effect_epoch`](#getentryexiteffectepoch) + - [`bls_verify`](#blsverify) + - [`bls_verify_multiple`](#blsverifymultiple) + - [`bls_aggregate_pubkeys`](#blsaggregatepubkeys) + - [`validate_proof_of_possession`](#validateproofofpossession) + - [`process_deposit`](#processdeposit) + - [Routines for updating validator status](#routines-for-updating-validator-status) + - [`activate_validator`](#activatevalidator) + - [`initiate_validator_exit`](#initiatevalidatorexit) + - [`exit_validator`](#exitvalidator) + - [`penalize_validator`](#penalizevalidator) + - [`prepare_validator_for_withdrawal`](#preparevalidatorforwithdrawal) + - [Ethereum 1.0 deposit contract](#ethereum-10-deposit-contract) + - [Deposit arguments](#deposit-arguments) + - [Withdrawal credentials](#withdrawal-credentials) + - [`Deposit` logs](#deposit-logs) + - [`ChainStart` log](#chainstart-log) + - [Vyper code](#vyper-code) + - [On startup](#on-startup) + - [Beacon chain processing](#beacon-chain-processing) + - [Beacon chain fork choice rule](#beacon-chain-fork-choice-rule) + - [Beacon chain state transition function](#beacon-chain-state-transition-function) + - [Per-slot processing](#per-slot-processing) + - [Slot](#slot) + - [Block roots](#block-roots) + - [Per-block processing](#per-block-processing) + - [Slot](#slot-1) + - [Proposer signature](#proposer-signature) + - [RANDAO](#randao) + - [Eth1 data](#eth1-data) + - [Operations](#operations) + - [Proposer slashings](#proposer-slashings-1) + - [Attester slashings](#attester-slashings-1) + - [Attestations](#attestations-1) + - [Deposits](#deposits-1) + - [Exits](#exits-1) + - [Per-epoch processing](#per-epoch-processing) + - [Helpers](#helpers) + - [Eth1 data](#eth1-data-1) + - [Justification](#justification) + - [Crosslinks](#crosslinks) + - [Rewards and penalties](#rewards-and-penalties) + - [Justification and finalization](#justification-and-finalization) + - [Attestation inclusion](#attestation-inclusion) + - [Crosslinks](#crosslinks-1) + - [Ejections](#ejections) + - [Validator registry and shuffling seed data](#validator-registry-and-shuffling-seed-data) + - [Final updates](#final-updates) + - [State root verification](#state-root-verification) - [References](#references) - - [Normative](#normative) - - [Informative](#informative) + - [Normative](#normative) + - [Informative](#informative) - [Copyright](#copyright) @@ -1052,7 +1052,7 @@ def get_effective_balance(state: State, index: ValidatorIndex) -> Gwei: ### `get_total_balance` ```python -def get_total_balance(state: BeaconState, validators: List[ValidatorIndex]) -> Gwei: +def get_total_balance(state: BeaconState, validators: List[ValidatorIndex]) -> Gwei: """ Return the combined effective balance of an array of validators. """ @@ -1150,7 +1150,7 @@ def verify_slashable_attestation(state: BeaconState, slashable_attestation: Slas bls_aggregate_pubkeys([state.validator_registry[i].pubkey for i in custody_bit_0_indices]), bls_aggregate_pubkeys([state.validator_registry[i].pubkey for i in custody_bit_1_indices]), ], - messages=[ + message_hashes=[ hash_tree_root(AttestationDataAndCustodyBit(data=slashable_attestation.data, custody_bit=0b0)), hash_tree_root(AttestationDataAndCustodyBit(data=slashable_attestation.data, custody_bit=0b1)), ], @@ -1245,7 +1245,7 @@ def validate_proof_of_possession(state: BeaconState, return bls_verify( pubkey=pubkey, - message=hash_tree_root(proof_of_possession_data), + message_hash=hash_tree_root(proof_of_possession_data), signature=proof_of_possession, domain=get_domain( state.fork, @@ -1633,12 +1633,12 @@ Below are the processing steps that happen at every `block`. * 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, message=proposal_root, signature=block.signature, domain=get_domain(state.fork, get_current_epoch(state), DOMAIN_PROPOSAL))`. +* Verify that `bls_verify(pubkey=state.validator_registry[get_beacon_proposer_index(state, state.slot)].pubkey, message_hash=proposal_root, signature=block.signature, domain=get_domain(state.fork, get_current_epoch(state), DOMAIN_PROPOSAL))`. #### RANDAO * Let `proposer = state.validator_registry[get_beacon_proposer_index(state, state.slot)]`. -* Verify that `bls_verify(pubkey=proposer.pubkey, message=int_to_bytes32(get_current_epoch(state)), signature=block.randao_reveal, domain=get_domain(state.fork, get_current_epoch(state), DOMAIN_RANDAO))`. +* Verify that `bls_verify(pubkey=proposer.pubkey, message_hash=int_to_bytes32(get_current_epoch(state)), signature=block.randao_reveal, domain=get_domain(state.fork, get_current_epoch(state), DOMAIN_RANDAO))`. * Set `state.latest_randao_mixes[get_current_epoch(state) % LATEST_RANDAO_MIXES_LENGTH] = xor(get_randao_mix(state, get_current_epoch(state)), hash(block.randao_reveal))`. #### Eth1 data @@ -1659,8 +1659,8 @@ For each `proposer_slashing` in `block.body.proposer_slashings`: * 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.penalized_epoch > get_current_epoch(state)`. -* 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, slot_to_epoch(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, slot_to_epoch(proposer_slashing.proposal_data_2.slot), DOMAIN_PROPOSAL))`. +* Verify that `bls_verify(pubkey=proposer.pubkey, message_hash=hash_tree_root(proposer_slashing.proposal_data_1), signature=proposer_slashing.proposal_signature_1, domain=get_domain(state.fork, slot_to_epoch(proposer_slashing.proposal_data_1.slot), DOMAIN_PROPOSAL))`. +* Verify that `bls_verify(pubkey=proposer.pubkey, message_hash=hash_tree_root(proposer_slashing.proposal_data_2), signature=proposer_slashing.proposal_signature_2, domain=get_domain(state.fork, slot_to_epoch(proposer_slashing.proposal_data_2.slot), DOMAIN_PROPOSAL))`. * Run `penalize_validator(state, proposer_slashing.proposer_index)`. ##### Attester slashings @@ -1772,7 +1772,7 @@ For each `exit` in `block.body.exits`: * Verify that `validator.exit_epoch > get_entry_exit_effect_epoch(get_current_epoch(state))`. * Verify that `get_current_epoch(state) >= exit.epoch`. * Let `exit_message = hash_tree_root(Exit(epoch=exit.epoch, validator_index=exit.validator_index, signature=EMPTY_SIGNATURE))`. -* Verify that `bls_verify(pubkey=validator.pubkey, message=exit_message, signature=exit.signature, domain=get_domain(state.fork, exit.epoch, DOMAIN_EXIT))`. +* Verify that `bls_verify(pubkey=validator.pubkey, message_hash=exit_message, signature=exit.signature, domain=get_domain(state.fork, exit.epoch, DOMAIN_EXIT))`. * Run `initiate_validator_exit(state, exit.validator_index)`. ### Per-epoch processing diff --git a/specs/validator/0_beacon-chain-validator.md b/specs/validator/0_beacon-chain-validator.md index 4d8d5eadf..b8db2117c 100644 --- a/specs/validator/0_beacon-chain-validator.md +++ b/specs/validator/0_beacon-chain-validator.md @@ -7,53 +7,53 @@ __NOTICE__: This document is a work-in-progress for researchers and implementers - [Ethereum 2.0 Phase 0 -- Honest Validator](#ethereum-20-phase-0----honest-validator) - - [Table of Contents](#table-of-contents) - - [Introduction](#introduction) - - [Prerequisites](#prerequisites) - - [Constants](#constants) - - [Misc](#misc) - - [Becoming a validator](#becoming-a-validator) - - [Initialization](#initialization) - - [BLS public key](#bls-public-key) - - [BLS withdrawal key](#bls-withdrawal-key) - - [Submit deposit](#submit-deposit) - - [Process deposit](#process-deposit) - - [Validator index](#validator-index) - - [Activation](#activation) - - [Beacon chain responsibilities](#beacon-chain-responsibilities) - - [Block proposal](#block-proposal) - - [Block header](#block-header) - - [Slot](#slot) - - [Parent root](#parent-root) - - [State root](#state-root) - - [Randao reveal](#randao-reveal) - - [Eth1 Data](#eth1-data) - - [Signature](#signature) - - [Block body](#block-body) - - [Proposer slashings](#proposer-slashings) - - [Attester slashings](#attester-slashings) - - [Attestations](#attestations) - - [Deposits](#deposits) - - [Exits](#exits) - - [Attestations](#attestations-1) - - [Attestation data](#attestation-data) - - [Slot](#slot-1) - - [Shard](#shard) - - [Beacon block root](#beacon-block-root) - - [Epoch boundary root](#epoch-boundary-root) - - [Shard block root](#shard-block-root) - - [Latest crosslink root](#latest-crosslink-root) - - [Justified epoch](#justified-epoch) - - [Justified block root](#justified-block-root) - - [Construct attestation](#construct-attestation) - - [Data](#data) - - [Aggregation bitfield](#aggregation-bitfield) - - [Custody bitfield](#custody-bitfield) - - [Aggregate signature](#aggregate-signature) - - [Responsibility lookahead](#responsibility-lookahead) - - [How to avoid slashing](#how-to-avoid-slashing) - - [Proposer slashing](#proposer-slashing) - - [Attester slashing](#attester-slashing) + - [Table of Contents](#table-of-contents) + - [Introduction](#introduction) + - [Prerequisites](#prerequisites) + - [Constants](#constants) + - [Misc](#misc) + - [Becoming a validator](#becoming-a-validator) + - [Initialization](#initialization) + - [BLS public key](#bls-public-key) + - [BLS withdrawal key](#bls-withdrawal-key) + - [Submit deposit](#submit-deposit) + - [Process deposit](#process-deposit) + - [Validator index](#validator-index) + - [Activation](#activation) + - [Beacon chain responsibilities](#beacon-chain-responsibilities) + - [Block proposal](#block-proposal) + - [Block header](#block-header) + - [Slot](#slot) + - [Parent root](#parent-root) + - [State root](#state-root) + - [Randao reveal](#randao-reveal) + - [Eth1 Data](#eth1-data) + - [Signature](#signature) + - [Block body](#block-body) + - [Proposer slashings](#proposer-slashings) + - [Attester slashings](#attester-slashings) + - [Attestations](#attestations) + - [Deposits](#deposits) + - [Exits](#exits) + - [Attestations](#attestations-1) + - [Attestation data](#attestation-data) + - [Slot](#slot-1) + - [Shard](#shard) + - [Beacon block root](#beacon-block-root) + - [Epoch boundary root](#epoch-boundary-root) + - [Shard block root](#shard-block-root) + - [Latest crosslink root](#latest-crosslink-root) + - [Justified epoch](#justified-epoch) + - [Justified block root](#justified-block-root) + - [Construct attestation](#construct-attestation) + - [Data](#data) + - [Aggregation bitfield](#aggregation-bitfield) + - [Custody bitfield](#custody-bitfield) + - [Aggregate signature](#aggregate-signature) + - [Responsibility lookahead](#responsibility-lookahead) + - [How to avoid slashing](#how-to-avoid-slashing) + - [Proposer slashing](#proposer-slashing) + - [Attester slashing](#attester-slashing) @@ -95,7 +95,7 @@ The validator constructs their `withdrawal_credentials` via the following: ### Submit deposit -In phase 0, all incoming validator deposits originate from the Ethereum 1.0 PoW chain. Deposits are made to the [deposit contract](https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#ethereum-10-deposit-contract) located at `DEPOSIT_CONTRACT_ADDRESS`. +In phase 0, all incoming validator deposits originate from the Ethereum 1.0 PoW chain. Deposits are made to the [deposit contract](https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#ethereum-10-deposit-contract) located at `DEPOSIT_CONTRACT_ADDRESS`. To submit a deposit: @@ -166,7 +166,7 @@ Set `block.randao_reveal = epoch_signature` where `epoch_signature` is defined a ```python epoch_signature = bls_sign( privkey=validator.privkey, # privkey store locally, not in state - message=int_to_bytes32(slot_to_epoch(block.slot)), + message_hash=int_to_bytes32(slot_to_epoch(block.slot)), domain=get_domain( fork=fork, # `fork` is the fork object at the slot `block.slot` epoch=slot_to_epoch(block.slot), @@ -205,7 +205,7 @@ proposal_root = hash_tree_root(proposal_data) signed_proposal_data = bls_sign( privkey=validator.privkey, # privkey store locally, not in state - message=proposal_root, + message_hash=proposal_root, domain=get_domain( fork=fork, # `fork` is the fork object at the slot `block.slot` epoch=slot_to_epoch(block.slot), @@ -321,7 +321,7 @@ attestation_message_to_sign = hash_tree_root(attestation_data_and_custody_bit) signed_attestation_data = bls_sign( privkey=validator.privkey, # privkey store locally, not in state - message=attestation_message_to_sign, + message_hash=attestation_message_to_sign, domain=get_domain( fork=fork, # `fork` is the fork object at the slot, `attestation_data.slot` epoch=slot_to_epoch(attestation_data.slot), From 911e4f104bde97f4361e78c7e14c9d09d6c6b5da Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 8 Feb 2019 05:12:58 +0800 Subject: [PATCH 41/46] Add `bytes_to_int` --- specs/core/0_beacon-chain.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 38d233b23..c7103b79e 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -76,6 +76,7 @@ - [`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-) + - [`bytes_to_int`](#bytes_to_int) - [`get_effective_balance`](#get_effective_balance) - [`get_total_balance`](#get_total_balance) - [`get_fork_version`](#get_fork_version) @@ -707,7 +708,7 @@ def get_permuted_index(index: int, list_size: int, seed: Bytes32, round_count: i See the 'generalized domain' algorithm on page 3. """ for round in range(round_count): - pivot = int.from_bytes(hash(seed + int_to_bytes1(round)), 'little') % list_size + pivot = bytes_to_int(hash(seed + int_to_bytes1(round))) % list_size flip = (pivot - index) % list_size position = max(index, flip) source = hash(seed + int_to_bytes1(round) + int_to_bytes4(position // 256)) @@ -1007,6 +1008,13 @@ def is_power_of_two(value: int) -> bool: `int_to_bytes1(x): return x.to_bytes(1, 'big')`, `int_to_bytes2(x): return x.to_bytes(2, 'big')`, and so on for all integers, particularly 1, 2, 3, 4, 8, 32, 48, 96. +### `bytes_to_int` + +```python +def bytes_to_int(data: bytes) -> int: + return int.from_bytes(data, 'little') +``` + ### `get_effective_balance` ```python From 89b9894328b6a2060c3fbe61d2079ac400ca1208 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 8 Feb 2019 05:15:42 +0800 Subject: [PATCH 42/46] Fix type hinting --- 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 c7103b79e..7167b93a6 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -697,7 +697,7 @@ def get_active_validator_indices(validators: List[Validator], epoch: EpochNumber ### `get_permuted_index` ```python -def get_permuted_index(index: int, list_size: int, seed: Bytes32, round_count: int=90) -> List[int]: +def get_permuted_index(index: int, list_size: int, seed: Bytes32, round_count: int=90) -> int: """ Return `p(index)` in a pseudorandom permutation `p` of `0...list_size-1` with ``seed`` as entropy. From fd3d4a5105db74016483c1d1abbf81c932889b7f Mon Sep 17 00:00:00 2001 From: mratsim Date: Thu, 7 Feb 2019 22:15:55 +0100 Subject: [PATCH 43/46] Don't change TOC --- specs/core/0_beacon-chain.md | 264 +++++++++++++++++------------------ 1 file changed, 132 insertions(+), 132 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index e6cf019f4..d4e90a57b 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -6,139 +6,139 @@ - [Ethereum 2.0 Phase 0 -- The Beacon Chain](#ethereum-20-phase-0----the-beacon-chain) - - [Table of contents](#table-of-contents) - - [Introduction](#introduction) - - [Notation](#notation) - - [Terminology](#terminology) - - [Constants](#constants) - - [Misc](#misc) - - [Deposit contract](#deposit-contract) - - [Gwei values](#gwei-values) - - [Initial values](#initial-values) - - [Time parameters](#time-parameters) - - [State list lengths](#state-list-lengths) - - [Reward and penalty quotients](#reward-and-penalty-quotients) - - [Status flags](#status-flags) - - [Max operations per block](#max-operations-per-block) - - [Signature domains](#signature-domains) - - [Data structures](#data-structures) - - [Beacon chain operations](#beacon-chain-operations) - - [Proposer slashings](#proposer-slashings) - - [`ProposerSlashing`](#proposerslashing) - - [Attester slashings](#attester-slashings) - - [`AttesterSlashing`](#attesterslashing) - - [`SlashableAttestation`](#slashableattestation) - - [Attestations](#attestations) - - [`Attestation`](#attestation) - - [`AttestationData`](#attestationdata) - - [`AttestationDataAndCustodyBit`](#attestationdataandcustodybit) - - [Deposits](#deposits) - - [`Deposit`](#deposit) - - [`DepositData`](#depositdata) - - [`DepositInput`](#depositinput) - - [Exits](#exits) - - [`Exit`](#exit) - - [Beacon chain blocks](#beacon-chain-blocks) - - [`BeaconBlock`](#beaconblock) - - [`BeaconBlockBody`](#beaconblockbody) - - [`ProposalSignedData`](#proposalsigneddata) - - [Beacon chain state](#beacon-chain-state) - - [`BeaconState`](#beaconstate) - - [`Validator`](#validator) - - [`Crosslink`](#crosslink) - - [`PendingAttestation`](#pendingattestation) - - [`Fork`](#fork) - - [`Eth1Data`](#eth1data) - - [`Eth1DataVote`](#eth1datavote) - - [Custom Types](#custom-types) - - [Helper functions](#helper-functions) - - [`hash`](#hash) - - [`hash_tree_root`](#hashtreeroot) - - [`slot_to_epoch`](#slottoepoch) - - [`get_previous_epoch`](#getpreviousepoch) - - [`get_current_epoch`](#getcurrentepoch) - - [`get_epoch_start_slot`](#getepochstartslot) - - [`is_active_validator`](#isactivevalidator) - - [`get_active_validator_indices`](#getactivevalidatorindices) - - [`shuffle`](#shuffle) - - [`split`](#split) - - [`get_epoch_committee_count`](#getepochcommitteecount) - - [`get_shuffling`](#getshuffling) - - [`get_previous_epoch_committee_count`](#getpreviousepochcommitteecount) - - [`get_current_epoch_committee_count`](#getcurrentepochcommitteecount) - - [`get_next_epoch_committee_count`](#getnextepochcommitteecount) - - [`get_crosslink_committees_at_slot`](#getcrosslinkcommitteesatslot) - - [`get_block_root`](#getblockroot) - - [`get_randao_mix`](#getrandaomix) - - [`get_active_index_root`](#getactiveindexroot) - - [`generate_seed`](#generateseed) - - [`get_beacon_proposer_index`](#getbeaconproposerindex) - - [`merkle_root`](#merkleroot) - - [`get_attestation_participants`](#getattestationparticipants) - - [`is_power_of_two`](#ispoweroftwo) - - [`int_to_bytes1`, `int_to_bytes2`, ...](#inttobytes1-inttobytes2) - - [`get_effective_balance`](#geteffectivebalance) - - [`get_total_balance`](#gettotalbalance) - - [`get_fork_version`](#getforkversion) - - [`get_domain`](#getdomain) - - [`get_bitfield_bit`](#getbitfieldbit) - - [`verify_bitfield`](#verifybitfield) - - [`verify_slashable_attestation`](#verifyslashableattestation) - - [`is_double_vote`](#isdoublevote) - - [`is_surround_vote`](#issurroundvote) - - [`integer_squareroot`](#integersquareroot) - - [`get_entry_exit_effect_epoch`](#getentryexiteffectepoch) - - [`bls_verify`](#blsverify) - - [`bls_verify_multiple`](#blsverifymultiple) - - [`bls_aggregate_pubkeys`](#blsaggregatepubkeys) - - [`validate_proof_of_possession`](#validateproofofpossession) - - [`process_deposit`](#processdeposit) - - [Routines for updating validator status](#routines-for-updating-validator-status) - - [`activate_validator`](#activatevalidator) - - [`initiate_validator_exit`](#initiatevalidatorexit) - - [`exit_validator`](#exitvalidator) - - [`penalize_validator`](#penalizevalidator) - - [`prepare_validator_for_withdrawal`](#preparevalidatorforwithdrawal) - - [Ethereum 1.0 deposit contract](#ethereum-10-deposit-contract) - - [Deposit arguments](#deposit-arguments) - - [Withdrawal credentials](#withdrawal-credentials) - - [`Deposit` logs](#deposit-logs) - - [`ChainStart` log](#chainstart-log) - - [Vyper code](#vyper-code) - - [On startup](#on-startup) - - [Beacon chain processing](#beacon-chain-processing) - - [Beacon chain fork choice rule](#beacon-chain-fork-choice-rule) - - [Beacon chain state transition function](#beacon-chain-state-transition-function) - - [Per-slot processing](#per-slot-processing) - - [Slot](#slot) - - [Block roots](#block-roots) - - [Per-block processing](#per-block-processing) - - [Slot](#slot-1) - - [Proposer signature](#proposer-signature) - - [RANDAO](#randao) - - [Eth1 data](#eth1-data) - - [Operations](#operations) - - [Proposer slashings](#proposer-slashings-1) - - [Attester slashings](#attester-slashings-1) - - [Attestations](#attestations-1) - - [Deposits](#deposits-1) - - [Exits](#exits-1) - - [Per-epoch processing](#per-epoch-processing) - - [Helpers](#helpers) - - [Eth1 data](#eth1-data-1) - - [Justification](#justification) - - [Crosslinks](#crosslinks) - - [Rewards and penalties](#rewards-and-penalties) - - [Justification and finalization](#justification-and-finalization) - - [Attestation inclusion](#attestation-inclusion) - - [Crosslinks](#crosslinks-1) - - [Ejections](#ejections) - - [Validator registry and shuffling seed data](#validator-registry-and-shuffling-seed-data) - - [Final updates](#final-updates) - - [State root verification](#state-root-verification) + - [Table of contents](#table-of-contents) + - [Introduction](#introduction) + - [Notation](#notation) + - [Terminology](#terminology) + - [Constants](#constants) + - [Misc](#misc) + - [Deposit contract](#deposit-contract) + - [Gwei values](#gwei-values) + - [Initial values](#initial-values) + - [Time parameters](#time-parameters) + - [State list lengths](#state-list-lengths) + - [Reward and penalty quotients](#reward-and-penalty-quotients) + - [Status flags](#status-flags) + - [Max operations per block](#max-operations-per-block) + - [Signature domains](#signature-domains) + - [Data structures](#data-structures) + - [Beacon chain operations](#beacon-chain-operations) + - [Proposer slashings](#proposer-slashings) + - [`ProposerSlashing`](#proposerslashing) + - [Attester slashings](#attester-slashings) + - [`AttesterSlashing`](#attesterslashing) + - [`SlashableAttestation`](#slashableattestation) + - [Attestations](#attestations) + - [`Attestation`](#attestation) + - [`AttestationData`](#attestationdata) + - [`AttestationDataAndCustodyBit`](#attestationdataandcustodybit) + - [Deposits](#deposits) + - [`Deposit`](#deposit) + - [`DepositData`](#depositdata) + - [`DepositInput`](#depositinput) + - [Exits](#exits) + - [`Exit`](#exit) + - [Beacon chain blocks](#beacon-chain-blocks) + - [`BeaconBlock`](#beaconblock) + - [`BeaconBlockBody`](#beaconblockbody) + - [`ProposalSignedData`](#proposalsigneddata) + - [Beacon chain state](#beacon-chain-state) + - [`BeaconState`](#beaconstate) + - [`Validator`](#validator) + - [`Crosslink`](#crosslink) + - [`PendingAttestation`](#pendingattestation) + - [`Fork`](#fork) + - [`Eth1Data`](#eth1data) + - [`Eth1DataVote`](#eth1datavote) + - [Custom Types](#custom-types) + - [Helper functions](#helper-functions) + - [`hash`](#hash) + - [`hash_tree_root`](#hash_tree_root) + - [`slot_to_epoch`](#slot_to_epoch) + - [`get_previous_epoch`](#get_previous_epoch) + - [`get_current_epoch`](#get_current_epoch) + - [`get_epoch_start_slot`](#get_epoch_start_slot) + - [`is_active_validator`](#is_active_validator) + - [`get_active_validator_indices`](#get_active_validator_indices) + - [`shuffle`](#shuffle) + - [`split`](#split) + - [`get_epoch_committee_count`](#get_epoch_committee_count) + - [`get_shuffling`](#get_shuffling) + - [`get_previous_epoch_committee_count`](#get_previous_epoch_committee_count) + - [`get_current_epoch_committee_count`](#get_current_epoch_committee_count) + - [`get_next_epoch_committee_count`](#get_next_epoch_committee_count) + - [`get_crosslink_committees_at_slot`](#get_crosslink_committees_at_slot) + - [`get_block_root`](#get_block_root) + - [`get_randao_mix`](#get_randao_mix) + - [`get_active_index_root`](#get_active_index_root) + - [`generate_seed`](#generate_seed) + - [`get_beacon_proposer_index`](#get_beacon_proposer_index) + - [`merkle_root`](#merkle_root) + - [`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-) + - [`get_effective_balance`](#get_effective_balance) + - [`get_total_balance`](#get_total_balance) + - [`get_fork_version`](#get_fork_version) + - [`get_domain`](#get_domain) + - [`get_bitfield_bit`](#get_bitfield_bit) + - [`verify_bitfield`](#verify_bitfield) + - [`verify_slashable_attestation`](#verify_slashable_attestation) + - [`is_double_vote`](#is_double_vote) + - [`is_surround_vote`](#is_surround_vote) + - [`integer_squareroot`](#integer_squareroot) + - [`get_entry_exit_effect_epoch`](#get_entry_exit_effect_epoch) + - [`bls_verify`](#bls_verify) + - [`bls_verify_multiple`](#bls_verify_multiple) + - [`bls_aggregate_pubkeys`](#bls_aggregate_pubkeys) + - [`validate_proof_of_possession`](#validate_proof_of_possession) + - [`process_deposit`](#process_deposit) + - [Routines for updating validator status](#routines-for-updating-validator-status) + - [`activate_validator`](#activate_validator) + - [`initiate_validator_exit`](#initiate_validator_exit) + - [`exit_validator`](#exit_validator) + - [`penalize_validator`](#penalize_validator) + - [`prepare_validator_for_withdrawal`](#prepare_validator_for_withdrawal) + - [Ethereum 1.0 deposit contract](#ethereum-10-deposit-contract) + - [Deposit arguments](#deposit-arguments) + - [Withdrawal credentials](#withdrawal-credentials) + - [`Deposit` logs](#deposit-logs) + - [`ChainStart` log](#chainstart-log) + - [Vyper code](#vyper-code) + - [On startup](#on-startup) + - [Beacon chain processing](#beacon-chain-processing) + - [Beacon chain fork choice rule](#beacon-chain-fork-choice-rule) + - [Beacon chain state transition function](#beacon-chain-state-transition-function) + - [Per-slot processing](#per-slot-processing) + - [Slot](#slot) + - [Block roots](#block-roots) + - [Per-block processing](#per-block-processing) + - [Slot](#slot-1) + - [Proposer signature](#proposer-signature) + - [RANDAO](#randao) + - [Eth1 data](#eth1-data) + - [Operations](#operations) + - [Proposer slashings](#proposer-slashings-1) + - [Attester slashings](#attester-slashings-1) + - [Attestations](#attestations-1) + - [Deposits](#deposits-1) + - [Exits](#exits-1) + - [Per-epoch processing](#per-epoch-processing) + - [Helpers](#helpers) + - [Eth1 data](#eth1-data-1) + - [Justification](#justification) + - [Crosslinks](#crosslinks) + - [Rewards and penalties](#rewards-and-penalties) + - [Justification and finalization](#justification-and-finalization) + - [Attestation inclusion](#attestation-inclusion) + - [Crosslinks](#crosslinks-1) + - [Ejections](#ejections) + - [Validator registry and shuffling seed data](#validator-registry-and-shuffling-seed-data) + - [Final updates](#final-updates) + - [State root verification](#state-root-verification) - [References](#references) - - [Normative](#normative) - - [Informative](#informative) + - [Normative](#normative) + - [Informative](#informative) - [Copyright](#copyright) From ca098f8cfa5c0ab0daa38c784ee4e563fd1c9fdf Mon Sep 17 00:00:00 2001 From: mratsim Date: Thu, 7 Feb 2019 22:19:04 +0100 Subject: [PATCH 44/46] Prevent changing another TOC --- specs/validator/0_beacon-chain-validator.md | 94 ++++++++++----------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/specs/validator/0_beacon-chain-validator.md b/specs/validator/0_beacon-chain-validator.md index b8db2117c..744df690f 100644 --- a/specs/validator/0_beacon-chain-validator.md +++ b/specs/validator/0_beacon-chain-validator.md @@ -7,53 +7,53 @@ __NOTICE__: This document is a work-in-progress for researchers and implementers - [Ethereum 2.0 Phase 0 -- Honest Validator](#ethereum-20-phase-0----honest-validator) - - [Table of Contents](#table-of-contents) - - [Introduction](#introduction) - - [Prerequisites](#prerequisites) - - [Constants](#constants) - - [Misc](#misc) - - [Becoming a validator](#becoming-a-validator) - - [Initialization](#initialization) - - [BLS public key](#bls-public-key) - - [BLS withdrawal key](#bls-withdrawal-key) - - [Submit deposit](#submit-deposit) - - [Process deposit](#process-deposit) - - [Validator index](#validator-index) - - [Activation](#activation) - - [Beacon chain responsibilities](#beacon-chain-responsibilities) - - [Block proposal](#block-proposal) - - [Block header](#block-header) - - [Slot](#slot) - - [Parent root](#parent-root) - - [State root](#state-root) - - [Randao reveal](#randao-reveal) - - [Eth1 Data](#eth1-data) - - [Signature](#signature) - - [Block body](#block-body) - - [Proposer slashings](#proposer-slashings) - - [Attester slashings](#attester-slashings) - - [Attestations](#attestations) - - [Deposits](#deposits) - - [Exits](#exits) - - [Attestations](#attestations-1) - - [Attestation data](#attestation-data) - - [Slot](#slot-1) - - [Shard](#shard) - - [Beacon block root](#beacon-block-root) - - [Epoch boundary root](#epoch-boundary-root) - - [Shard block root](#shard-block-root) - - [Latest crosslink root](#latest-crosslink-root) - - [Justified epoch](#justified-epoch) - - [Justified block root](#justified-block-root) - - [Construct attestation](#construct-attestation) - - [Data](#data) - - [Aggregation bitfield](#aggregation-bitfield) - - [Custody bitfield](#custody-bitfield) - - [Aggregate signature](#aggregate-signature) - - [Responsibility lookahead](#responsibility-lookahead) - - [How to avoid slashing](#how-to-avoid-slashing) - - [Proposer slashing](#proposer-slashing) - - [Attester slashing](#attester-slashing) + - [Table of Contents](#table-of-contents) + - [Introduction](#introduction) + - [Prerequisites](#prerequisites) + - [Constants](#constants) + - [Misc](#misc) + - [Becoming a validator](#becoming-a-validator) + - [Initialization](#initialization) + - [BLS public key](#bls-public-key) + - [BLS withdrawal key](#bls-withdrawal-key) + - [Submit deposit](#submit-deposit) + - [Process deposit](#process-deposit) + - [Validator index](#validator-index) + - [Activation](#activation) + - [Beacon chain responsibilities](#beacon-chain-responsibilities) + - [Block proposal](#block-proposal) + - [Block header](#block-header) + - [Slot](#slot) + - [Parent root](#parent-root) + - [State root](#state-root) + - [Randao reveal](#randao-reveal) + - [Eth1 Data](#eth1-data) + - [Signature](#signature) + - [Block body](#block-body) + - [Proposer slashings](#proposer-slashings) + - [Attester slashings](#attester-slashings) + - [Attestations](#attestations) + - [Deposits](#deposits) + - [Exits](#exits) + - [Attestations](#attestations-1) + - [Attestation data](#attestation-data) + - [Slot](#slot-1) + - [Shard](#shard) + - [Beacon block root](#beacon-block-root) + - [Epoch boundary root](#epoch-boundary-root) + - [Shard block root](#shard-block-root) + - [Latest crosslink root](#latest-crosslink-root) + - [Justified epoch](#justified-epoch) + - [Justified block root](#justified-block-root) + - [Construct attestation](#construct-attestation) + - [Data](#data) + - [Aggregation bitfield](#aggregation-bitfield) + - [Custody bitfield](#custody-bitfield) + - [Aggregate signature](#aggregate-signature) + - [Responsibility lookahead](#responsibility-lookahead) + - [How to avoid slashing](#how-to-avoid-slashing) + - [Proposer slashing](#proposer-slashing) + - [Attester slashing](#attester-slashing) From f797826ee29767ef3133a97ec1f28d347553ede7 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Thu, 7 Feb 2019 21:51:56 -0600 Subject: [PATCH 45/46] 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 7167b93a6..50daad513 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -708,7 +708,7 @@ def get_permuted_index(index: int, list_size: int, seed: Bytes32, round_count: i See the 'generalized domain' algorithm on page 3. """ for round in range(round_count): - pivot = bytes_to_int(hash(seed + int_to_bytes1(round))) % list_size + pivot = bytes_to_int(hash(seed + int_to_bytes1(round))[0:8]) % list_size flip = (pivot - index) % list_size position = max(index, flip) source = hash(seed + int_to_bytes1(round) + int_to_bytes4(position // 256)) From 1c6ccac8fc1f02079f49bf9fd715b64764c304e0 Mon Sep 17 00:00:00 2001 From: vbuterin Date: Thu, 7 Feb 2019 21:55:33 -0600 Subject: [PATCH 46/46] SHUFFLE_ROUND_COUNT as global constant --- specs/core/0_beacon-chain.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 50daad513..a7a21683c 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -185,6 +185,7 @@ Code snippets appearing in `this style` are to be interpreted as Python code. Be | `BEACON_CHAIN_SHARD_NUMBER` | `2**64 - 1` | - | | `MAX_INDICES_PER_SLASHABLE_VOTE` | `2**12` (= 4,096) | votes | | `MAX_WITHDRAWALS_PER_EPOCH` | `2**2` (= 4) | withdrawals | +| `SHUFFLE_ROUND_COUNT` | 90 | - | * For the safety of crosslinks `TARGET_COMMITTEE_SIZE` exceeds [the recommended minimum committee size of 111](https://vitalik.ca/files/Ithaca201807_Sharding.pdf); with sufficient active validators (at least `EPOCH_LENGTH * TARGET_COMMITTEE_SIZE`), the shuffling algorithm ensures committee sizes at least `TARGET_COMMITTEE_SIZE`. (Unbiasable randomness with a Verifiable Delay Function (VDF) will improve committee robustness and lower the safe minimum committee size.) @@ -697,17 +698,15 @@ def get_active_validator_indices(validators: List[Validator], epoch: EpochNumber ### `get_permuted_index` ```python -def get_permuted_index(index: int, list_size: int, seed: Bytes32, round_count: int=90) -> int: +def get_permuted_index(index: int, list_size: int, seed: Bytes32) -> int: """ Return `p(index)` in a pseudorandom permutation `p` of `0...list_size-1` with ``seed`` as entropy. - Note that ``round_count`` is ``90`` in protocol and parameterized for the shuffling tests. - Utilizes 'swap or not' shuffling found in https://link.springer.com/content/pdf/10.1007%2F978-3-642-32009-5_1.pdf See the 'generalized domain' algorithm on page 3. """ - for round in range(round_count): + for round in range(SHUFFLE_ROUND_COUNT): pivot = bytes_to_int(hash(seed + int_to_bytes1(round))[0:8]) % list_size flip = (pivot - index) % list_size position = max(index, flip)