From 8597cbef1fb28f6f54eedfded5b5f633b4928694 Mon Sep 17 00:00:00 2001 From: vbuterin Date: Wed, 6 Feb 2019 20:32:56 -0600 Subject: [PATCH 01/22] Updated phase 1: shard block structure --- specs/core/1_shard-data-chains.md | 58 +++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 19 deletions(-) diff --git a/specs/core/1_shard-data-chains.md b/specs/core/1_shard-data-chains.md index cabe2934e..f3324bbbd 100644 --- a/specs/core/1_shard-data-chains.md +++ b/specs/core/1_shard-data-chains.md @@ -16,10 +16,11 @@ Ethereum 2.0 consists of a central beacon chain along with `SHARD_COUNT` shard c Phase 1 depends upon all of the constants defined in [Phase 0](0_beacon-chain.md#constants) in addition to the following: -| Constant | Value | Unit | Approximation | -|------------------------|-----------------|-------|---------------| -| `SHARD_CHUNK_SIZE` | 2**5 (= 32) | bytes | | -| `SHARD_BLOCK_SIZE` | 2**14 (= 16384) | bytes | | +| Constant | Value | Unit | Approximation | +|-----------------------------|-----------------|--------|---------------| +| `SHARD_CHUNK_SIZE` | 2**5 (= 32) | bytes | | +| `SHARD_BLOCK_SIZE` | 2**14 (= 16384) | bytes | | +| `PROPOSAL_RESHUFFLE_PERIOD` | 2**11 (= 2048) | epochs | 9 days | ### Flags, domains, etc. @@ -40,12 +41,10 @@ A `ShardBlock` object has the following fields: 'slot': 'uint64', # What shard is it on 'shard_id': 'uint64', - # Parent block's hash of root + # Parent block's root 'parent_root': 'hash32', # Beacon chain block 'beacon_chain_ref': 'hash32', - # Depth of the Merkle tree - 'data_tree_depth': 'uint8', # Merkle root of data 'data_root': 'hash32' # State root (placeholder for now) @@ -67,22 +66,43 @@ For a block on a shard to be processed by a node, the following conditions must To validate a block header on shard `shard_id`, compute as follows: -* Verify that `beacon_chain_ref` is the hash of a block in the beacon chain with slot less than or equal to `slot`. Verify that `beacon_chain_ref` is equal to or a descendant of the `beacon_chain_ref` specified in the `ShardBlock` pointed to by `parent_root`. -* Let `state` be the state of the beacon chain block referred to by `beacon_chain_ref`. Let `validators` be `[validators[i] for i in state.current_persistent_committees[shard_id]]`. -* Assert `len(participation_bitfield) == ceil_div8(len(validators))` +* Verify that `beacon_chain_ref` is the hash of a block in the (canonical) beacon chain with slot less than or equal to `slot`. +* Verify that `beacon_chain_ref` is equal to or a descendant of the `beacon_chain_ref` specified in the `ShardBlock` pointed to by `parent_root`. +* Let `state` be the state of the beacon chain block referred to by `beacon_chain_ref`. Let `persistent_committee` be `[persistent_committee[i] for i in get_persistent_committee(state, slot, shard_id)`. +* Assert `verify_bitfield(participation_bitfield, len(persistent_committee))` * Let `proposer_index = hash(state.randao_mix + int_to_bytes8(shard_id) + int_to_bytes8(slot)) % len(validators)`. Let `msg` be the block but with the `block.signature` set to `[0, 0]`. Verify that `BLSVerify(pub=validators[proposer_index].pubkey, msg=hash(msg), sig=block.signature, domain=get_domain(state, slot, SHARD_PROPOSER_DOMAIN))` passes. -* Generate the `group_public_key` by adding the public keys of all the validators for whom the corresponding position in the bitfield is set to 1. Verify that `BLSVerify(pub=group_public_key, msg=parent_root, sig=block.aggregate_signature, domain=get_domain(state, slot, SHARD_ATTESTER_DOMAIN))` passes. +* Let `group_public_key = bls_aggregate_pubkeys([state.validators[index].pubkey for i, index in enumerate(persistent_committee) if get_bitfield_bit(participation_bitfield, i) is True])`. Verify that `bls_verify(pubkey=group_public_key, msg=parent_root, sig=block.aggregate_signature, domain=get_domain(state, slot, SHARD_ATTESTER_DOMAIN))` passes. -### Block Merklization helper +We define the helper `get_proposal_committee` as follows: ```python -def merkle_root(block_body): - assert len(block_body) == SHARD_BLOCK_SIZE - chunks = SHARD_BLOCK_SIZE // SHARD_CHUNK_SIZE - o = [0] * chunks + [block_body[i * SHARD_CHUNK_SIZE: (i+1) * SHARD_CHUNK_SIZE] for i in range(chunks)] - for i in range(chunks-1, 0, -1): - o[i] = hash(o[i*2] + o[i*2+1]) - return o[1] +def get_proposal_committee(seed: Bytes32, + validators: List[Validator], + shard: int, + epoch: EpochNumber) -> List[ValidatorIndex]: + + earlier_committee_start = epoch - (epoch % PROPOSAL_RESHUFFLE_PERIOD) - PROPOSAL_RESHUFFLE_PERIOD * 2 + earlier_committee = split(shuffle( + get_active_validator_indices(validators, earlier_committee_start), + generate_seed(state, earlier_committee_start) + ), SHARD_COUNT)[shard] + + later_committee_start = epoch - (epoch % PROPOSAL_RESHUFFLE_PERIOD) - PROPOSAL_RESHUFFLE_PERIOD + later_committee = split(shuffle( + get_active_validator_indices(validators, earlier_committee_start), + generate_seed(state, earlier_committee_start) + ), SHARD_COUNT)[shard] + + def get_switchover_epoch(index): + return ( + int.from_bytes(hash(generate_seed(state, earlier_committee_start) + bytes3(index)), 'little') % + PROPOSAL_RESHUFFLE_PERIOD + ) + + return ( + [i for i in earlier_committee if epoch % PROPOSAL_RESHUFFLE_PERIOD < get_switchover_epoch(i)] + + [i for i in later_committee if epoch % PROPOSAL_RESHUFFLE_PERIOD >= get_switchover_epoch(i)] + ) ``` ### Verifying shard block data From fb90fd7ac3b1accd9dc680439260dd25d59414c8 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 8 Feb 2019 01:07:31 -0600 Subject: [PATCH 02/22] Update specs/core/1_shard-data-chains.md Co-Authored-By: vbuterin --- specs/core/1_shard-data-chains.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/core/1_shard-data-chains.md b/specs/core/1_shard-data-chains.md index f3324bbbd..f25844ecb 100644 --- a/specs/core/1_shard-data-chains.md +++ b/specs/core/1_shard-data-chains.md @@ -71,7 +71,7 @@ To validate a block header on shard `shard_id`, compute as follows: * Let `state` be the state of the beacon chain block referred to by `beacon_chain_ref`. Let `persistent_committee` be `[persistent_committee[i] for i in get_persistent_committee(state, slot, shard_id)`. * Assert `verify_bitfield(participation_bitfield, len(persistent_committee))` * Let `proposer_index = hash(state.randao_mix + int_to_bytes8(shard_id) + int_to_bytes8(slot)) % len(validators)`. Let `msg` be the block but with the `block.signature` set to `[0, 0]`. Verify that `BLSVerify(pub=validators[proposer_index].pubkey, msg=hash(msg), sig=block.signature, domain=get_domain(state, slot, SHARD_PROPOSER_DOMAIN))` passes. -* Let `group_public_key = bls_aggregate_pubkeys([state.validators[index].pubkey for i, index in enumerate(persistent_committee) if get_bitfield_bit(participation_bitfield, i) is True])`. Verify that `bls_verify(pubkey=group_public_key, msg=parent_root, sig=block.aggregate_signature, domain=get_domain(state, slot, SHARD_ATTESTER_DOMAIN))` passes. +* Let `group_public_key = bls_aggregate_pubkeys([state.validators[index].pubkey for i, index in enumerate(persistent_committee) if get_bitfield_bit(participation_bitfield, i) is True])`. Verify that `bls_verify(pubkey=group_public_key, message_hash=parent_root, sig=block.aggregate_signature, domain=get_domain(state, slot, SHARD_ATTESTER_DOMAIN))` passes. We define the helper `get_proposal_committee` as follows: From a1f542b6743bba384763cb0b76a67d2e919ed4e6 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 8 Feb 2019 01:07:46 -0600 Subject: [PATCH 03/22] Update specs/core/1_shard-data-chains.md Co-Authored-By: vbuterin --- specs/core/1_shard-data-chains.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/core/1_shard-data-chains.md b/specs/core/1_shard-data-chains.md index f25844ecb..a401c87c3 100644 --- a/specs/core/1_shard-data-chains.md +++ b/specs/core/1_shard-data-chains.md @@ -78,7 +78,7 @@ We define the helper `get_proposal_committee` as follows: ```python def get_proposal_committee(seed: Bytes32, validators: List[Validator], - shard: int, + shard: ShardNumber, epoch: EpochNumber) -> List[ValidatorIndex]: earlier_committee_start = epoch - (epoch % PROPOSAL_RESHUFFLE_PERIOD) - PROPOSAL_RESHUFFLE_PERIOD * 2 From bdd7dc106af7e541da4f257d5233495f074aaff6 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 8 Feb 2019 01:08:01 -0600 Subject: [PATCH 04/22] Update specs/core/1_shard-data-chains.md Co-Authored-By: vbuterin --- specs/core/1_shard-data-chains.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/core/1_shard-data-chains.md b/specs/core/1_shard-data-chains.md index a401c87c3..cb262a1ee 100644 --- a/specs/core/1_shard-data-chains.md +++ b/specs/core/1_shard-data-chains.md @@ -90,7 +90,7 @@ def get_proposal_committee(seed: Bytes32, later_committee_start = epoch - (epoch % PROPOSAL_RESHUFFLE_PERIOD) - PROPOSAL_RESHUFFLE_PERIOD later_committee = split(shuffle( get_active_validator_indices(validators, earlier_committee_start), - generate_seed(state, earlier_committee_start) + generate_seed(state, later_committee_start) ), SHARD_COUNT)[shard] def get_switchover_epoch(index): From 5e84d7e3ffd411e31f284989393085b20941a1b4 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 8 Feb 2019 01:08:15 -0600 Subject: [PATCH 05/22] Update specs/core/1_shard-data-chains.md Co-Authored-By: vbuterin --- specs/core/1_shard-data-chains.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/core/1_shard-data-chains.md b/specs/core/1_shard-data-chains.md index cb262a1ee..2984b3fb7 100644 --- a/specs/core/1_shard-data-chains.md +++ b/specs/core/1_shard-data-chains.md @@ -95,7 +95,7 @@ def get_proposal_committee(seed: Bytes32, def get_switchover_epoch(index): return ( - int.from_bytes(hash(generate_seed(state, earlier_committee_start) + bytes3(index)), 'little') % + bytes_to_int(hash(generate_seed(state, earlier_committee_start) + bytes3(index))[0:8]) % PROPOSAL_RESHUFFLE_PERIOD ) From 5a1b2c29f262460c10bee8f2658294ddc2015326 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 8 Feb 2019 01:08:30 -0600 Subject: [PATCH 06/22] Update specs/core/1_shard-data-chains.md Co-Authored-By: vbuterin --- specs/core/1_shard-data-chains.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/core/1_shard-data-chains.md b/specs/core/1_shard-data-chains.md index 2984b3fb7..af49825bd 100644 --- a/specs/core/1_shard-data-chains.md +++ b/specs/core/1_shard-data-chains.md @@ -89,7 +89,7 @@ def get_proposal_committee(seed: Bytes32, later_committee_start = epoch - (epoch % PROPOSAL_RESHUFFLE_PERIOD) - PROPOSAL_RESHUFFLE_PERIOD later_committee = split(shuffle( - get_active_validator_indices(validators, earlier_committee_start), + get_active_validator_indices(validators, later_committee_start), generate_seed(state, later_committee_start) ), SHARD_COUNT)[shard] From 2cff0e6b7a3f3437bc040f1fd023385a6c1a743c Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 8 Feb 2019 16:46:50 +0800 Subject: [PATCH 07/22] Use the new `bytesN` SSZ object `hash32` -> `bytes32` ['uint384'] -> `bytes96` --- specs/core/1_shard-data-chains.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/specs/core/1_shard-data-chains.md b/specs/core/1_shard-data-chains.md index af49825bd..0af79235e 100644 --- a/specs/core/1_shard-data-chains.md +++ b/specs/core/1_shard-data-chains.md @@ -16,11 +16,11 @@ Ethereum 2.0 consists of a central beacon chain along with `SHARD_COUNT` shard c Phase 1 depends upon all of the constants defined in [Phase 0](0_beacon-chain.md#constants) in addition to the following: -| Constant | Value | Unit | Approximation | -|-----------------------------|-----------------|--------|---------------| -| `SHARD_CHUNK_SIZE` | 2**5 (= 32) | bytes | | -| `SHARD_BLOCK_SIZE` | 2**14 (= 16384) | bytes | | -| `PROPOSAL_RESHUFFLE_PERIOD` | 2**11 (= 2048) | epochs | 9 days | +| Constant | Value | Unit | Approximation | +|-----------------------------|------------------|--------|---------------| +| `SHARD_CHUNK_SIZE` | 2**5 (= 32) | bytes | | +| `SHARD_BLOCK_SIZE` | 2**14 (= 16,384) | bytes | | +| `PROPOSAL_RESHUFFLE_PERIOD` | 2**11 (= 2,048) | epochs | 9 days | ### Flags, domains, etc. @@ -42,18 +42,18 @@ A `ShardBlock` object has the following fields: # What shard is it on 'shard_id': 'uint64', # Parent block's root - 'parent_root': 'hash32', + 'parent_root': 'bytes32', # Beacon chain block - 'beacon_chain_ref': 'hash32', + 'beacon_chain_ref': 'bytes32', # Merkle root of data - 'data_root': 'hash32' + 'data_root': 'bytes32' # State root (placeholder for now) - 'state_root': 'hash32', + 'state_root': 'bytes32', # Block signature - 'signature': ['uint384'], + 'signature': 'bytes96', # Attestation 'participation_bitfield': 'bytes', - 'aggregate_signature': ['uint384'], + 'aggregate_signature': 'bytes96', } ``` From 410372ff0ed909f7b5a1063a74f2eee70343cea4 Mon Sep 17 00:00:00 2001 From: vbuterin Date: Fri, 8 Feb 2019 03:48:58 -0600 Subject: [PATCH 08/22] Proposal committee -> persistent committee --- specs/core/1_shard-data-chains.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/specs/core/1_shard-data-chains.md b/specs/core/1_shard-data-chains.md index 0af79235e..1224449e3 100644 --- a/specs/core/1_shard-data-chains.md +++ b/specs/core/1_shard-data-chains.md @@ -16,11 +16,11 @@ Ethereum 2.0 consists of a central beacon chain along with `SHARD_COUNT` shard c Phase 1 depends upon all of the constants defined in [Phase 0](0_beacon-chain.md#constants) in addition to the following: -| Constant | Value | Unit | Approximation | -|-----------------------------|------------------|--------|---------------| -| `SHARD_CHUNK_SIZE` | 2**5 (= 32) | bytes | | -| `SHARD_BLOCK_SIZE` | 2**14 (= 16,384) | bytes | | -| `PROPOSAL_RESHUFFLE_PERIOD` | 2**11 (= 2,048) | epochs | 9 days | +| Constant | Value | Unit | Approximation | +|-------------------------------|------------------|--------|---------------| +| `SHARD_CHUNK_SIZE` | 2**5 (= 32) | bytes | | +| `SHARD_BLOCK_SIZE` | 2**14 (= 16,384) | bytes | | +| `PERSISTENT_COMMITTEE_PERIOD` | 2**11 (= 2,048) | epochs | 9 days | ### Flags, domains, etc. @@ -73,21 +73,21 @@ To validate a block header on shard `shard_id`, compute as follows: * Let `proposer_index = hash(state.randao_mix + int_to_bytes8(shard_id) + int_to_bytes8(slot)) % len(validators)`. Let `msg` be the block but with the `block.signature` set to `[0, 0]`. Verify that `BLSVerify(pub=validators[proposer_index].pubkey, msg=hash(msg), sig=block.signature, domain=get_domain(state, slot, SHARD_PROPOSER_DOMAIN))` passes. * Let `group_public_key = bls_aggregate_pubkeys([state.validators[index].pubkey for i, index in enumerate(persistent_committee) if get_bitfield_bit(participation_bitfield, i) is True])`. Verify that `bls_verify(pubkey=group_public_key, message_hash=parent_root, sig=block.aggregate_signature, domain=get_domain(state, slot, SHARD_ATTESTER_DOMAIN))` passes. -We define the helper `get_proposal_committee` as follows: +We define the helper `get_persistent_committee` as follows: ```python -def get_proposal_committee(seed: Bytes32, - validators: List[Validator], - shard: ShardNumber, - epoch: EpochNumber) -> List[ValidatorIndex]: +def get_persistent_commmitee(seed: Bytes32, + validators: List[Validator], + shard: ShardNumber, + epoch: EpochNumber) -> List[ValidatorIndex]: - earlier_committee_start = epoch - (epoch % PROPOSAL_RESHUFFLE_PERIOD) - PROPOSAL_RESHUFFLE_PERIOD * 2 + earlier_committee_start = epoch - (epoch % PERSISTENT_COMMITTEE_PERIOD) - PERSISTENT_COMMITTEE_PERIOD * 2 earlier_committee = split(shuffle( get_active_validator_indices(validators, earlier_committee_start), generate_seed(state, earlier_committee_start) ), SHARD_COUNT)[shard] - later_committee_start = epoch - (epoch % PROPOSAL_RESHUFFLE_PERIOD) - PROPOSAL_RESHUFFLE_PERIOD + later_committee_start = epoch - (epoch % PERSISTENT_COMMITTEE_PERIOD) - PERSISTENT_COMMITTEE_PERIOD later_committee = split(shuffle( get_active_validator_indices(validators, later_committee_start), generate_seed(state, later_committee_start) @@ -96,12 +96,12 @@ def get_proposal_committee(seed: Bytes32, def get_switchover_epoch(index): return ( bytes_to_int(hash(generate_seed(state, earlier_committee_start) + bytes3(index))[0:8]) % - PROPOSAL_RESHUFFLE_PERIOD + PERSISTENT_COMMITTEE_PERIOD ) return ( - [i for i in earlier_committee if epoch % PROPOSAL_RESHUFFLE_PERIOD < get_switchover_epoch(i)] + - [i for i in later_committee if epoch % PROPOSAL_RESHUFFLE_PERIOD >= get_switchover_epoch(i)] + [i for i in earlier_committee if epoch % PERSISTENT_COMMITTEE_PERIOD < get_switchover_epoch(i)] + + [i for i in later_committee if epoch % PERSISTENT_COMMITTEE_PERIOD >= get_switchover_epoch(i)] ) ``` From 47c396f3f8839644db5337922c1d31468d3cba6c Mon Sep 17 00:00:00 2001 From: vbuterin Date: Fri, 8 Feb 2019 03:50:00 -0600 Subject: [PATCH 09/22] Break lets into separate lines --- specs/core/1_shard-data-chains.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/specs/core/1_shard-data-chains.md b/specs/core/1_shard-data-chains.md index 1224449e3..3fa49697c 100644 --- a/specs/core/1_shard-data-chains.md +++ b/specs/core/1_shard-data-chains.md @@ -68,7 +68,8 @@ To validate a block header on shard `shard_id`, compute as follows: * Verify that `beacon_chain_ref` is the hash of a block in the (canonical) beacon chain with slot less than or equal to `slot`. * Verify that `beacon_chain_ref` is equal to or a descendant of the `beacon_chain_ref` specified in the `ShardBlock` pointed to by `parent_root`. -* Let `state` be the state of the beacon chain block referred to by `beacon_chain_ref`. Let `persistent_committee` be `[persistent_committee[i] for i in get_persistent_committee(state, slot, shard_id)`. +* Let `state` be the state of the beacon chain block referred to by `beacon_chain_ref`. +* Let `persistent_committee` be `[persistent_committee[i] for i in get_persistent_committee(state, slot, shard_id)`. * Assert `verify_bitfield(participation_bitfield, len(persistent_committee))` * Let `proposer_index = hash(state.randao_mix + int_to_bytes8(shard_id) + int_to_bytes8(slot)) % len(validators)`. Let `msg` be the block but with the `block.signature` set to `[0, 0]`. Verify that `BLSVerify(pub=validators[proposer_index].pubkey, msg=hash(msg), sig=block.signature, domain=get_domain(state, slot, SHARD_PROPOSER_DOMAIN))` passes. * Let `group_public_key = bls_aggregate_pubkeys([state.validators[index].pubkey for i, index in enumerate(persistent_committee) if get_bitfield_bit(participation_bitfield, i) is True])`. Verify that `bls_verify(pubkey=group_public_key, message_hash=parent_root, sig=block.aggregate_signature, domain=get_domain(state, slot, SHARD_ATTESTER_DOMAIN))` passes. From 65ec418213c025d64d0d498dab964950dedf4fba Mon Sep 17 00:00:00 2001 From: vbuterin Date: Fri, 8 Feb 2019 03:54:02 -0600 Subject: [PATCH 10/22] A few more cleanups --- specs/core/1_shard-data-chains.md | 93 ++++++++++++++++--------------- 1 file changed, 48 insertions(+), 45 deletions(-) diff --git a/specs/core/1_shard-data-chains.md b/specs/core/1_shard-data-chains.md index 3fa49697c..8b6d4ad5f 100644 --- a/specs/core/1_shard-data-chains.md +++ b/specs/core/1_shard-data-chains.md @@ -29,52 +29,9 @@ Phase 1 depends upon all of the constants defined in [Phase 0](0_beacon-chain.md | `SHARD_PROPOSER_DOMAIN`| 129 | | `SHARD_ATTESTER_DOMAIN`| 130 | -## Data Structures +## Helper functions -### Shard chain blocks - -A `ShardBlock` object has the following fields: - -```python -{ - # Slot number - 'slot': 'uint64', - # What shard is it on - 'shard_id': 'uint64', - # Parent block's root - 'parent_root': 'bytes32', - # Beacon chain block - 'beacon_chain_ref': 'bytes32', - # Merkle root of data - 'data_root': 'bytes32' - # State root (placeholder for now) - 'state_root': 'bytes32', - # Block signature - 'signature': 'bytes96', - # Attestation - 'participation_bitfield': 'bytes', - 'aggregate_signature': 'bytes96', -} -``` - -## Shard block processing - -For a block on a shard to be processed by a node, the following conditions must be met: - -* The `ShardBlock` pointed to by `parent_root` has already been processed and accepted -* The signature for the block from the _proposer_ (see below for definition) of that block is included along with the block in the network message object - -To validate a block header on shard `shard_id`, compute as follows: - -* Verify that `beacon_chain_ref` is the hash of a block in the (canonical) beacon chain with slot less than or equal to `slot`. -* Verify that `beacon_chain_ref` is equal to or a descendant of the `beacon_chain_ref` specified in the `ShardBlock` pointed to by `parent_root`. -* Let `state` be the state of the beacon chain block referred to by `beacon_chain_ref`. -* Let `persistent_committee` be `[persistent_committee[i] for i in get_persistent_committee(state, slot, shard_id)`. -* Assert `verify_bitfield(participation_bitfield, len(persistent_committee))` -* Let `proposer_index = hash(state.randao_mix + int_to_bytes8(shard_id) + int_to_bytes8(slot)) % len(validators)`. Let `msg` be the block but with the `block.signature` set to `[0, 0]`. Verify that `BLSVerify(pub=validators[proposer_index].pubkey, msg=hash(msg), sig=block.signature, domain=get_domain(state, slot, SHARD_PROPOSER_DOMAIN))` passes. -* Let `group_public_key = bls_aggregate_pubkeys([state.validators[index].pubkey for i, index in enumerate(persistent_committee) if get_bitfield_bit(participation_bitfield, i) is True])`. Verify that `bls_verify(pubkey=group_public_key, message_hash=parent_root, sig=block.aggregate_signature, domain=get_domain(state, slot, SHARD_ATTESTER_DOMAIN))` passes. - -We define the helper `get_persistent_committee` as follows: +#### get_persistent_committee ```python def get_persistent_commmitee(seed: Bytes32, @@ -106,6 +63,52 @@ def get_persistent_commmitee(seed: Bytes32, ) ``` +## Data Structures + +### Shard chain blocks + +A `ShardBlock` object has the following fields: + +```python +{ + # Slot number + 'slot': 'uint64', + # What shard is it on + 'shard_id': 'uint64', + # Parent block's root + 'parent_root': 'bytes32', + # Beacon chain block + 'beacon_chain_ref': 'bytes32', + # Merkle root of data + 'data_root': 'bytes32' + # State root (placeholder for now) + 'state_root': 'bytes32', + # Block signature + 'signature': 'bytes96', + # Attestation + 'participation_bitfield': 'bytes', + 'aggregate_signature': 'bytes96', +} +``` + +## Shard block processing + +For a `shard_block` on a shard to be processed by a node, the following conditions must be met: + +* The `ShardBlock` pointed to by `shard_block.parent_root` has already been processed and accepted +* The signature for the block from the _proposer_ (see below for definition) of that block is included along with the block in the network message object + +To validate a block header on shard `shard_block.shard_id`, compute as follows: + +* Verify that `shard_block.beacon_chain_ref` is the hash of a block in the (canonical) beacon chain with slot less than or equal to `slot`. +* Verify that `shard_block.beacon_chain_ref` is equal to or a descendant of the `shard_block.beacon_chain_ref` specified in the `ShardBlock` pointed to by `shard_block.parent_root`. +* Let `state` be the state of the beacon chain block referred to by `shard_block.beacon_chain_ref`. +* Let `persistent_committee` be `[persistent_committee[i] for i in get_persistent_committee(state, shard_block.slot, shard_block.shard_id)`. +* Assert `verify_bitfield(shard_block.participation_bitfield, len(persistent_committee))` +* Let `proposer_index = hash(state.randao_mix + int_to_bytes8(shard_block.shard_id) + int_to_bytes8(shard_block.slot)) % len(validators)`. Let `msg` be the `shard_block` but with `shard_block.signature` set to `[0, 0]`. Verify that `bls_verify(pubkey=validators[proposer_index].pubkey, message_hash=hash(msg), signature=shard_block.signature, domain=get_domain(state, shard_block.slot, SHARD_PROPOSER_DOMAIN))` passes. +* Let `group_public_key = bls_aggregate_pubkeys([state.validators[index].pubkey for i, index in enumerate(persistent_committee) if get_bitfield_bit(shard_block.participation_bitfield, i) is True])`. Verify that `bls_verify(pubkey=group_public_key, message_hash=shard_block.parent_root, sig=shard_block.aggregate_signature, domain=get_domain(state, slot, SHARD_ATTESTER_DOMAIN))` passes. + + ### Verifying shard block data At network layer, we expect a shard block header to be broadcast along with its `block_body`. From e5bd78e5e659208f89bce16c9a0aa4f82cd03fae Mon Sep 17 00:00:00 2001 From: vbuterin Date: Fri, 8 Feb 2019 04:08:52 -0600 Subject: [PATCH 11/22] Persistent committee refactors --- specs/core/1_shard-data-chains.md | 38 +++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/specs/core/1_shard-data-chains.md b/specs/core/1_shard-data-chains.md index 8b6d4ad5f..b4bbf3a7e 100644 --- a/specs/core/1_shard-data-chains.md +++ b/specs/core/1_shard-data-chains.md @@ -31,6 +31,17 @@ Phase 1 depends upon all of the constants defined in [Phase 0](0_beacon-chain.md ## Helper functions +#### get_split_offset + +````python +def get_split_offset(list_size: int, chunks: int, index: int) -> int: + """ + Returns a value such that for a list L, chunk count k and index i, + split(L, k)[i] == L[get_split_offset(len(L), k, i): get_split_offset(len(L), k+1, i)] + """ + return (len(list_size) * index) // chunks +```` + #### get_persistent_committee ```python @@ -40,20 +51,28 @@ def get_persistent_commmitee(seed: Bytes32, epoch: EpochNumber) -> List[ValidatorIndex]: earlier_committee_start = epoch - (epoch % PERSISTENT_COMMITTEE_PERIOD) - PERSISTENT_COMMITTEE_PERIOD * 2 - earlier_committee = split(shuffle( - get_active_validator_indices(validators, earlier_committee_start), - generate_seed(state, earlier_committee_start) - ), SHARD_COUNT)[shard] + earlier_validator_set = get_active_validator_indices(validators, earlier_committee_start) + earlier_seed = generate_seed(state, earlier_committee_start) + earlier_start_offset = get_split_offset(len(earlier_validator_set), SHARD_COUNT, shard) + earlier_end_offset = get_split_offset(len(earlier_validator_set), SHARD_COUNT, shard+1) + earlier_committee = [ + earlier_validator_set[get_permuted_index(i, len(earlier_validator_set), earlier_seed)] + for i in range(earlier_start_offset, earlier_end_offset) + ] later_committee_start = epoch - (epoch % PERSISTENT_COMMITTEE_PERIOD) - PERSISTENT_COMMITTEE_PERIOD - later_committee = split(shuffle( - get_active_validator_indices(validators, later_committee_start), - generate_seed(state, later_committee_start) - ), SHARD_COUNT)[shard] + later_validator_set = get_active_validator_indices(validators, later_committee_start) + later_seed = generate_seed(state, later_committee_start) + later_start_offset = get_split_offset(len(later_validator_set), SHARD_COUNT, shard) + later_end_offset = get_split_offset(len(later_validator_set), SHARD_COUNT, shard+1) + later_committee = [ + later_validator_set[get_permuted_index(i, len(later_validator_set), later_seed)] + for i in range(later_start_offset, later_end_offset) + ] def get_switchover_epoch(index): return ( - bytes_to_int(hash(generate_seed(state, earlier_committee_start) + bytes3(index))[0:8]) % + bytes_to_int(hash(earlier_seed + bytes3(index))[0:8]) % PERSISTENT_COMMITTEE_PERIOD ) @@ -108,7 +127,6 @@ To validate a block header on shard `shard_block.shard_id`, compute as follows: * Let `proposer_index = hash(state.randao_mix + int_to_bytes8(shard_block.shard_id) + int_to_bytes8(shard_block.slot)) % len(validators)`. Let `msg` be the `shard_block` but with `shard_block.signature` set to `[0, 0]`. Verify that `bls_verify(pubkey=validators[proposer_index].pubkey, message_hash=hash(msg), signature=shard_block.signature, domain=get_domain(state, shard_block.slot, SHARD_PROPOSER_DOMAIN))` passes. * Let `group_public_key = bls_aggregate_pubkeys([state.validators[index].pubkey for i, index in enumerate(persistent_committee) if get_bitfield_bit(shard_block.participation_bitfield, i) is True])`. Verify that `bls_verify(pubkey=group_public_key, message_hash=shard_block.parent_root, sig=shard_block.aggregate_signature, domain=get_domain(state, slot, SHARD_ATTESTER_DOMAIN))` passes. - ### Verifying shard block data At network layer, we expect a shard block header to be broadcast along with its `block_body`. From ad0ff80be2b0f3682abf4134bc1660a566790c46 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 8 Feb 2019 22:06:03 -0600 Subject: [PATCH 12/22] Update specs/core/1_shard-data-chains.md Co-Authored-By: vbuterin --- specs/core/1_shard-data-chains.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/core/1_shard-data-chains.md b/specs/core/1_shard-data-chains.md index b4bbf3a7e..e910e24ac 100644 --- a/specs/core/1_shard-data-chains.md +++ b/specs/core/1_shard-data-chains.md @@ -122,7 +122,7 @@ To validate a block header on shard `shard_block.shard_id`, compute as follows: * Verify that `shard_block.beacon_chain_ref` is the hash of a block in the (canonical) beacon chain with slot less than or equal to `slot`. * Verify that `shard_block.beacon_chain_ref` is equal to or a descendant of the `shard_block.beacon_chain_ref` specified in the `ShardBlock` pointed to by `shard_block.parent_root`. * Let `state` be the state of the beacon chain block referred to by `shard_block.beacon_chain_ref`. -* Let `persistent_committee` be `[persistent_committee[i] for i in get_persistent_committee(state, shard_block.slot, shard_block.shard_id)`. +* Let `persistent_committee = get_persistent_committee(state, shard_block.slot, shard_block.shard_id)`. * Assert `verify_bitfield(shard_block.participation_bitfield, len(persistent_committee))` * Let `proposer_index = hash(state.randao_mix + int_to_bytes8(shard_block.shard_id) + int_to_bytes8(shard_block.slot)) % len(validators)`. Let `msg` be the `shard_block` but with `shard_block.signature` set to `[0, 0]`. Verify that `bls_verify(pubkey=validators[proposer_index].pubkey, message_hash=hash(msg), signature=shard_block.signature, domain=get_domain(state, shard_block.slot, SHARD_PROPOSER_DOMAIN))` passes. * Let `group_public_key = bls_aggregate_pubkeys([state.validators[index].pubkey for i, index in enumerate(persistent_committee) if get_bitfield_bit(shard_block.participation_bitfield, i) is True])`. Verify that `bls_verify(pubkey=group_public_key, message_hash=shard_block.parent_root, sig=shard_block.aggregate_signature, domain=get_domain(state, slot, SHARD_ATTESTER_DOMAIN))` passes. From 8dd111b7e62ba768c54d2af875dadb442303b103 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 8 Feb 2019 22:06:46 -0600 Subject: [PATCH 13/22] Update specs/core/1_shard-data-chains.md Co-Authored-By: vbuterin --- specs/core/1_shard-data-chains.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/core/1_shard-data-chains.md b/specs/core/1_shard-data-chains.md index e910e24ac..9362d537e 100644 --- a/specs/core/1_shard-data-chains.md +++ b/specs/core/1_shard-data-chains.md @@ -124,7 +124,7 @@ To validate a block header on shard `shard_block.shard_id`, compute as follows: * Let `state` be the state of the beacon chain block referred to by `shard_block.beacon_chain_ref`. * Let `persistent_committee = get_persistent_committee(state, shard_block.slot, shard_block.shard_id)`. * Assert `verify_bitfield(shard_block.participation_bitfield, len(persistent_committee))` -* Let `proposer_index = hash(state.randao_mix + int_to_bytes8(shard_block.shard_id) + int_to_bytes8(shard_block.slot)) % len(validators)`. Let `msg` be the `shard_block` but with `shard_block.signature` set to `[0, 0]`. Verify that `bls_verify(pubkey=validators[proposer_index].pubkey, message_hash=hash(msg), signature=shard_block.signature, domain=get_domain(state, shard_block.slot, SHARD_PROPOSER_DOMAIN))` passes. +* Let `proposer_index = bytes_to_int(hash(state.current_epoch_seed + int_to_bytes8(shard_block.shard_id) + int_to_bytes8(shard_block.slot))[0:8]) % len(validators)`. Let `msg` be the `shard_block` but with `shard_block.signature` set to `[0, 0]`. Verify that `bls_verify(pubkey=validators[proposer_index].pubkey, message_hash=hash(msg), signature=shard_block.signature, domain=get_domain(state, slot_to_epoch(shard_block.slot), SHARD_PROPOSER_DOMAIN))` passes. * Let `group_public_key = bls_aggregate_pubkeys([state.validators[index].pubkey for i, index in enumerate(persistent_committee) if get_bitfield_bit(shard_block.participation_bitfield, i) is True])`. Verify that `bls_verify(pubkey=group_public_key, message_hash=shard_block.parent_root, sig=shard_block.aggregate_signature, domain=get_domain(state, slot, SHARD_ATTESTER_DOMAIN))` passes. ### Verifying shard block data From e0d8cf42688b1011121cbc5f3b586e0513ab507c Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 8 Feb 2019 22:07:14 -0600 Subject: [PATCH 14/22] Update specs/core/1_shard-data-chains.md Co-Authored-By: vbuterin --- specs/core/1_shard-data-chains.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/core/1_shard-data-chains.md b/specs/core/1_shard-data-chains.md index 9362d537e..2752765c5 100644 --- a/specs/core/1_shard-data-chains.md +++ b/specs/core/1_shard-data-chains.md @@ -125,7 +125,7 @@ To validate a block header on shard `shard_block.shard_id`, compute as follows: * Let `persistent_committee = get_persistent_committee(state, shard_block.slot, shard_block.shard_id)`. * Assert `verify_bitfield(shard_block.participation_bitfield, len(persistent_committee))` * Let `proposer_index = bytes_to_int(hash(state.current_epoch_seed + int_to_bytes8(shard_block.shard_id) + int_to_bytes8(shard_block.slot))[0:8]) % len(validators)`. Let `msg` be the `shard_block` but with `shard_block.signature` set to `[0, 0]`. Verify that `bls_verify(pubkey=validators[proposer_index].pubkey, message_hash=hash(msg), signature=shard_block.signature, domain=get_domain(state, slot_to_epoch(shard_block.slot), SHARD_PROPOSER_DOMAIN))` passes. -* Let `group_public_key = bls_aggregate_pubkeys([state.validators[index].pubkey for i, index in enumerate(persistent_committee) if get_bitfield_bit(shard_block.participation_bitfield, i) is True])`. Verify that `bls_verify(pubkey=group_public_key, message_hash=shard_block.parent_root, sig=shard_block.aggregate_signature, domain=get_domain(state, slot, SHARD_ATTESTER_DOMAIN))` passes. +* Let `group_public_key = bls_aggregate_pubkeys([state.validators[index].pubkey for i, index in enumerate(persistent_committee) if get_bitfield_bit(shard_block.participation_bitfield, i) is True])`. Verify that `bls_verify(pubkey=group_public_key, message_hash=shard_block.parent_root, sig=shard_block.aggregate_signature, domain=get_domain(state, slot_to_epoch(shard_block.slot), SHARD_ATTESTER_DOMAIN))` passes. ### Verifying shard block data From 65c5a1a1b76d112e0d6ec2f7ac6fe1bf61ec6e27 Mon Sep 17 00:00:00 2001 From: vbuterin Date: Fri, 8 Feb 2019 22:10:54 -0600 Subject: [PATCH 15/22] Fixed get_persistent_committee --- specs/core/1_shard-data-chains.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/specs/core/1_shard-data-chains.md b/specs/core/1_shard-data-chains.md index 2752765c5..132a3b7bc 100644 --- a/specs/core/1_shard-data-chains.md +++ b/specs/core/1_shard-data-chains.md @@ -45,13 +45,15 @@ def get_split_offset(list_size: int, chunks: int, index: int) -> int: #### get_persistent_committee ```python -def get_persistent_commmitee(seed: Bytes32, - validators: List[Validator], - shard: ShardNumber, - epoch: EpochNumber) -> List[ValidatorIndex]: +def get_persistent_commmitee(state: BeaconState, + shard: ShardNumber, + epoch: EpochNumber) -> List[ValidatorIndex]: + """ + Returns the persistent committee for the given shard at the given epoch + """ earlier_committee_start = epoch - (epoch % PERSISTENT_COMMITTEE_PERIOD) - PERSISTENT_COMMITTEE_PERIOD * 2 - earlier_validator_set = get_active_validator_indices(validators, earlier_committee_start) + earlier_validator_set = get_active_validator_indices(state.validators, earlier_committee_start) earlier_seed = generate_seed(state, earlier_committee_start) earlier_start_offset = get_split_offset(len(earlier_validator_set), SHARD_COUNT, shard) earlier_end_offset = get_split_offset(len(earlier_validator_set), SHARD_COUNT, shard+1) @@ -61,7 +63,7 @@ def get_persistent_commmitee(seed: Bytes32, ] later_committee_start = epoch - (epoch % PERSISTENT_COMMITTEE_PERIOD) - PERSISTENT_COMMITTEE_PERIOD - later_validator_set = get_active_validator_indices(validators, later_committee_start) + later_validator_set = get_active_validator_indices(state.validators, later_committee_start) later_seed = generate_seed(state, later_committee_start) later_start_offset = get_split_offset(len(later_validator_set), SHARD_COUNT, shard) later_end_offset = get_split_offset(len(later_validator_set), SHARD_COUNT, shard+1) From 8097b2373b1d0462ddc02309ceff4a9db958d23d Mon Sep 17 00:00:00 2001 From: vbuterin Date: Sun, 10 Feb 2019 00:09:34 -0600 Subject: [PATCH 16/22] Added deduplication --- specs/core/1_shard-data-chains.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/specs/core/1_shard-data-chains.md b/specs/core/1_shard-data-chains.md index 132a3b7bc..5213f7da7 100644 --- a/specs/core/1_shard-data-chains.md +++ b/specs/core/1_shard-data-chains.md @@ -77,11 +77,13 @@ def get_persistent_commmitee(state: BeaconState, bytes_to_int(hash(earlier_seed + bytes3(index))[0:8]) % PERSISTENT_COMMITTEE_PERIOD ) - - return ( + + # Take not-yet-cycled-out validators from earlier committee and already-cycled-in validators from + # later committee; return a sorted list of the union of the two, deduplicated + return sorted(list(set( [i for i in earlier_committee if epoch % PERSISTENT_COMMITTEE_PERIOD < get_switchover_epoch(i)] + [i for i in later_committee if epoch % PERSISTENT_COMMITTEE_PERIOD >= get_switchover_epoch(i)] - ) + ))) ``` ## Data Structures From 046119fb2eb4252b4353edd95c70181fb40299e3 Mon Sep 17 00:00:00 2001 From: vbuterin Date: Sun, 10 Feb 2019 15:44:58 -0600 Subject: [PATCH 17/22] Update specs/core/1_shard-data-chains.md --- specs/core/1_shard-data-chains.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/specs/core/1_shard-data-chains.md b/specs/core/1_shard-data-chains.md index a4a67cd8b..c470395df 100644 --- a/specs/core/1_shard-data-chains.md +++ b/specs/core/1_shard-data-chains.md @@ -86,7 +86,27 @@ def get_persistent_commmitee(state: BeaconState, [i for i in later_committee if epoch % PERSISTENT_COMMITTEE_PERIOD >= get_switchover_epoch(i)] ))) ``` +#### get_shard_proposer_index +```python +def get_shard_proposer_index(state: BeaconState, + shard: ShardNumber, + slot: SlotNumber) -> ValidatorIndex: + seed = hash( + state.current_epoch_seed + + int_to_bytes8(shard) + + int_to_bytes8(slot) + ) + persistent_committee = get_persistent_committee(state, shard, slot_to_epoch(slot)) + # Default proposer + index = bytes_to_int(seed[0:8]) % len(persistent_committee) + # If default proposer exits, try the other proposers in order; if all are exited + # return None (ie. no block can be proposed) + validators_to_try = persistent_committee[index:] + persistent_committee[:index] + for index in validators_to_try: + if is_active_validator(state.validators[index], get_current_epoch(state)): + return index + return None ## Data Structures ### Shard chain blocks From ad3f43a4a6dfe472cc65fa9a2c5c934e18a45e24 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Sun, 10 Feb 2019 15:45:06 -0600 Subject: [PATCH 18/22] Update specs/core/1_shard-data-chains.md Co-Authored-By: vbuterin --- specs/core/1_shard-data-chains.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/core/1_shard-data-chains.md b/specs/core/1_shard-data-chains.md index c470395df..cbbd98048 100644 --- a/specs/core/1_shard-data-chains.md +++ b/specs/core/1_shard-data-chains.md @@ -147,7 +147,7 @@ To validate a block header on shard `shard_block.shard_id`, compute as follows: * Verify that `shard_block.beacon_chain_ref` is the hash of a block in the (canonical) beacon chain with slot less than or equal to `slot`. * Verify that `shard_block.beacon_chain_ref` is equal to or a descendant of the `shard_block.beacon_chain_ref` specified in the `ShardBlock` pointed to by `shard_block.parent_root`. * Let `state` be the state of the beacon chain block referred to by `shard_block.beacon_chain_ref`. -* Let `persistent_committee = get_persistent_committee(state, shard_block.slot, shard_block.shard_id)`. +* Let `persistent_committee = get_persistent_committee(state, shard_block.shard_id, slot_to_epoch(shard_block.slot))`. * Assert `verify_bitfield(shard_block.participation_bitfield, len(persistent_committee))` * Let `proposer_index = bytes_to_int(hash(state.current_epoch_seed + int_to_bytes8(shard_block.shard_id) + int_to_bytes8(shard_block.slot))[0:8]) % len(validators)`. Let `msg` be the `shard_block` but with `shard_block.signature` set to `[0, 0]`. Verify that `bls_verify(pubkey=validators[proposer_index].pubkey, message_hash=hash(msg), signature=shard_block.signature, domain=get_domain(state, slot_to_epoch(shard_block.slot), SHARD_PROPOSER_DOMAIN))` passes. * Let `group_public_key = bls_aggregate_pubkeys([state.validators[index].pubkey for i, index in enumerate(persistent_committee) if get_bitfield_bit(shard_block.participation_bitfield, i) is True])`. Verify that `bls_verify(pubkey=group_public_key, message_hash=shard_block.parent_root, sig=shard_block.aggregate_signature, domain=get_domain(state, slot_to_epoch(shard_block.slot), SHARD_ATTESTER_DOMAIN))` passes. From 9e66b069b223d714ca3e1da4c2f412f86d895367 Mon Sep 17 00:00:00 2001 From: vbuterin Date: Sun, 10 Feb 2019 15:45:16 -0600 Subject: [PATCH 19/22] Update specs/core/1_shard-data-chains.md --- specs/core/1_shard-data-chains.md | 1 + 1 file changed, 1 insertion(+) diff --git a/specs/core/1_shard-data-chains.md b/specs/core/1_shard-data-chains.md index cbbd98048..d07c6b1ed 100644 --- a/specs/core/1_shard-data-chains.md +++ b/specs/core/1_shard-data-chains.md @@ -149,6 +149,7 @@ To validate a block header on shard `shard_block.shard_id`, compute as follows: * Let `state` be the state of the beacon chain block referred to by `shard_block.beacon_chain_ref`. * Let `persistent_committee = get_persistent_committee(state, shard_block.shard_id, slot_to_epoch(shard_block.slot))`. * Assert `verify_bitfield(shard_block.participation_bitfield, len(persistent_committee))` +* For every `i in range(len(persistent_committee))` where `is_active_validator(state.validators[persistent_committee[i]], get_current_epoch(state))` returns `False`, verify that `get_bitfield_bit(shard_block.participation_bitfield, i) == 0` * Let `proposer_index = bytes_to_int(hash(state.current_epoch_seed + int_to_bytes8(shard_block.shard_id) + int_to_bytes8(shard_block.slot))[0:8]) % len(validators)`. Let `msg` be the `shard_block` but with `shard_block.signature` set to `[0, 0]`. Verify that `bls_verify(pubkey=validators[proposer_index].pubkey, message_hash=hash(msg), signature=shard_block.signature, domain=get_domain(state, slot_to_epoch(shard_block.slot), SHARD_PROPOSER_DOMAIN))` passes. * Let `group_public_key = bls_aggregate_pubkeys([state.validators[index].pubkey for i, index in enumerate(persistent_committee) if get_bitfield_bit(shard_block.participation_bitfield, i) is True])`. Verify that `bls_verify(pubkey=group_public_key, message_hash=shard_block.parent_root, sig=shard_block.aggregate_signature, domain=get_domain(state, slot_to_epoch(shard_block.slot), SHARD_ATTESTER_DOMAIN))` passes. From 9bba3362eb18c9bcaff8353c34e254df7c628007 Mon Sep 17 00:00:00 2001 From: vbuterin Date: Sun, 10 Feb 2019 15:45:47 -0600 Subject: [PATCH 20/22] Update specs/core/1_shard-data-chains.md --- specs/core/1_shard-data-chains.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/specs/core/1_shard-data-chains.md b/specs/core/1_shard-data-chains.md index d07c6b1ed..29d47dfed 100644 --- a/specs/core/1_shard-data-chains.md +++ b/specs/core/1_shard-data-chains.md @@ -150,7 +150,10 @@ To validate a block header on shard `shard_block.shard_id`, compute as follows: * Let `persistent_committee = get_persistent_committee(state, shard_block.shard_id, slot_to_epoch(shard_block.slot))`. * Assert `verify_bitfield(shard_block.participation_bitfield, len(persistent_committee))` * For every `i in range(len(persistent_committee))` where `is_active_validator(state.validators[persistent_committee[i]], get_current_epoch(state))` returns `False`, verify that `get_bitfield_bit(shard_block.participation_bitfield, i) == 0` -* Let `proposer_index = bytes_to_int(hash(state.current_epoch_seed + int_to_bytes8(shard_block.shard_id) + int_to_bytes8(shard_block.slot))[0:8]) % len(validators)`. Let `msg` be the `shard_block` but with `shard_block.signature` set to `[0, 0]`. Verify that `bls_verify(pubkey=validators[proposer_index].pubkey, message_hash=hash(msg), signature=shard_block.signature, domain=get_domain(state, slot_to_epoch(shard_block.slot), SHARD_PROPOSER_DOMAIN))` passes. +* Let `proposer_index = get_shard_proposer_index(state, shard_block.shard_id, shard_block.slot)`. +* Verify that `proposer_index` is not `None`. +* Let `msg` be the `shard_block` but with `shard_block.signature` set to `[0, 0]`. +* Verify that `bls_verify(pubkey=validators[proposer_index].pubkey, message_hash=hash(msg), signature=shard_block.signature, domain=get_domain(state, slot_to_epoch(shard_block.slot), SHARD_PROPOSER_DOMAIN))` passes. * Let `group_public_key = bls_aggregate_pubkeys([state.validators[index].pubkey for i, index in enumerate(persistent_committee) if get_bitfield_bit(shard_block.participation_bitfield, i) is True])`. Verify that `bls_verify(pubkey=group_public_key, message_hash=shard_block.parent_root, sig=shard_block.aggregate_signature, domain=get_domain(state, slot_to_epoch(shard_block.slot), SHARD_ATTESTER_DOMAIN))` passes. ### Verifying shard block data From ab44cbe380b57afaeb2121307cc4a83ae2f7b77c Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Sun, 10 Feb 2019 15:45:57 -0600 Subject: [PATCH 21/22] Update specs/core/1_shard-data-chains.md Co-Authored-By: vbuterin --- specs/core/1_shard-data-chains.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/specs/core/1_shard-data-chains.md b/specs/core/1_shard-data-chains.md index 29d47dfed..0c90e0028 100644 --- a/specs/core/1_shard-data-chains.md +++ b/specs/core/1_shard-data-chains.md @@ -154,7 +154,8 @@ To validate a block header on shard `shard_block.shard_id`, compute as follows: * Verify that `proposer_index` is not `None`. * Let `msg` be the `shard_block` but with `shard_block.signature` set to `[0, 0]`. * Verify that `bls_verify(pubkey=validators[proposer_index].pubkey, message_hash=hash(msg), signature=shard_block.signature, domain=get_domain(state, slot_to_epoch(shard_block.slot), SHARD_PROPOSER_DOMAIN))` passes. -* Let `group_public_key = bls_aggregate_pubkeys([state.validators[index].pubkey for i, index in enumerate(persistent_committee) if get_bitfield_bit(shard_block.participation_bitfield, i) is True])`. Verify that `bls_verify(pubkey=group_public_key, message_hash=shard_block.parent_root, sig=shard_block.aggregate_signature, domain=get_domain(state, slot_to_epoch(shard_block.slot), SHARD_ATTESTER_DOMAIN))` passes. +* Let `group_public_key = bls_aggregate_pubkeys([state.validators[index].pubkey for i, index in enumerate(persistent_committee) if get_bitfield_bit(shard_block.participation_bitfield, i) is True])`. +* Verify that `bls_verify(pubkey=group_public_key, message_hash=shard_block.parent_root, sig=shard_block.aggregate_signature, domain=get_domain(state, slot_to_epoch(shard_block.slot), SHARD_ATTESTER_DOMAIN))` passes. ### Verifying shard block data From db4f99d8992ab05236ba8ec35c23f5800ad677cf Mon Sep 17 00:00:00 2001 From: vbuterin Date: Sun, 10 Feb 2019 15:47:26 -0600 Subject: [PATCH 22/22] Fixed end of code block --- specs/core/1_shard-data-chains.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/specs/core/1_shard-data-chains.md b/specs/core/1_shard-data-chains.md index 0c90e0028..a4cf36134 100644 --- a/specs/core/1_shard-data-chains.md +++ b/specs/core/1_shard-data-chains.md @@ -107,6 +107,8 @@ def get_shard_proposer_index(state: BeaconState, if is_active_validator(state.validators[index], get_current_epoch(state)): return index return None +``` + ## Data Structures ### Shard chain blocks