From 375659dc6c92ddcbf1682a024f9afc4fb24335c6 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Thu, 14 Feb 2019 16:02:01 -0700 Subject: [PATCH 01/10] name changes in validator doc and phase 1 doc --- specs/core/1_shard-data-chains.md | 18 +++++++++--------- specs/validator/0_beacon-chain-validator.md | 16 ++++++++-------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/specs/core/1_shard-data-chains.md b/specs/core/1_shard-data-chains.md index 365fb640d..cbb84aa0e 100644 --- a/specs/core/1_shard-data-chains.md +++ b/specs/core/1_shard-data-chains.md @@ -47,8 +47,8 @@ def get_split_offset(list_size: int, chunks: int, index: int) -> int: ```python def get_shuffled_committee(state: BeaconState, - shard: ShardNumber, - committee_start_epoch: EpochNumber) -> List[ValidatorIndex]: + shard: Shard, + committee_start_epoch: Epoch) -> List[ValidatorIndex]: """ Return shuffled committee. """ @@ -66,8 +66,8 @@ def get_shuffled_committee(state: BeaconState, ```python def get_persistent_committee(state: BeaconState, - shard: ShardNumber, - epoch: EpochNumber) -> List[ValidatorIndex]: + shard: Shard, + epoch: Epoch) -> List[ValidatorIndex]: """ Return the persistent committee for the given ``shard`` at the given ``epoch``. """ @@ -94,10 +94,10 @@ def get_persistent_committee(state: BeaconState, ```python def get_shard_proposer_index(state: BeaconState, - shard: ShardNumber, - slot: SlotNumber) -> ValidatorIndex: + shard: Shard, + slot: Slot) -> ValidatorIndex: seed = hash( - state.current_epoch_seed + + state.current_shuffling_seed + int_to_bytes8(shard) + int_to_bytes8(slot) ) @@ -177,8 +177,8 @@ A node should sign a crosslink only if the following conditions hold. **If a nod First, the conditions must recursively apply to the crosslink referenced in `last_crosslink_root` for the same shard (unless `last_crosslink_root` equals zero, in which case we are at the genesis). Second, we verify the `shard_chain_commitment`. -* Let `start_slot = state.latest_crosslinks[shard].epoch * EPOCH_LENGTH + EPOCH_LENGTH - CROSSLINK_LOOKBACK`. -* Let `end_slot = attestation.data.slot - attestation.data.slot % EPOCH_LENGTH - CROSSLINK_LOOKBACK`. +* Let `start_slot = state.latest_crosslinks[shard].epoch * SLOTS_PER_EPOCH + SLOTS_PER_EPOCH - CROSSLINK_LOOKBACK`. +* Let `end_slot = attestation.data.slot - attestation.data.slot % SLOTS_PER_EPOCH - CROSSLINK_LOOKBACK`. * Let `length = end_slot - start_slot`, `headers[0] .... headers[length-1]` be the serialized block headers in the canonical shard chain from the verifer's point of view (note that this implies that `headers` and `bodies` have been checked for validity). * Let `bodies[0] ... bodies[length-1]` be the bodies of the blocks. * Note: If there is a missing slot, then the header and body are the same as that of the block at the most recent slot that has a block. diff --git a/specs/validator/0_beacon-chain-validator.md b/specs/validator/0_beacon-chain-validator.md index b893941ec..2211e2e41 100644 --- a/specs/validator/0_beacon-chain-validator.md +++ b/specs/validator/0_beacon-chain-validator.md @@ -34,7 +34,7 @@ __NOTICE__: This document is a work-in-progress for researchers and implementers - [Attester slashings](#attester-slashings) - [Attestations](#attestations) - [Deposits](#deposits) - - [Exits](#exits) + - [Voluntary exits](#voluntary-exits) - [Attestations](#attestations-1) - [Attestation data](#attestation-data) - [Slot](#slot-1) @@ -118,7 +118,7 @@ Once a validator has been processed and added to the beacon state's `validator_r ### Activation -In normal operation, the validator is quickly activated at which point the validator is added to the shuffling and begins validation after an additional `ENTRY_EXIT_DELAY` epochs (25.6 minutes). +In normal operation, the validator is quickly activated at which point the validator is added to the shuffling and begins validation after an additional `ACTIVATION_EXIT_DELAY` epochs (25.6 minutes). The function [`is_active_validator`](https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#is_active_validator) can be used to check if a validator is active during a given epoch. Usage is as follows: @@ -232,15 +232,15 @@ Up to `MAX_ATTESTATIONS` aggregate attestations can be included in the `block`. Up to `MAX_DEPOSITS` [`Deposit`](https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#deposit) objects can be included in the `block`. These deposits are constructed from the `Deposit` logs from the [Eth1.0 deposit contract](https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#ethereum-10-deposit-contract) and must be processed in sequential order. The deposits included in the `block` must satisfy the verification conditions found in [deposits processing](https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#deposits-1). -##### Exits +##### Voluntary exits -Up to `MAX_EXITS` [`Exit`](https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#exit) objects can be included in the `block`. The exits must satisfy the verification conditions found in [exits processing](https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#exits-1). +Up to `MAX_VOLUNTARY_EXITS` [`VoluntaryExit`](https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#voluntaryexit) objects can be included in the `block`. The exits must satisfy the verification conditions found in [exits processing](https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#exits-1). ### Attestations A validator is expected to create, sign, and broadcast an attestation during each epoch. The slot during which the validator performs this role is any slot at which `get_crosslink_committees_at_slot(state, slot)` contains a committee that contains `validator_index`. -A validator should create and broadcast the attestation halfway through the `slot` during which the validator is assigned -- that is `SLOT_DURATION * 0.5` seconds after the start of `slot`. +A validator should create and broadcast the attestation halfway through the `slot` during which the validator is assigned -- that is `SECONDS_PER_SLOT * 0.5` seconds after the start of `slot`. #### Attestation data @@ -347,7 +347,7 @@ Either (2) or (3) occurs if (1) fails. The choice between (2) and (3) is determi def get_next_epoch_committee_assignment( state: BeaconState, validator_index: ValidatorIndex, - registry_change: bool) -> Tuple[List[ValidatorIndex], ShardNumber, SlotNumber, bool]: + registry_change: bool) -> Tuple[List[ValidatorIndex], Shard, Slot, bool]: """ Return the committee assignment in the next epoch for ``validator_index`` and ``registry_change``. ``assignment`` returned is a tuple of the following form: @@ -360,14 +360,14 @@ def get_next_epoch_committee_assignment( current_epoch = get_current_epoch(state) next_epoch = current_epoch + 1 next_epoch_start_slot = get_epoch_start_slot(next_epoch) - for slot in range(next_epoch_start_slot, next_epoch_start_slot + EPOCH_LENGTH): + for slot in range(next_epoch_start_slot, next_epoch_start_slot + SLOTS_PER_EPOCH): crosslink_committees = get_crosslink_committees_at_slot( state, slot, registry_change=registry_change, ) selected_committees = [ - committee # Tuple[List[ValidatorIndex], ShardNumber] + committee # Tuple[List[ValidatorIndex], Shard] for committee in crosslink_committees if validator_index in committee[0] ] From e0c28a3cd06309caa61b72c83feafefd983df226 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 15 Feb 2019 18:25:30 +0800 Subject: [PATCH 02/10] Fix `slash_validator` Define `validator` before using it. --- 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 a48d881fa..e181fc28c 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1372,9 +1372,9 @@ def slash_validator(state: BeaconState, index: ValidatorIndex) -> None: Slash the validator with index ``index``. Note that this function mutates ``state``. """ + validator = state.validator_registry[index] assert state.slot < validator.withdrawable_epoch # [TO BE REMOVED IN PHASE 2] exit_validator(state, index) - validator = state.validator_registry[index] state.latest_slashed_balances[get_current_epoch(state) % LATEST_SLASHED_EXIT_LENGTH] += get_effective_balance(state, index) whistleblower_index = get_beacon_proposer_index(state, state.slot) From 6f856ba00913fefba28d217ec20acd302bf05b15 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 15 Feb 2019 18:33:22 +0800 Subject: [PATCH 03/10] Comparing in 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 e181fc28c..673c2eeaf 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1373,7 +1373,7 @@ def slash_validator(state: BeaconState, index: ValidatorIndex) -> None: Note that this function mutates ``state``. """ validator = state.validator_registry[index] - assert state.slot < validator.withdrawable_epoch # [TO BE REMOVED IN PHASE 2] + assert state.slot < get_epoch_start_slot(validator.withdrawable_epoch) # [TO BE REMOVED IN PHASE 2] exit_validator(state, index) state.latest_slashed_balances[get_current_epoch(state) % LATEST_SLASHED_EXIT_LENGTH] += get_effective_balance(state, index) From 984eb79f68ca8533fccf95155219504b422655a0 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 15 Feb 2019 21:46:47 +0800 Subject: [PATCH 04/10] Fix unix time condition of an acceptable block (#636) --- 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 a48d881fa..023315356 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1555,7 +1555,7 @@ For a beacon chain block, `block`, to be processed by a node, the following cond * The parent block with root `block.parent_root` has been processed and accepted. * An Ethereum 1.0 block pointed to by the `state.latest_eth1_data.block_hash` has been processed and accepted. -* The node's Unix time is greater than or equal to `state.genesis_time + block.slot * SECONDS_PER_SLOT`. (Note that leap seconds mean that slots will occasionally last `SECONDS_PER_SLOT + 1` or `SECONDS_PER_SLOT - 1` seconds, possibly several times a year.) +* The node's Unix time is greater than or equal to `state.genesis_time + (block.slot - GENESIS_SLOT) * SECONDS_PER_SLOT`. (Note that leap seconds mean that slots will occasionally last `SECONDS_PER_SLOT + 1` or `SECONDS_PER_SLOT - 1` seconds, possibly several times a year.) If these conditions are not met, the client should delay processing the beacon block until the conditions are all satisfied. From e074bc2c344b0154e1d993141def13cc48389ec1 Mon Sep 17 00:00:00 2001 From: Jonny Rhea Date: Fri, 15 Feb 2019 08:48:09 -0600 Subject: [PATCH 05/10] Update 0_beacon-chain.md (#635) replace vote_data with slashable_attestation in verify_slashable_attestation() --- 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 023315356..490a306b4 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1168,7 +1168,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(slashable_attestation.data.slot), DOMAIN_ATTESTATION), ) ``` From 464947dbd4b7a0f210e3a88862a91a6329b39667 Mon Sep 17 00:00:00 2001 From: d-yokoi Date: Sat, 16 Feb 2019 18:11:29 +0900 Subject: [PATCH 06/10] docs: fix typo in 0_beacon-chain.md (#640) --- 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 ce13c6105..af6f78976 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -181,7 +181,7 @@ Code snippets appearing in `this style` are to be interpreted as Python code. ### Misc | Name | Value | -| - | - | :-: | +| - | - | | `SHARD_COUNT` | `2**10` (= 1,024) | | `TARGET_COMMITTEE_SIZE` | `2**7` (= 128) | | `MAX_BALANCE_CHURN_QUOTIENT` | `2**5` (= 32) | From f2e547e62909d98181eeebf22e6323ff5ca3e103 Mon Sep 17 00:00:00 2001 From: d-yokoi Date: Sat, 16 Feb 2019 23:12:00 +0900 Subject: [PATCH 07/10] docs: fix typo in 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 af6f78976..544d79244 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1666,7 +1666,7 @@ Below are the processing steps that happen at every `block`. #### Eth1 data -* 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`. +* If there exists an `eth1_data_vote` in `state.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)`. #### Transactions From 59ade930d6384434b2e606e98422c54b9fc9576e Mon Sep 17 00:00:00 2001 From: vbuterin Date: Sat, 16 Feb 2019 15:44:27 -0600 Subject: [PATCH 08/10] Signature hashing proposal (#625) If this is accepted, then we can replace all uses of signing in the protocol, which are currently done in a relatively inconsistent way (see proposer signatures, attester signatures, shard proposer signatures, exit message signatures.....) could be unified. --- specs/simple-serialize.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/specs/simple-serialize.md b/specs/simple-serialize.md index c71654b67..6021619a6 100644 --- a/specs/simple-serialize.md +++ b/specs/simple-serialize.md @@ -24,11 +24,12 @@ deserializing objects and data types. - [bytesN](#bytesn-1) - [List/Vectors](#listvectors-1) - [Container](#container-1) - + [Tree Hash](#tree-hash) + + [Tree Hash](#tree-hash) - [`uint8`..`uint256`, `bool`, `bytes1`..`bytes32`](#uint8uint256-bool-bytes1bytes32) - [`uint264`..`uintN`, `bytes33`..`bytesN`](#uint264uintn-bytes33bytesn) - [List/Vectors](#listvectors-2) - [Container](#container-2) + + [Signed Roots](#signed-roots) * [Implementations](#implementations) ## About @@ -396,6 +397,14 @@ Recursively tree hash the values in the container in the same order as the field return merkle_hash([hash_tree_root_internal(getattr(x, field)) for field in value.fields]) ``` +### Signed roots + +Let `field_name` be a field name in an SSZ container `container`. We define `truncate(container, field_name)` to be the `container` with the fields from `field_name` onwards truncated away. That is, `truncate(container, field_name) = [getattr(container, field)) for field in value.fields[:i]]` where `i = value.fields.index(field_name)`. + +When `field_name` maps to a signature (e.g. a BLS12-381 signature of type `Bytes96`) the convention is that the corresponding signed message be `signed_root(container, field_name) = hash_tree_root(truncate(container, field_name))`. For example if `container = {"foo": sub_object_1, "bar": sub_object_2, "signature": bytes96, "baz": sub_object_3}` then `signed_root(container, "signature") = merkle_hash([hash_tree_root(sub_object_1), hash_tree_root(sub_object_2)])`. + +Note that this convention means that fields after the signature are _not_ signed over. If there are multiple signatures in `container` then those are expected to be signing over the fields in the order specified. If multiple signatures of the same value are expected the convention is that the signature field be an array of signatures. + ## Implementations | Language | Implementation | Description | From eea413bcc5bfc083cd33eddd2eaa3ad2a545398b Mon Sep 17 00:00:00 2001 From: Cayman Date: Sun, 17 Feb 2019 15:53:59 -0700 Subject: [PATCH 09/10] Fix typos (#648) --- 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 544d79244..7ce4939e8 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1797,7 +1797,7 @@ For each `exit` in `block.body.voluntary_exits`: * Let `validator = state.validator_registry[exit.validator_index]`. * 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))`. +* Let `exit_message = hash_tree_root(VoluntaryExit(epoch=exit.epoch, validator_index=exit.validator_index, signature=EMPTY_SIGNATURE))`. * 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)`. @@ -2098,7 +2098,7 @@ def process_exit_queue(state: BeaconState) -> None: #### Final updates -* Set `state.latest_active_index_roots[(next_epoch + ACTIVATION_EXIT_DELAY) % LATEST_ACTIVE_INDEX_ROOTS_LENGTH] = hash_tree_root(get_active_validator_indices(state, next_epoch + ACTIVATION_EXIT_DELAY))`. +* Set `state.latest_active_index_roots[(next_epoch + ACTIVATION_EXIT_DELAY) % LATEST_ACTIVE_INDEX_ROOTS_LENGTH] = hash_tree_root(get_active_validator_indices(state.validator_registry, next_epoch + ACTIVATION_EXIT_DELAY))`. * Set `state.latest_slashed_balances[(next_epoch) % LATEST_SLASHED_EXIT_LENGTH] = state.latest_slashed_balances[current_epoch % LATEST_SLASHED_EXIT_LENGTH]`. * Set `state.latest_randao_mixes[next_epoch % LATEST_RANDAO_MIXES_LENGTH] = get_randao_mix(state, current_epoch)`. * Remove any `attestation` in `state.latest_attestations` such that `slot_to_epoch(attestation.data.slot) < current_epoch`. From 5fbbb4f18117e0313bfb13303f29b219111dd900 Mon Sep 17 00:00:00 2001 From: Cayman Date: Sun, 17 Feb 2019 21:11:01 -0700 Subject: [PATCH 10/10] Clarify merkle_root documentation (#646) This function is used to get the merkle root of some block roots which are themselves hashes, so the leaves do not need to be rehashed. Unfortunately, it's easy to assume that a merkle_root function would hash its leaves, so it should be clarified. --- 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 7ce4939e8..116745dcc 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -995,6 +995,7 @@ def get_beacon_proposer_index(state: BeaconState, def merkle_root(values: List[Bytes32]) -> Bytes32: """ Merkleize ``values`` (where ``len(values)`` is a power of two) and return the Merkle root. + Note that the leaves are not hashed. """ o = [0] * len(values) + values for i in range(len(values) - 1, 0, -1):