From 6c824ffee462686787b27cb7ad11420513eccb32 Mon Sep 17 00:00:00 2001 From: Justin Date: Tue, 22 Jan 2019 20:45:30 +0000 Subject: [PATCH 01/19] Remove placeholders MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove all custody and VDF placeholders (56 lines less!). A few notes on the placeholder fields and logic: * All placeholder fields were dummy fields that can easily be restored in the phase 1 hard fork. * One special case to the above is `custody_bit_0_validator_indices` in `SlashableVoteData` which was renamed to `validator_indices`. Renaming it back is *not* a spec change because SSZ field names are [no longer part of the spec](https://github.com/ethereum/eth2.0-specs/commit/a9328157a87451ee4f372df272ece158b386ec41#diff-8d8fe480a35579c7be2f976d9b321216). * The placeholder logic was written using generalised functions (e.g. `bls_verify_multiple` vs `bls_verify`, and `indices(slashable_vote_data)` vs `slashable_vote_data.validator_indices`). This generality was unnecessary because it was not triggered when all custody bits were 0. This means we can simplify the logic without being inconsistent with phase 1. Rationale: * Keep phase 0 (likely far harder to deliver than phase 1) as clean as possible * Focus on upgrade paths and incremental releases * Custody is still under research—keep the design space open --- specs/core/0_beacon-chain.md | 76 +++++------------------------------- 1 file changed, 10 insertions(+), 66 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 56430cd56..a47cad399 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -30,7 +30,6 @@ - [Attestations](#attestations) - [`Attestation`](#attestation) - [`AttestationData`](#attestationdata) - - [`AttestationDataAndCustodyBit`](#attestationdataandcustodybit) - [Deposits](#deposits) - [`Deposit`](#deposit) - [`DepositData`](#depositdata) @@ -104,7 +103,6 @@ - [Attestations](#attestations-1) - [Deposits](#deposits-1) - [Exits](#exits-1) - - [Custody](#custody) - [Per-epoch processing](#per-epoch-processing) - [Helpers](#helpers) - [Eth1 data](#eth1-data-1) @@ -292,10 +290,8 @@ Code snippets appearing in `this style` are to be interpreted as Python code. Be ```python { - # Validator indices with custody bit equal to 0 - 'custody_bit_0_indices': ['uint24'], - # Validator indices with custody bit equal to 1 - 'custody_bit_1_indices': ['uint24'], + # Validator indices + 'validator_indices': ['uint24'], # Attestation data 'data': AttestationData, # Aggregate signature @@ -313,8 +309,6 @@ Code snippets appearing in `this style` are to be interpreted as Python code. Be 'data': AttestationData, # Attester aggregation bitfield 'aggregation_bitfield': 'bytes', - # Custody bitfield - 'custody_bitfield': 'bytes', # BLS aggregate signature 'aggregate_signature': 'bytes96', } @@ -343,17 +337,6 @@ Code snippets appearing in `this style` are to be interpreted as Python code. Be } ``` -##### `AttestationDataAndCustodyBit` - -```python -{ - # Attestation data - data: AttestationData, - # Custody bit - custody_bit: bool, -} -``` - #### Deposits ##### `Deposit` @@ -436,16 +419,11 @@ Code snippets appearing in `this style` are to be interpreted as Python code. Be 'proposer_slashings': [ProposerSlashing], 'casper_slashings': [CasperSlashing], 'attestations': [Attestation], - 'custody_reseeds': [CustodyReseed], - 'custody_challenges': [CustodyChallenge], - 'custody_responses': [CustodyResponse], 'deposits': [Deposit], 'exits': [Exit], } ``` -`CustodyReseed`, `CustodyChallenge`, and `CustodyResponse` will be defined in phase 1; for now, put dummy classes as these lists will remain empty throughout phase 0. - #### `ProposalSignedData` ```python @@ -479,7 +457,6 @@ Code snippets appearing in `this style` are to be interpreted as Python code. Be # Randomness and committees 'latest_randao_mixes': ['bytes32'], - 'latest_vdf_outputs': ['bytes32'], 'previous_epoch_start_shard': 'uint64', 'current_epoch_start_shard': 'uint64', 'previous_epoch_calculation_slot': 'uint64', @@ -487,9 +464,6 @@ Code snippets appearing in `this style` are to be interpreted as Python code. Be 'previous_epoch_randao_mix': 'bytes32', 'current_epoch_randao_mix': 'bytes32', - # Custody challenges - 'custody_challenges': [CustodyChallenge], - # Finality 'previous_justified_slot': 'uint64', 'justified_slot': 'uint64', @@ -531,10 +505,6 @@ Code snippets appearing in `this style` are to be interpreted as Python code. Be 'exit_count': 'uint64', # Status flags 'status_flags': 'uint64', - # Slot of latest custody reseed - 'latest_custody_reseed_slot': 'uint64', - # Slot of second-latest custody reseed - 'penultimate_custody_reseed_slot': 'uint64', } ``` @@ -557,8 +527,6 @@ Code snippets appearing in `this style` are to be interpreted as Python code. Be 'data': AttestationData, # Attester aggregation bitfield 'aggregation_bitfield': 'bytes', - # Custody bitfield - 'custody_bitfield': 'bytes', # Slot the attestation was included 'slot_included': 'uint64', } @@ -1092,24 +1060,14 @@ def get_domain(fork: Fork, ```python def verify_slashable_vote_data(state: BeaconState, vote_data: SlashableVoteData) -> bool: - if len(vote_data.custody_bit_0_indices) + len(vote_data.custody_bit_1_indices) > MAX_CASPER_VOTES: + if len(vote_data.validator_indices) > MAX_CASPER_VOTES: return False - return bls_verify_multiple( - pubkeys=[ - bls_aggregate_pubkeys([state.validator_registry[i].pubkey for i in vote_data.custody_bit_0_indices]), - bls_aggregate_pubkeys([state.validator_registry[i].pubkey for i in vote_data.custody_bit_1_indices]), - ], - messages=[ - hash_tree_root(AttestationDataAndCustodyBit(vote_data.data, False)), - hash_tree_root(AttestationDataAndCustodyBit(vote_data.data, True)), - ], + return bls_verify( + pubkey=bls_aggregate_pubkeys([state.validator_registry[i].pubkey for i in vote_data.validator_indices]), + message=hash_tree_root(AttestationData(vote_data.data)), signature=vote_data.aggregate_signature, - domain=get_domain( - state.fork, - vote_data.data.slot, - DOMAIN_ATTESTATION, - ), + domain=get_domain(state.fork, vote_data.data.slot, DOMAIN_ATTESTATION), ) ``` @@ -1198,9 +1156,6 @@ A valid block with slot `GENESIS_SLOT` (a "genesis block") has the following val proposer_slashings=[], casper_slashings=[], attestations=[], - custody_reseeds=[], - custody_challenges=[], - custody_responses=[], deposits=[], exits=[], ), @@ -1232,7 +1187,6 @@ def get_initial_beacon_state(initial_validator_deposits: List[Deposit], # Randomness and committees latest_randao_mixes=[ZERO_HASH for _ in range(LATEST_RANDAO_MIXES_LENGTH)], - latest_vdf_outputs=[ZERO_HASH for _ in range(LATEST_RANDAO_MIXES_LENGTH // EPOCH_LENGTH)], previous_epoch_start_shard=GENESIS_START_SHARD, current_epoch_start_shard=GENESIS_START_SHARD, previous_epoch_calculation_slot=GENESIS_SLOT, @@ -1240,9 +1194,6 @@ def get_initial_beacon_state(initial_validator_deposits: List[Deposit], previous_epoch_randao_mix=ZERO_HASH, current_epoch_randao_mix=ZERO_HASH, - # Custody challenges - custody_challenges=[], - # Finality previous_justified_slot=GENESIS_SLOT, justified_slot=GENESIS_SLOT, @@ -1340,8 +1291,6 @@ def process_deposit(state: BeaconState, penalized_slot=FAR_FUTURE_SLOT, exit_count=0, status_flags=0, - latest_custody_reseed_slot=GENESIS_SLOT, - penultimate_custody_reseed_slot=GENESIS_SLOT, ) # Note: In phase 2 registry indices that have been withdrawn for a long time will be recycled. @@ -1489,8 +1438,7 @@ For each `casper_slashing` in `block.body.casper_slashings`: * Let `slashable_vote_data_1 = casper_slashing.slashable_vote_data_1`. * Let `slashable_vote_data_2 = casper_slashing.slashable_vote_data_2`. -* Let `indices(slashable_vote_data) = slashable_vote_data.custody_bit_0_indices + slashable_vote_data.custody_bit_1_indices`. -* Let `intersection = [x for x in indices(slashable_vote_data_1) if x in indices(slashable_vote_data_2)]`. +* Let `intersection = [x for x in slashable_vote_data_1.validator_indices if x in slashable_vote_data_2.validator_indices]`. * Verify that `len(intersection) >= 1`. * Verify that `slashable_vote_data_1.data != slashable_vote_data_2.data`. * Verify that `is_double_vote(slashable_vote_data_1.data, slashable_vote_data_2.data)` or `is_surround_vote(slashable_vote_data_1.data, slashable_vote_data_2.data)`. @@ -1512,9 +1460,9 @@ For each `attestation` in `block.body.attestations`: * `aggregate_signature` verification: * Let `participants = get_attestation_participants(state, attestation.data, attestation.aggregation_bitfield)`. * Let `group_public_key = bls_aggregate_pubkeys([state.validator_registry[v].pubkey for v in participants])`. - * Verify that `bls_verify(pubkey=group_public_key, message=hash_tree_root(AttestationDataAndCustodyBit(attestation.data, False)), signature=attestation.aggregate_signature, domain=get_domain(state.fork, attestation.data.slot, DOMAIN_ATTESTATION))`. + * Verify that `bls_verify(pubkey=group_public_key, message=hash_tree_root(AttestationData(attestation.data)), signature=attestation.aggregate_signature, domain=get_domain(state.fork, attestation.data.slot, DOMAIN_ATTESTATION))`. * [TO BE REMOVED IN PHASE 1] Verify that `attestation.data.shard_block_root == ZERO_HASH`. -* Append `PendingAttestation(data=attestation.data, aggregation_bitfield=attestation.aggregation_bitfield, custody_bitfield=attestation.custody_bitfield, slot_included=state.slot)` to `state.latest_attestations`. +* Append `PendingAttestation(data=attestation.data, aggregation_bitfield=attestation.aggregation_bitfield, slot_included=state.slot)` to `state.latest_attestations`. #### Deposits @@ -1564,10 +1512,6 @@ For each `exit` in `block.body.exits`: * Verify that `bls_verify(pubkey=validator.pubkey, message=exit_message, signature=exit.signature, domain=get_domain(state.fork, exit.slot, DOMAIN_EXIT))`. * Run `initiate_validator_exit(state, exit.validator_index)`. -#### Custody - -[TO BE REMOVED IN PHASE 1] Verify that `len(block.body.custody_reseeds) == len(block.body.custody_challenges) == len(block.body.custody_responses) == 0`. - ## Per-epoch processing The steps below happen when `state.slot % EPOCH_LENGTH == 0`. From 109ac8969774188011a94ad2ed36e21687c59f09 Mon Sep 17 00:00:00 2001 From: Justin Date: Wed, 23 Jan 2019 09:57:48 +0000 Subject: [PATCH 02/19] Update 0_beacon-chain.md --- specs/core/0_beacon-chain.md | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index a47cad399..4d900cfe8 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -30,6 +30,7 @@ - [Attestations](#attestations) - [`Attestation`](#attestation) - [`AttestationData`](#attestationdata) + - [`AttestationDataWrapped`](#attestationdatawrapped) - [Deposits](#deposits) - [`Deposit`](#deposit) - [`DepositData`](#depositdata) @@ -290,12 +291,12 @@ Code snippets appearing in `this style` are to be interpreted as Python code. Be ```python { - # Validator indices - 'validator_indices': ['uint24'], # Attestation data 'data': AttestationData, # Aggregate signature 'aggregate_signature': 'bytes96', + # Validator indices + 'validator_indices': ['uint24'], } ``` @@ -337,6 +338,15 @@ Code snippets appearing in `this style` are to be interpreted as Python code. Be } ``` +#### `AttestationDataWrapped` + +```python +{ + # Attestation data + 'data': AttestationData, +} +``` + #### Deposits ##### `Deposit` @@ -1065,7 +1075,7 @@ def verify_slashable_vote_data(state: BeaconState, vote_data: SlashableVoteData) return bls_verify( pubkey=bls_aggregate_pubkeys([state.validator_registry[i].pubkey for i in vote_data.validator_indices]), - message=hash_tree_root(AttestationData(vote_data.data)), + message=hash_tree_root(AttestationDataWrapped(data=vote_data.data)), signature=vote_data.aggregate_signature, domain=get_domain(state.fork, vote_data.data.slot, DOMAIN_ATTESTATION), ) @@ -1460,7 +1470,7 @@ For each `attestation` in `block.body.attestations`: * `aggregate_signature` verification: * Let `participants = get_attestation_participants(state, attestation.data, attestation.aggregation_bitfield)`. * Let `group_public_key = bls_aggregate_pubkeys([state.validator_registry[v].pubkey for v in participants])`. - * Verify that `bls_verify(pubkey=group_public_key, message=hash_tree_root(AttestationData(attestation.data)), signature=attestation.aggregate_signature, domain=get_domain(state.fork, attestation.data.slot, DOMAIN_ATTESTATION))`. + * Verify that `bls_verify(pubkey=group_public_key, message=hash_tree_root(AttestationDataWrapped(data=attestation.data)), signature=attestation.aggregate_signature, domain=get_domain(state.fork, attestation.data.slot, DOMAIN_ATTESTATION))`. * [TO BE REMOVED IN PHASE 1] Verify that `attestation.data.shard_block_root == ZERO_HASH`. * Append `PendingAttestation(data=attestation.data, aggregation_bitfield=attestation.aggregation_bitfield, slot_included=state.slot)` to `state.latest_attestations`. From 696a6c140a23dc900cc31878c584daecd022488d Mon Sep 17 00:00:00 2001 From: Justin Date: Wed, 23 Jan 2019 12:40:59 +0000 Subject: [PATCH 03/19] Update 0_beacon-chain.md --- specs/core/0_beacon-chain.md | 121 +++++++++++++++++++++++++++++------ 1 file changed, 101 insertions(+), 20 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 4d900cfe8..865c4c175 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -30,7 +30,7 @@ - [Attestations](#attestations) - [`Attestation`](#attestation) - [`AttestationData`](#attestationdata) - - [`AttestationDataWrapped`](#attestationdatawrapped) + - [`AttestationDataAndCustodyBit`](#attestationdataandcustodybit) - [Deposits](#deposits) - [`Deposit`](#deposit) - [`DepositData`](#depositdata) @@ -80,10 +80,13 @@ - [`get_effective_balance`](#get_effective_balance) - [`get_fork_version`](#get_fork_version) - [`get_domain`](#get_domain) + - [`get_bitfield_bit`](#get_bitfield_bit) + - [`verify_bitfield`](#verify_bitfield) - [`verify_slashable_vote_data`](#verify_slashable_vote_data) - [`is_double_vote`](#is_double_vote) - [`is_surround_vote`](#is_surround_vote) - [`integer_squareroot`](#integer_squareroot) + - [`indices`](#indices) - [`bls_verify`](#bls_verify) - [`bls_verify_multiple`](#bls_verify_multiple) - [`bls_aggregate_pubkeys`](#bls_aggregate_pubkeys) @@ -251,6 +254,13 @@ Code snippets appearing in `this style` are to be interpreted as Python code. Be | `DOMAIN_EXIT` | `3` | | `DOMAIN_RANDAO` | `4` | +### Custody bits + +| Name | Value | +| - | - | +| `CUSTODY_BIT_ZERO` | `False` | +| `CUSTODY_BIT_ONE` | `True` | + ## Data structures ### Beacon chain operations @@ -291,12 +301,14 @@ Code snippets appearing in `this style` are to be interpreted as Python code. Be ```python { + # Validator indices with custody bit equal to 0 + 'custody_bit_0_indices': ['uint24'], + # Validator indices with custody bit equal to 1 + 'custody_bit_1_indices': ['uint24'], # Attestation data 'data': AttestationData, # Aggregate signature 'aggregate_signature': 'bytes96', - # Validator indices - 'validator_indices': ['uint24'], } ``` @@ -310,6 +322,8 @@ Code snippets appearing in `this style` are to be interpreted as Python code. Be 'data': AttestationData, # Attester aggregation bitfield 'aggregation_bitfield': 'bytes', + # Custody bitfield + 'custody_bitfield': 'bytes', # BLS aggregate signature 'aggregate_signature': 'bytes96', } @@ -338,12 +352,14 @@ Code snippets appearing in `this style` are to be interpreted as Python code. Be } ``` -#### `AttestationDataWrapped` +##### `AttestationDataAndCustodyBit` ```python { # Attestation data 'data': AttestationData, + # Custody bit + 'custody_bit': bool, } ``` @@ -537,6 +553,8 @@ Code snippets appearing in `this style` are to be interpreted as Python code. Be 'data': AttestationData, # Attester aggregation bitfield 'aggregation_bitfield': 'bytes', + # Custody bitfield + 'custody_bitfield': 'bytes', # Slot the attestation was included 'slot_included': 'uint64', } @@ -1008,22 +1026,20 @@ def merkle_root(values: List[Bytes32]) -> Bytes32: ```python def get_attestation_participants(state: BeaconState, attestation_data: AttestationData, - aggregation_bitfield: bytes) -> List[int]: + bitfield: bytes) -> List[int]: """ - Returns the participant indices at for the ``attestation_data`` and ``aggregation_bitfield``. + Returns the participant indices at for the ``attestation_data`` and ``bitfield``. """ - # Find the committee in the list with the desired shard crosslink_committees = get_crosslink_committees_at_slot(state, attestation_data.slot) assert attestation_data.shard in [shard for _, shard in crosslink_committees] crosslink_committee = [committee for committee, shard in crosslink_committees if shard == attestation_data.shard][0] - assert len(aggregation_bitfield) == (len(committee) + 7) // 8 # Find the participating attesters in the committee participants = [] for i, validator_index in enumerate(crosslink_committee): - aggregation_bit = (aggregation_bitfield[i // 8] >> (7 - (i % 8))) % 2 + aggregation_bit = get_bitfield_bit(bitfield, i) if aggregation_bit == 1: participants.append(validator_index) return participants @@ -1066,18 +1082,51 @@ def get_domain(fork: Fork, ) * 2**32 + domain_type ``` +#### `get_bitfield_bit` + +```python +def get_bitfield_bit(bitfield: bytes, i: int) -> int: + return (bitfield[i // 8] >> (7 - (i % 8))) % 2 +``` + +#### `verify_bitfield` + +```python +def verify_bitfield(bitfield: bytes, size: int) -> bool: + ``` + Verify ``bitfield`` against the ``size``. + if len(bitfield) != (size + 7) // 8: + return False + + for i in range(size + 1, size + size % 8 + 8): + if get_bitfield_bit(bitfield, i) != 0: + return False + + return True +``` + #### `verify_slashable_vote_data` ```python -def verify_slashable_vote_data(state: BeaconState, vote_data: SlashableVoteData) -> bool: - if len(vote_data.validator_indices) > MAX_CASPER_VOTES: +def verify_slashable_vote_data(state: BeaconState, slashable_vote_data: SlashableVoteData) -> bool: + # [TO BE REMOVED IN PHASE 1] + if len(slashable_vote_data.custody_bit_1_indices) > 0: + return False + + if len(indices(slashable_vote_data)) > MAX_CASPER_VOTES: return False return bls_verify( - pubkey=bls_aggregate_pubkeys([state.validator_registry[i].pubkey for i in vote_data.validator_indices]), - message=hash_tree_root(AttestationDataWrapped(data=vote_data.data)), - signature=vote_data.aggregate_signature, - domain=get_domain(state.fork, vote_data.data.slot, DOMAIN_ATTESTATION), + pubkeys=[ + bls_aggregate_pubkeys([state.validator_registry[i].pubkey for i in slashable_vote_data.custody_bit_0_indices]), + bls_aggregate_pubkeys([state.validator_registry[i].pubkey for i in slashable_vote_data.custody_bit_1_indices]), + ], + messages=[ + hash_tree_root(AttestationDataAndCustodyBit(slashable_vote_data.data, CUSTODY_BIT_ZERO)), + hash_tree_root(AttestationDataAndCustodyBit(slashable_vote_data.data, CUSTODY_BIT_ONE)), + ], + signature=slashable_vote_data.aggregate_signature, + domain=get_domain(state.fork, slashable_vote_data.data.slot, DOMAIN_ATTESTATION), ) ``` @@ -1135,6 +1184,16 @@ def integer_squareroot(n: int) -> int: return x ``` +#### `indices` + +```python +def indices(slashable_vote_data: SlashableVoteData) -> List[int]: + """ + Return all indicies in ``slashable_vote_data``. + """ + return slashable_vote_data.custody_bit_0_indices + slashable_vote_data.custody_bit_1_indices +``` + #### `bls_verify` `bls_verify` is a function for verifying a BLS signature, defined in the [BLS Signature spec](https://github.com/ethereum/eth2.0-specs/blob/master/specs/bls_signature.md#bls_verify). @@ -1448,7 +1507,7 @@ For each `casper_slashing` in `block.body.casper_slashings`: * Let `slashable_vote_data_1 = casper_slashing.slashable_vote_data_1`. * Let `slashable_vote_data_2 = casper_slashing.slashable_vote_data_2`. -* Let `intersection = [x for x in slashable_vote_data_1.validator_indices if x in slashable_vote_data_2.validator_indices]`. +* Let `intersection = [x for x in indices(slashable_vote_data_1) if x in indices(slashable_vote_data_2)]`. * Verify that `len(intersection) >= 1`. * Verify that `slashable_vote_data_1.data != slashable_vote_data_2.data`. * Verify that `is_double_vote(slashable_vote_data_1.data, slashable_vote_data_2.data)` or `is_surround_vote(slashable_vote_data_1.data, slashable_vote_data_2.data)`. @@ -1467,10 +1526,32 @@ For each `attestation` in `block.body.attestations`: * Verify that `attestation.data.justified_slot` is equal to `state.justified_slot if attestation.data.slot >= state.slot - (state.slot % EPOCH_LENGTH) else state.previous_justified_slot`. * Verify that `attestation.data.justified_block_root` is equal to `get_block_root(state, attestation.data.justified_slot)`. * Verify that either `attestation.data.latest_crosslink_root` or `attestation.data.shard_block_root` equals `state.latest_crosslinks[shard].shard_block_root`. -* `aggregate_signature` verification: - * Let `participants = get_attestation_participants(state, attestation.data, attestation.aggregation_bitfield)`. - * Let `group_public_key = bls_aggregate_pubkeys([state.validator_registry[v].pubkey for v in participants])`. - * Verify that `bls_verify(pubkey=group_public_key, message=hash_tree_root(AttestationDataWrapped(data=attestation.data)), signature=attestation.aggregate_signature, domain=get_domain(state.fork, attestation.data.slot, DOMAIN_ATTESTATION))`. +* `attestation.aggregate_signature` verification: + +```python + assert verify_bitfield(attestation.aggregation_bitfield) + assert verify_bitfield(attestation.custody_bitfield) + assert attestation.custody_bitfield & attestation.aggregation_bitfield == attestation.custody_bitfield + + participants = get_attestation_participants(state, attestation.data, attestation.aggregation_bitfield) + custody_bit_0_participants = get_attestation_participants(state, attestation.data, attestation.custody_bitfield) + custody_bit_1_participants = [i in participants for i not in custody_bit_0_participants] + + assert bls_verify_multiple( + pubkeys=[ + bls_aggregate_pubkeys([state.validator_registry[i].pubkey for i in custody_bit_0_participants]), + bls_aggregate_pubkeys([state.validator_registry[i].pubkey for i in custody_bit_1_participants]), + ], + messages=[ + hash_tree_root(AttestationDataAndCustodyBit(data=attestation.data, custody_bit=CUSTODY_BIT_ZERO)), + hash_tree_root(AttestationDataAndCustodyBit(data=attestation.data, custody_bit=CUSTODY_BIT_ONE)), + ], + signature=attestation.aggregate_signature, + domain=get_domain(state.fork, attestation.data.slot, DOMAIN_ATTESTATION), + ) + +``` + * [TO BE REMOVED IN PHASE 1] Verify that `attestation.data.shard_block_root == ZERO_HASH`. * Append `PendingAttestation(data=attestation.data, aggregation_bitfield=attestation.aggregation_bitfield, slot_included=state.slot)` to `state.latest_attestations`. From ee081e160ca93eddd3bab9c59ed2d6a6a5979fb2 Mon Sep 17 00:00:00 2001 From: Justin Date: Wed, 23 Jan 2019 12:47:11 +0000 Subject: [PATCH 04/19] Update 0_beacon-chain.md --- specs/core/0_beacon-chain.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 865c4c175..ecbcdebb1 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1526,13 +1526,17 @@ For each `attestation` in `block.body.attestations`: * Verify that `attestation.data.justified_slot` is equal to `state.justified_slot if attestation.data.slot >= state.slot - (state.slot % EPOCH_LENGTH) else state.previous_justified_slot`. * Verify that `attestation.data.justified_block_root` is equal to `get_block_root(state, attestation.data.justified_slot)`. * Verify that either `attestation.data.latest_crosslink_root` or `attestation.data.shard_block_root` equals `state.latest_crosslinks[shard].shard_block_root`. -* `attestation.aggregate_signature` verification: +* Verify bitfields: ```python assert verify_bitfield(attestation.aggregation_bitfield) assert verify_bitfield(attestation.custody_bitfield) assert attestation.custody_bitfield & attestation.aggregation_bitfield == attestation.custody_bitfield +``` +* Verify aggregate signature: + +```python participants = get_attestation_participants(state, attestation.data, attestation.aggregation_bitfield) custody_bit_0_participants = get_attestation_participants(state, attestation.data, attestation.custody_bitfield) custody_bit_1_participants = [i in participants for i not in custody_bit_0_participants] From ac85e06e81f0664a5177478a9f3d37efeb255004 Mon Sep 17 00:00:00 2001 From: Justin Date: Wed, 23 Jan 2019 12:48:54 +0000 Subject: [PATCH 05/19] Update 0_beacon-chain.md --- 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 ecbcdebb1..3a79ee71d 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1109,8 +1109,7 @@ def verify_bitfield(bitfield: bytes, size: int) -> bool: ```python def verify_slashable_vote_data(state: BeaconState, slashable_vote_data: SlashableVoteData) -> bool: - # [TO BE REMOVED IN PHASE 1] - if len(slashable_vote_data.custody_bit_1_indices) > 0: + if len(slashable_vote_data.custody_bit_1_indices) > 0: # [TO BE REMOVED IN PHASE 1] return False if len(indices(slashable_vote_data)) > MAX_CASPER_VOTES: @@ -1532,6 +1531,7 @@ For each `attestation` in `block.body.attestations`: assert verify_bitfield(attestation.aggregation_bitfield) assert verify_bitfield(attestation.custody_bitfield) assert attestation.custody_bitfield & attestation.aggregation_bitfield == attestation.custody_bitfield + assert attestation.custody_bitfield == 0 # [TO BE REMOVED IN PHASE 1] ``` * Verify aggregate signature: From 1e48535edd4e80779008a17a1eef1eb66d13ca32 Mon Sep 17 00:00:00 2001 From: Justin Date: Wed, 23 Jan 2019 12:57:06 +0000 Subject: [PATCH 06/19] 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 3a79ee71d..151e5f696 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1557,7 +1557,7 @@ For each `attestation` in `block.body.attestations`: ``` * [TO BE REMOVED IN PHASE 1] Verify that `attestation.data.shard_block_root == ZERO_HASH`. -* Append `PendingAttestation(data=attestation.data, aggregation_bitfield=attestation.aggregation_bitfield, slot_included=state.slot)` to `state.latest_attestations`. +* Append `PendingAttestation(data=attestation.data, aggregation_bitfield=attestation.aggregation_bitfield, custody_bitfield=attestation.custody_bitfield, slot_included=state.slot)` to `state.latest_attestations`. #### Deposits From e3a5720c1b7587e69cdebb453a6ae07e9d198e80 Mon Sep 17 00:00:00 2001 From: Justin Date: Wed, 23 Jan 2019 13:03:33 +0000 Subject: [PATCH 07/19] Update 0_beacon-chain.md --- 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 151e5f696..585ff5223 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -20,6 +20,7 @@ - [Max operations per block](#max-operations-per-block) - [Validator registry delta flags](#validator-registry-delta-flags) - [Signature domains](#signature-domains) + - [Custody bits](#custody-bits) - [Data structures](#data-structures) - [Beacon chain operations](#beacon-chain-operations) - [Proposer slashings](#proposer-slashings) From d1efd65d8a53a1e69b087cf30f7830eb36dd1acf Mon Sep 17 00:00:00 2001 From: Justin Date: Wed, 23 Jan 2019 13:24:35 +0000 Subject: [PATCH 08/19] Update 0_beacon-chain.md --- specs/core/0_beacon-chain.md | 46 +++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 585ff5223..ac3a00a37 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -302,10 +302,10 @@ Code snippets appearing in `this style` are to be interpreted as Python code. Be ```python { - # Validator indices with custody bit equal to 0 - 'custody_bit_0_indices': ['uint24'], - # Validator indices with custody bit equal to 1 - 'custody_bit_1_indices': ['uint24'], + # Validator indices + 'validator_indices': '[uint24]', + # Custody bitfield + 'custody_bitfield': 'bytes', # Attestation data 'data': AttestationData, # Aggregate signature @@ -1110,16 +1110,34 @@ def verify_bitfield(bitfield: bytes, size: int) -> bool: ```python def verify_slashable_vote_data(state: BeaconState, slashable_vote_data: SlashableVoteData) -> bool: - if len(slashable_vote_data.custody_bit_1_indices) > 0: # [TO BE REMOVED IN PHASE 1] + if slashable_vote_data.custody_bitfield != 0: # [TO BE REMOVED IN PHASE 1] return False - if len(indices(slashable_vote_data)) > MAX_CASPER_VOTES: + if len(slashable_vote_data.validator_indices) == 0: return False + for i in range(len(slashable_vote_data.validator_indices) - 1): + if slashable_vote_data.validator_indices[i] >= slashable_vote_data.validator_indices[i + 1]: + return False + + if not verify_bitfield(slashable_vote_data.custody_bitfield, len(slashable_vote_data.validator_indices)): + return False + + if len(slashable_vote_data.validator_indices) > MAX_CASPER_VOTES: + return False + + custody_bit_0_indices = [] + custody_bit_1_indices = [] + for i, validator_index in enumerate(slashable_vote_data.validator_indices): + if get_bitfield_bit(slashable_vote_data.custody_bitfield, i) == 0: + custody_bit_0_indices.append(validator_index) + else: + custody_bit_1_indices.append(validator_index) + return bls_verify( pubkeys=[ - bls_aggregate_pubkeys([state.validator_registry[i].pubkey for i in slashable_vote_data.custody_bit_0_indices]), - bls_aggregate_pubkeys([state.validator_registry[i].pubkey for i in slashable_vote_data.custody_bit_1_indices]), + 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=[ hash_tree_root(AttestationDataAndCustodyBit(slashable_vote_data.data, CUSTODY_BIT_ZERO)), @@ -1184,16 +1202,6 @@ def integer_squareroot(n: int) -> int: return x ``` -#### `indices` - -```python -def indices(slashable_vote_data: SlashableVoteData) -> List[int]: - """ - Return all indicies in ``slashable_vote_data``. - """ - return slashable_vote_data.custody_bit_0_indices + slashable_vote_data.custody_bit_1_indices -``` - #### `bls_verify` `bls_verify` is a function for verifying a BLS signature, defined in the [BLS Signature spec](https://github.com/ethereum/eth2.0-specs/blob/master/specs/bls_signature.md#bls_verify). @@ -1507,7 +1515,7 @@ For each `casper_slashing` in `block.body.casper_slashings`: * Let `slashable_vote_data_1 = casper_slashing.slashable_vote_data_1`. * Let `slashable_vote_data_2 = casper_slashing.slashable_vote_data_2`. -* Let `intersection = [x for x in indices(slashable_vote_data_1) if x in indices(slashable_vote_data_2)]`. +* Let `intersection = [x for x in slashable_vote_data_1.validator_indices if x in slashable_vote_data_2.validator_indices]`. * Verify that `len(intersection) >= 1`. * Verify that `slashable_vote_data_1.data != slashable_vote_data_2.data`. * Verify that `is_double_vote(slashable_vote_data_1.data, slashable_vote_data_2.data)` or `is_surround_vote(slashable_vote_data_1.data, slashable_vote_data_2.data)`. From 022dd0cc3d8ad239bb484cbf16d1f45bd360c951 Mon Sep 17 00:00:00 2001 From: Justin Date: Wed, 23 Jan 2019 13:26:23 +0000 Subject: [PATCH 09/19] Update 0_beacon-chain.md --- specs/core/0_beacon-chain.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index ac3a00a37..8c6197927 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1561,8 +1561,7 @@ For each `attestation` in `block.body.attestations`: ], signature=attestation.aggregate_signature, domain=get_domain(state.fork, attestation.data.slot, DOMAIN_ATTESTATION), - ) - + ) ``` * [TO BE REMOVED IN PHASE 1] Verify that `attestation.data.shard_block_root == ZERO_HASH`. From 6f3cb7e7e5991366f5dbfbc729d739edcf698a94 Mon Sep 17 00:00:00 2001 From: Justin Date: Wed, 23 Jan 2019 13:28:43 +0000 Subject: [PATCH 10/19] Update 0_beacon-chain.md --- specs/core/0_beacon-chain.md | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 8c6197927..a708a30a8 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -255,13 +255,6 @@ Code snippets appearing in `this style` are to be interpreted as Python code. Be | `DOMAIN_EXIT` | `3` | | `DOMAIN_RANDAO` | `4` | -### Custody bits - -| Name | Value | -| - | - | -| `CUSTODY_BIT_ZERO` | `False` | -| `CUSTODY_BIT_ONE` | `True` | - ## Data structures ### Beacon chain operations @@ -1140,8 +1133,8 @@ def verify_slashable_vote_data(state: BeaconState, slashable_vote_data: Slashabl bls_aggregate_pubkeys([state.validator_registry[i].pubkey for i in custody_bit_1_indices]), ], messages=[ - hash_tree_root(AttestationDataAndCustodyBit(slashable_vote_data.data, CUSTODY_BIT_ZERO)), - hash_tree_root(AttestationDataAndCustodyBit(slashable_vote_data.data, CUSTODY_BIT_ONE)), + hash_tree_root(AttestationDataAndCustodyBit(slashable_vote_data.data, 0)), + hash_tree_root(AttestationDataAndCustodyBit(slashable_vote_data.data, 1)), ], signature=slashable_vote_data.aggregate_signature, domain=get_domain(state.fork, slashable_vote_data.data.slot, DOMAIN_ATTESTATION), @@ -1556,8 +1549,8 @@ For each `attestation` in `block.body.attestations`: bls_aggregate_pubkeys([state.validator_registry[i].pubkey for i in custody_bit_1_participants]), ], messages=[ - hash_tree_root(AttestationDataAndCustodyBit(data=attestation.data, custody_bit=CUSTODY_BIT_ZERO)), - hash_tree_root(AttestationDataAndCustodyBit(data=attestation.data, custody_bit=CUSTODY_BIT_ONE)), + hash_tree_root(AttestationDataAndCustodyBit(data=attestation.data, custody_bit=0)), + hash_tree_root(AttestationDataAndCustodyBit(data=attestation.data, custody_bit=1)), ], signature=attestation.aggregate_signature, domain=get_domain(state.fork, attestation.data.slot, DOMAIN_ATTESTATION), From dfaf24c75e3df6aaaabab88bfd6115c23928dc77 Mon Sep 17 00:00:00 2001 From: Justin Date: Wed, 23 Jan 2019 13:52:52 +0000 Subject: [PATCH 11/19] Update 0_beacon-chain.md --- specs/core/0_beacon-chain.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index a708a30a8..5c0663242 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -20,7 +20,6 @@ - [Max operations per block](#max-operations-per-block) - [Validator registry delta flags](#validator-registry-delta-flags) - [Signature domains](#signature-domains) - - [Custody bits](#custody-bits) - [Data structures](#data-structures) - [Beacon chain operations](#beacon-chain-operations) - [Proposer slashings](#proposer-slashings) @@ -1080,6 +1079,9 @@ def get_domain(fork: Fork, ```python def get_bitfield_bit(bitfield: bytes, i: int) -> int: + """ + Extract the bit in ``bitfield`` at position ``i``. + """ return (bitfield[i // 8] >> (7 - (i % 8))) % 2 ``` @@ -1087,12 +1089,13 @@ def get_bitfield_bit(bitfield: bytes, i: int) -> int: ```python def verify_bitfield(bitfield: bytes, size: int) -> bool: - ``` + """ Verify ``bitfield`` against the ``size``. + """ if len(bitfield) != (size + 7) // 8: return False - for i in range(size + 1, size + size % 8 + 8): + for i in range(size + 1, size - size % 8 + 8): if get_bitfield_bit(bitfield, i) != 0: return False @@ -1103,6 +1106,9 @@ def verify_bitfield(bitfield: bytes, size: int) -> bool: ```python def verify_slashable_vote_data(state: BeaconState, slashable_vote_data: SlashableVoteData) -> bool: + """ + Verify validity of ``slashable_vote_data`` fields. + """ if slashable_vote_data.custody_bitfield != 0: # [TO BE REMOVED IN PHASE 1] return False From 6e16cdc00e6e5492e5046b562db82666293d31b3 Mon Sep 17 00:00:00 2001 From: Justin Date: Sat, 26 Jan 2019 18:59:07 +0000 Subject: [PATCH 12/19] Update 0_beacon-chain.md --- specs/core/0_beacon-chain.md | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 5c0663242..4da97cc54 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -167,7 +167,7 @@ Code snippets appearing in `this style` are to be interpreted as Python code. Be | `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_CASPER_VOTES` | `2**10` (= 1,024) | votes | +| `MAX_CASPER_VOTES` | `2**12` (= 4,096) | votes | | `LATEST_BLOCK_ROOTS_LENGTH` | `2**13` (= 8,192) | block roots | | `LATEST_RANDAO_MIXES_LENGTH` | `2**13` (= 8,192) | randao mixes | | `LATEST_PENALIZED_EXIT_LENGTH` | `2**13` (= 8,192) | epochs | ~36 days | @@ -232,7 +232,7 @@ Code snippets appearing in `this style` are to be interpreted as Python code. Be | Name | Value | | - | - | | `MAX_PROPOSER_SLASHINGS` | `2**4` (= 16) | -| `MAX_CASPER_SLASHINGS` | `2**4` (= 16) | +| `MAX_CASPER_SLASHINGS` | `2**0` (= 1) | | `MAX_ATTESTATIONS` | `2**7` (= 128) | | `MAX_DEPOSITS` | `2**4` (= 16) | | `MAX_EXITS` | `2**4` (= 16) | @@ -1029,6 +1029,8 @@ def get_attestation_participants(state: BeaconState, assert attestation_data.shard in [shard for _, shard in crosslink_committees] crosslink_committee = [committee for committee, shard in crosslink_committees if shard == attestation_data.shard][0] + assert verify_bitfield(bitfield, len(crosslink_committee)) + # Find the participating attesters in the committee participants = [] for i, validator_index in enumerate(crosslink_committee): @@ -1088,14 +1090,14 @@ def get_bitfield_bit(bitfield: bytes, i: int) -> int: #### `verify_bitfield` ```python -def verify_bitfield(bitfield: bytes, size: int) -> bool: +def verify_bitfield(bitfield: bytes, committee_size: int) -> bool: """ - Verify ``bitfield`` against the ``size``. + Verify ``bitfield`` against the ``committee_size``. """ - if len(bitfield) != (size + 7) // 8: + if len(bitfield) != (committee_size + 7) // 8: return False - for i in range(size + 1, size - size % 8 + 8): + for i in range(committee_size + 1, committee_size - committee_size % 8 + 8): if get_bitfield_bit(bitfield, i) != 0: return False @@ -1109,7 +1111,7 @@ def verify_slashable_vote_data(state: BeaconState, slashable_vote_data: Slashabl """ Verify validity of ``slashable_vote_data`` fields. """ - if slashable_vote_data.custody_bitfield != 0: # [TO BE REMOVED IN PHASE 1] + if slashable_vote_data.custody_bitfield != b'\x00' * len(slashable_vote_data.custody_bitfield): # [TO BE REMOVED IN PHASE 1] return False if len(slashable_vote_data.validator_indices) == 0: @@ -1536,9 +1538,10 @@ For each `attestation` in `block.body.attestations`: * Verify bitfields: ```python - assert verify_bitfield(attestation.aggregation_bitfield) - assert verify_bitfield(attestation.custody_bitfield) - assert attestation.custody_bitfield & attestation.aggregation_bitfield == attestation.custody_bitfield + for i in range(len(crosslink_committee)): + if get_bitfield_bit(attestation.aggregation_bitfield) == 0: + assert get_bitfield_bit(attestation.custody_bitfield) == 0 + assert attestation.custody_bitfield == 0 # [TO BE REMOVED IN PHASE 1] ``` From c3aff31da862e0a585405597f8da85ade2a04ca2 Mon Sep 17 00:00:00 2001 From: Justin Date: Sat, 26 Jan 2019 19:06:46 +0000 Subject: [PATCH 13/19] Update 0_beacon-chain.md --- specs/core/0_beacon-chain.md | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 898f9ae3d..906d3e1b5 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1551,19 +1551,15 @@ For each `attestation` in `block.body.attestations`: * Verify that `attestation.data.justified_slot` is equal to `state.justified_slot if attestation.data.slot >= state.slot - (state.slot % EPOCH_LENGTH) else state.previous_justified_slot`. * Verify that `attestation.data.justified_block_root` is equal to `get_block_root(state, attestation.data.justified_slot)`. * Verify that either `attestation.data.latest_crosslink_root` or `attestation.data.shard_block_root` equals `state.latest_crosslinks[shard].shard_block_root`. -* Verify bitfields: +* Verify bitfields and aggregate signature: ```python + assert attestation.custody_bitfield == 0 # [TO BE REMOVED IN PHASE 1] + for i in range(len(crosslink_committee)): if get_bitfield_bit(attestation.aggregation_bitfield) == 0: assert get_bitfield_bit(attestation.custody_bitfield) == 0 - assert attestation.custody_bitfield == 0 # [TO BE REMOVED IN PHASE 1] -``` - -* Verify aggregate signature: - -```python participants = get_attestation_participants(state, attestation.data, attestation.aggregation_bitfield) custody_bit_0_participants = get_attestation_participants(state, attestation.data, attestation.custody_bitfield) custody_bit_1_participants = [i in participants for i not in custody_bit_0_participants] From a81092627a4bfedc0427cd5b9ffa1e491d16f321 Mon Sep 17 00:00:00 2001 From: Justin Date: Sat, 26 Jan 2019 19:10:21 +0000 Subject: [PATCH 14/19] Update 0_beacon-chain.md --- 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 906d3e1b5..0648a351c 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -167,7 +167,7 @@ Code snippets appearing in `this style` are to be interpreted as Python code. Be | `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_CASPER_VOTES` | `2**12` (= 4,096) | votes | +| `MAX_INDICES_PER_SLASHABLE_VOTE` | `2**12` (= 4,096) | votes | | `LATEST_BLOCK_ROOTS_LENGTH` | `2**13` (= 8,192) | block roots | | `LATEST_RANDAO_MIXES_LENGTH` | `2**13` (= 8,192) | randao mixes | | `LATEST_INDEX_ROOTS_LENGTH` | `2**13` (= 8,192) | index roots | @@ -1147,7 +1147,7 @@ def verify_slashable_vote_data(state: BeaconState, slashable_vote_data: Slashabl if not verify_bitfield(slashable_vote_data.custody_bitfield, len(slashable_vote_data.validator_indices)): return False - if len(slashable_vote_data.validator_indices) > MAX_CASPER_VOTES: + if len(slashable_vote_data.validator_indices) > MAX_INDICES_PER_SLASHABLE_VOTE: return False custody_bit_0_indices = [] From cfb1cb57b8bd7db23f8a7feaaf33b708036f4c11 Mon Sep 17 00:00:00 2001 From: Justin Date: Sat, 26 Jan 2019 19:25:18 +0000 Subject: [PATCH 15/19] Update 0_beacon-chain.md --- specs/core/0_beacon-chain.md | 54 ++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 0648a351c..9d1fd14b7 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -25,7 +25,7 @@ - [`ProposerSlashing`](#proposerslashing) - [Casper slashings](#casper-slashings) - [`CasperSlashing`](#casperslashing) - - [`SlashableVoteData`](#slashablevotedata) + - [`SlashableVote`](#SlashableVote) - [Attestations](#attestations) - [`Attestation`](#attestation) - [`AttestationData`](#attestationdata) @@ -82,7 +82,7 @@ - [`get_domain`](#get_domain) - [`get_bitfield_bit`](#get_bitfield_bit) - [`verify_bitfield`](#verify_bitfield) - - [`verify_slashable_vote_data`](#verify_slashable_vote_data) + - [`verify_slashable_vote`](#verify_slashable_vote) - [`is_double_vote`](#is_double_vote) - [`is_surround_vote`](#is_surround_vote) - [`integer_squareroot`](#integer_squareroot) @@ -280,13 +280,13 @@ The following data structures are defined as [SimpleSerialize (SSZ)](https://git ```python { # First batch of votes - 'slashable_vote_data_1': SlashableVoteData, + 'slashable_vote_1': SlashableVote, # Second batch of votes - 'slashable_vote_data_2': SlashableVoteData, + 'slashable_vote_2': SlashableVote, } ``` -##### `SlashableVoteData` +##### `SlashableVote` ```python { @@ -1127,33 +1127,33 @@ def verify_bitfield(bitfield: bytes, committee_size: int) -> bool: return True ``` -#### `verify_slashable_vote_data` +#### `verify_slashable_vote` ```python -def verify_slashable_vote_data(state: BeaconState, slashable_vote_data: SlashableVoteData) -> bool: +def verify_slashable_vote(state: BeaconState, slashable_vote: SlashableVote) -> bool: """ - Verify validity of ``slashable_vote_data`` fields. + Verify validity of ``slashable_vote`` fields. """ - if slashable_vote_data.custody_bitfield != b'\x00' * len(slashable_vote_data.custody_bitfield): # [TO BE REMOVED IN PHASE 1] + if slashable_vote.custody_bitfield != b'\x00' * len(slashable_vote.custody_bitfield): # [TO BE REMOVED IN PHASE 1] return False - if len(slashable_vote_data.validator_indices) == 0: + if len(slashable_vote.validator_indices) == 0: return False - for i in range(len(slashable_vote_data.validator_indices) - 1): - if slashable_vote_data.validator_indices[i] >= slashable_vote_data.validator_indices[i + 1]: + for i in range(len(slashable_vote.validator_indices) - 1): + if slashable_vote.validator_indices[i] >= slashable_vote.validator_indices[i + 1]: return False - if not verify_bitfield(slashable_vote_data.custody_bitfield, len(slashable_vote_data.validator_indices)): + if not verify_bitfield(slashable_vote.custody_bitfield, len(slashable_vote.validator_indices)): return False - if len(slashable_vote_data.validator_indices) > MAX_INDICES_PER_SLASHABLE_VOTE: + if len(slashable_vote.validator_indices) > MAX_INDICES_PER_SLASHABLE_VOTE: return False custody_bit_0_indices = [] custody_bit_1_indices = [] - for i, validator_index in enumerate(slashable_vote_data.validator_indices): - if get_bitfield_bit(slashable_vote_data.custody_bitfield, i) == 0: + for i, validator_index in enumerate(slashable_vote.validator_indices): + if get_bitfield_bit(slashable_vote.custody_bitfield, i) == 0: custody_bit_0_indices.append(validator_index) else: custody_bit_1_indices.append(validator_index) @@ -1164,11 +1164,11 @@ def verify_slashable_vote_data(state: BeaconState, slashable_vote_data: Slashabl bls_aggregate_pubkeys([state.validator_registry[i].pubkey for i in custody_bit_1_indices]), ], messages=[ - hash_tree_root(AttestationDataAndCustodyBit(slashable_vote_data.data, 0)), - hash_tree_root(AttestationDataAndCustodyBit(slashable_vote_data.data, 1)), + hash_tree_root(AttestationDataAndCustodyBit(slashable_vote.data, 0)), + hash_tree_root(AttestationDataAndCustodyBit(slashable_vote.data, 1)), ], - signature=slashable_vote_data.aggregate_signature, - domain=get_domain(state.fork, slashable_vote_data.data.slot, DOMAIN_ATTESTATION), + signature=slashable_vote.aggregate_signature, + domain=get_domain(state.fork, slashable_vote.data.slot, DOMAIN_ATTESTATION), ) ``` @@ -1530,14 +1530,14 @@ Verify that `len(block.body.casper_slashings) <= MAX_CASPER_SLASHINGS`. For each `casper_slashing` in `block.body.casper_slashings`: -* Let `slashable_vote_data_1 = casper_slashing.slashable_vote_data_1`. -* Let `slashable_vote_data_2 = casper_slashing.slashable_vote_data_2`. -* Let `intersection = [x for x in slashable_vote_data_1.validator_indices if x in slashable_vote_data_2.validator_indices]`. +* Let `slashable_vote_1 = casper_slashing.slashable_vote_1`. +* Let `slashable_vote_2 = casper_slashing.slashable_vote_2`. +* Let `intersection = [x for x in slashable_vote_1.validator_indices if x in slashable_vote_2.validator_indices]`. * Verify that `len(intersection) >= 1`. -* Verify that `slashable_vote_data_1.data != slashable_vote_data_2.data`. -* Verify that `is_double_vote(slashable_vote_data_1.data, slashable_vote_data_2.data)` or `is_surround_vote(slashable_vote_data_1.data, slashable_vote_data_2.data)`. -* Verify that `verify_slashable_vote_data(state, slashable_vote_data_1)`. -* Verify that `verify_slashable_vote_data(state, slashable_vote_data_2)`. +* Verify that `slashable_vote_1.data != slashable_vote_2.data`. +* Verify that `is_double_vote(slashable_vote_1.data, slashable_vote_2.data)` or `is_surround_vote(slashable_vote_1.data, slashable_vote_2.data)`. +* Verify that `verify_slashable_vote(state, slashable_vote_1)`. +* Verify that `verify_slashable_vote(state, slashable_vote_2)`. * For each [validator](#dfn-validator) index `i` in `intersection` run `penalize_validator(state, i)` if `state.validator_registry[i].penalized_slot > state.slot`. #### Attestations From aa909bddf3f32115ecfbd2bb5ddbeb0efab6f976 Mon Sep 17 00:00:00 2001 From: Justin Date: Sat, 26 Jan 2019 19:25:58 +0000 Subject: [PATCH 16/19] 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 9d1fd14b7..9a3590d9a 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -25,7 +25,7 @@ - [`ProposerSlashing`](#proposerslashing) - [Casper slashings](#casper-slashings) - [`CasperSlashing`](#casperslashing) - - [`SlashableVote`](#SlashableVote) + - [`SlashableVote`](#slashablevote) - [Attestations](#attestations) - [`Attestation`](#attestation) - [`AttestationData`](#attestationdata) From d282a36c63d51b1db2fe65dc98e75be173858c1f Mon Sep 17 00:00:00 2001 From: Justin Date: Sat, 26 Jan 2019 19:27:22 +0000 Subject: [PATCH 17/19] 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 9a3590d9a..33226aeee 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1554,7 +1554,7 @@ For each `attestation` in `block.body.attestations`: * Verify bitfields and aggregate signature: ```python - assert attestation.custody_bitfield == 0 # [TO BE REMOVED IN PHASE 1] + assert attestation.custody_bitfield == 0 # [TO BE REMOVED IN PHASE 1] for i in range(len(crosslink_committee)): if get_bitfield_bit(attestation.aggregation_bitfield) == 0: From 82ecc8c86856fc504db96504aa93488f6218510d Mon Sep 17 00:00:00 2001 From: Justin Date: Sun, 27 Jan 2019 09:01:11 +0000 Subject: [PATCH 18/19] Update 0_beacon-chain.md --- specs/core/0_beacon-chain.md | 48 ++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 33226aeee..8ac9fb47c 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -261,7 +261,7 @@ The following data structures are defined as [SimpleSerialize (SSZ)](https://git ```python { # Proposer index - 'proposer_index': 'uint24', + 'proposer_index': 'uint64', # First proposal data 'proposal_data_1': ProposalSignedData, # First proposal signature @@ -291,7 +291,7 @@ The following data structures are defined as [SimpleSerialize (SSZ)](https://git ```python { # Validator indices - 'validator_indices': '[uint24]', + 'validator_indices': '[uint64]', # Custody bitfield 'custody_bitfield': 'bytes', # Attestation data @@ -402,7 +402,7 @@ The following data structures are defined as [SimpleSerialize (SSZ)](https://git # Minimum slot for processing exit 'slot': 'uint64', # Index of the exiting validator - 'validator_index': 'uint24', + 'validator_index': 'uint64', # Validator signature 'signature': 'bytes96', } @@ -588,15 +588,15 @@ The following data structures are defined as [SimpleSerialize (SSZ)](https://git We define the following Python custom types for type hinting and readability: -| Name | Type | Description | +| Name | SSZ equivalent | Description | | - | - | - | -| `SlotNumber` | unsigned 64-bit integer | the number of a slot | -| `ShardNumber` | unsigned 64-bit integer | the number of a shard | -| `ValidatorIndex` | unsigned 24-bit integer | the index number of a validator in the registry | -| `Gwei` | unsigned 64-bit integer | an amount in Gwei | -| `Bytes32` | 32-byte data | binary data with 32-byte length | -| `BLSPubkey` | 48-byte data | a public key in BLS signature scheme | -| `BLSSignature` | 96-byte data | a signature in BLS signature scheme | +| `SlotNumber` | `uint64` | a slot number | +| `ShardNumber` | `uint64` | a shard number | +| `ValidatorIndex` | `uint64` | an index in the validator registry | +| `Gwei` | `uint64` | an amount in Gwei | +| `Bytes32` | `bytes32` | 32 bytes of binary data | +| `BLSPubkey` | `bytes48` | a BLS public key | +| `BLSSignature` | `bytes96` | a BLS signature | ## Ethereum 1.0 deposit contract @@ -1058,7 +1058,7 @@ def get_attestation_participants(state: BeaconState, participants = [] for i, validator_index in enumerate(crosslink_committee): aggregation_bit = get_bitfield_bit(bitfield, i) - if aggregation_bit == 1: + if aggregation_bit == 0b1: participants.append(validator_index) return participants ``` @@ -1121,7 +1121,7 @@ def verify_bitfield(bitfield: bytes, committee_size: int) -> bool: return False for i in range(committee_size + 1, committee_size - committee_size % 8 + 8): - if get_bitfield_bit(bitfield, i) != 0: + if get_bitfield_bit(bitfield, i) == 0b1: return False return True @@ -1142,7 +1142,7 @@ def verify_slashable_vote(state: BeaconState, slashable_vote: SlashableVote) -> for i in range(len(slashable_vote.validator_indices) - 1): if slashable_vote.validator_indices[i] >= slashable_vote.validator_indices[i + 1]: - return False + return False if not verify_bitfield(slashable_vote.custody_bitfield, len(slashable_vote.validator_indices)): return False @@ -1153,7 +1153,7 @@ def verify_slashable_vote(state: BeaconState, slashable_vote: SlashableVote) -> custody_bit_0_indices = [] custody_bit_1_indices = [] for i, validator_index in enumerate(slashable_vote.validator_indices): - if get_bitfield_bit(slashable_vote.custody_bitfield, i) == 0: + if get_bitfield_bit(slashable_vote.custody_bitfield, i) == 0b0: custody_bit_0_indices.append(validator_index) else: custody_bit_1_indices.append(validator_index) @@ -1164,8 +1164,8 @@ def verify_slashable_vote(state: BeaconState, slashable_vote: SlashableVote) -> bls_aggregate_pubkeys([state.validator_registry[i].pubkey for i in custody_bit_1_indices]), ], messages=[ - hash_tree_root(AttestationDataAndCustodyBit(slashable_vote.data, 0)), - hash_tree_root(AttestationDataAndCustodyBit(slashable_vote.data, 1)), + hash_tree_root(AttestationDataAndCustodyBit(attestation_data=slashable_vote.data, custody_bit=0b0)), + hash_tree_root(AttestationDataAndCustodyBit(attestation_data=slashable_vote.data, custody_bit=0b1)), ], signature=slashable_vote.aggregate_signature, domain=get_domain(state.fork, slashable_vote.data.slot, DOMAIN_ATTESTATION), @@ -1554,15 +1554,15 @@ For each `attestation` in `block.body.attestations`: * Verify bitfields and aggregate signature: ```python - assert attestation.custody_bitfield == 0 # [TO BE REMOVED IN PHASE 1] + assert attestation.custody_bitfield == b'\x00' * len(attestation.custody_bitfield) # [TO BE REMOVED IN PHASE 1] for i in range(len(crosslink_committee)): - if get_bitfield_bit(attestation.aggregation_bitfield) == 0: - assert get_bitfield_bit(attestation.custody_bitfield) == 0 + if get_bitfield_bit(attestation.aggregation_bitfield) == 0b0: + assert get_bitfield_bit(attestation.custody_bitfield) == 0b0 participants = get_attestation_participants(state, attestation.data, attestation.aggregation_bitfield) - custody_bit_0_participants = get_attestation_participants(state, attestation.data, attestation.custody_bitfield) - custody_bit_1_participants = [i in participants for i not in custody_bit_0_participants] + custody_bit_1_participants = get_attestation_participants(state, attestation.data, attestation.custody_bitfield) + custody_bit_0_participants = [i in participants for i not in custody_bit_1_participants] assert bls_verify_multiple( pubkeys=[ @@ -1570,8 +1570,8 @@ For each `attestation` in `block.body.attestations`: bls_aggregate_pubkeys([state.validator_registry[i].pubkey for i in custody_bit_1_participants]), ], messages=[ - hash_tree_root(AttestationDataAndCustodyBit(data=attestation.data, custody_bit=0)), - hash_tree_root(AttestationDataAndCustodyBit(data=attestation.data, custody_bit=1)), + hash_tree_root(AttestationDataAndCustodyBit(data=attestation.data, custody_bit=0b0)), + hash_tree_root(AttestationDataAndCustodyBit(data=attestation.data, custody_bit=0b1)), ], signature=attestation.aggregate_signature, domain=get_domain(state.fork, attestation.data.slot, DOMAIN_ATTESTATION), From 9b7d94f07babca4bbd1359e4b9276759af0704d0 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Mon, 28 Jan 2019 18:31:13 +0000 Subject: [PATCH 19/19] Apply suggestions from code review Co-Authored-By: JustinDrake --- 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 6a04eb2fb..bb5a0b850 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -361,7 +361,7 @@ The following data structures are defined as [SimpleSerialize (SSZ)](https://git # Attestation data 'data': AttestationData, # Custody bit - 'custody_bit': bool, + 'custody_bit': 'bool', } ``` @@ -1624,7 +1624,7 @@ For each `attestation` in `block.body.attestations`: hash_tree_root(AttestationDataAndCustodyBit(data=attestation.data, custody_bit=0b1)), ], signature=attestation.aggregate_signature, - domain=get_domain(state.fork, attestation.data.slot, DOMAIN_ATTESTATION), + domain=get_domain(state.fork, slot_to_epoch(attestation.data.slot), DOMAIN_ATTESTATION), ) ```