From ab140c2f1c92fa5821a332e89d56393f4499ef86 Mon Sep 17 00:00:00 2001 From: Justin Date: Fri, 15 Feb 2019 00:23:03 +0000 Subject: [PATCH 1/3] Update 0_beacon-chain.md --- specs/core/0_beacon-chain.md | 151 ++++++++++++++--------------------- 1 file changed, 62 insertions(+), 89 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index a48d881fa5..c38b237bc4 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -43,7 +43,8 @@ - [Beacon chain blocks](#beacon-chain-blocks) - [`BeaconBlock`](#beaconblock) - [`BeaconBlockBody`](#beaconblockbody) - - [`ProposalSignedData`](#proposalsigneddata) + - [`Proposal`](#proposal) + - [`RandaoReveal`](#randaoreveal) - [Beacon chain state](#beacon-chain-state) - [`BeaconState`](#beaconstate) - [`Validator`](#validator) @@ -94,7 +95,6 @@ - [`bls_verify`](#bls_verify) - [`bls_verify_multiple`](#bls_verify_multiple) - [`bls_aggregate_pubkeys`](#bls_aggregate_pubkeys) - - [`validate_proof_of_possession`](#validate_proof_of_possession) - [`process_deposit`](#process_deposit) - [Routines for updating validator status](#routines-for-updating-validator-status) - [`activate_validator`](#activate_validator) @@ -117,7 +117,7 @@ - [Block roots](#block-roots) - [Per-block processing](#per-block-processing) - [Slot](#slot-1) - - [Proposer signature](#proposer-signature) + - [Block signature](#block-signature) - [RANDAO](#randao) - [Eth1 data](#eth1-data) - [Transactions](#transactions) @@ -299,14 +299,10 @@ The following data structures are defined as [SimpleSerialize (SSZ)](https://git { # Proposer index 'proposer_index': 'uint64', - # First proposal data - 'proposal_data_1': ProposalSignedData, - # First proposal signature - 'proposal_signature_1': 'bytes96', - # Second proposal data - 'proposal_data_2': ProposalSignedData, - # Second proposal signature - 'proposal_signature_2': 'bytes96', + # First proposal + 'proposal_1': Proposal, + # Second proposal + 'proposal_2': Proposal, } ``` @@ -363,9 +359,9 @@ The following data structures are defined as [SimpleSerialize (SSZ)](https://git 'slot': 'uint64', # Shard number 'shard': 'uint64', - # Hash of root of the signed beacon block + # Root of the signed beacon block 'beacon_block_root': 'bytes32', - # Hash of root of the ancestor at the epoch boundary + # Root of the ancestor at the epoch boundary 'epoch_boundary_root': 'bytes32', # Shard block's hash of root 'shard_block_root': 'bytes32', @@ -474,16 +470,17 @@ The following data structures are defined as [SimpleSerialize (SSZ)](https://git ```python { - ## Header ## - 'slot': 'uint64', + # Header + 'slot': Slot, 'parent_root': 'bytes32', 'state_root': 'bytes32', 'randao_reveal': 'bytes96', 'eth1_data': Eth1Data, - 'signature': 'bytes96', - ## Body ## + # Body 'body': BeaconBlockBody, + # Signature + 'signature': 'bytes96', } ``` @@ -500,7 +497,7 @@ The following data structures are defined as [SimpleSerialize (SSZ)](https://git } ``` -#### `ProposalSignedData` +#### `Proposal` ```python { @@ -508,8 +505,21 @@ The following data structures are defined as [SimpleSerialize (SSZ)](https://git 'slot': 'uint64', # Shard number (`BEACON_CHAIN_SHARD_NUMBER` for beacon chain) 'shard': 'uint64', - # Block's hash of root + # Block root 'block_root': 'bytes32', + # Signature + 'signature': 'bytes96', +} +``` + +#### `RandaoReveal` + +```python +{ + # Epoch number + 'epoch': 'uint64', + # RANDAO reveal + 'randao_reveal': 'bytes96', } ``` @@ -670,6 +680,10 @@ Note: We aim to migrate to a S[T/N]ARK-friendly hash function in a future Ethere `def hash_tree_root(object: SSZSerializable) -> Bytes32` is a function for hashing objects into a single root utilizing a hash tree structure. `hash_tree_root` is defined in the [SimpleSerialize spec](https://github.com/ethereum/eth2.0-specs/blob/master/specs/simple-serialize.md#tree-hash). +### `signed_root` + +`def signed_root(object: SSZContainer) -> Bytes32` is a function defined in the [SimpleSerialize spec](https://github.com/ethereum/eth2.0-specs/blob/master/specs/simple-serialize.md#signed-roots) to compute signed messages. + ### `slot_to_epoch` ```python @@ -1240,60 +1254,33 @@ def get_entry_exit_effect_epoch(epoch: Epoch) -> Epoch: `bls_aggregate_pubkeys` is a function for aggregating multiple BLS public keys into a single aggregate key, defined in the [BLS Signature spec](https://github.com/ethereum/eth2.0-specs/blob/master/specs/bls_signature.md#bls_aggregate_pubkeys). -### `validate_proof_of_possession` +### `process_deposit` + +Used to add a [validator](#dfn-validator) or top up an existing [validator](#dfn-validator)'s balance by some `deposit` amount: ```python -def validate_proof_of_possession(state: BeaconState, - pubkey: BLSPubkey, - proof_of_possession: BLSSignature, - withdrawal_credentials: Bytes32) -> bool: +def process_deposit(state: BeaconState, deposit: Deposit) -> None: """ - Verify the given ``proof_of_possession``. + Process a deposit from Ethereum 1.0. + Note that this function mutates ``state``. """ - proof_of_possession_data = DepositInput( - pubkey=pubkey, - withdrawal_credentials=withdrawal_credentials, - proof_of_possession=EMPTY_SIGNATURE, - ) + deposit_input = deposit.deposit_data.deposit_input - return bls_verify( - pubkey=pubkey, - message_hash=hash_tree_root(proof_of_possession_data), - signature=proof_of_possession, + assert bls_verify( + pubkey=deposit_input.pubkey, + message_hash=signed_root(deposit_input, "proof_of_possession"), + signature=deposit_input.proof_of_possession, domain=get_domain( state.fork, get_current_epoch(state), DOMAIN_DEPOSIT, ) ) -``` - -### `process_deposit` - -Used to add a [validator](#dfn-validator) or top up an existing [validator](#dfn-validator)'s balance by some `deposit` amount: - -```python -def process_deposit(state: BeaconState, - pubkey: BLSPubkey, - amount: Gwei, - proof_of_possession: BLSSignature, - withdrawal_credentials: Bytes32) -> None: - """ - Process a deposit from Ethereum 1.0. - Note that this function mutates ``state``. - """ - # Validate the given `proof_of_possession` - proof_is_valid = validate_proof_of_possession( - state, - pubkey, - proof_of_possession, - withdrawal_credentials, - ) - - if not proof_is_valid: - return validator_pubkeys = [v.pubkey for v in state.validator_registry] + pubkey = deposit_input.pubkey + amount = deposit.deposit_data.amount + withdrawal_credentials = deposit_input.withdrawal_credentials if pubkey not in validator_pubkeys: # Add new validator @@ -1520,13 +1507,7 @@ def get_genesis_beacon_state(genesis_validator_deposits: List[Deposit], # Process genesis deposits for deposit in genesis_validator_deposits: - process_deposit( - state=state, - pubkey=deposit.deposit_data.deposit_input.pubkey, - amount=deposit.deposit_data.amount, - proof_of_possession=deposit.deposit_data.deposit_input.proof_of_possession, - withdrawal_credentials=deposit.deposit_data.deposit_input.withdrawal_credentials, - ) + process_deposit(state, deposit) # Process genesis activations for validator_index, _ in enumerate(state.validator_registry): @@ -1652,16 +1633,16 @@ Below are the processing steps that happen at every `block`. * Verify that `block.slot == state.slot`. -#### Proposer signature +#### Block signature -* Let `block_without_signature_root` be the `hash_tree_root` of `block` where `block.signature` is set to `EMPTY_SIGNATURE`. -* Let `proposal_root = hash_tree_root(ProposalSignedData(state.slot, BEACON_CHAIN_SHARD_NUMBER, block_without_signature_root))`. -* Verify that `bls_verify(pubkey=state.validator_registry[get_beacon_proposer_index(state, state.slot)].pubkey, message_hash=proposal_root, signature=block.signature, domain=get_domain(state.fork, get_current_epoch(state), DOMAIN_PROPOSAL))`. +* Let `proposer = state.validator_registry[get_beacon_proposer_index(state, state.slot)]`. +* Let `proposal = Proposal(block.slot, BEACON_CHAIN_SHARD_NUMBER, signed_root(block, "signature"), block.signature)`. +* Verify that `bls_verify(pubkey=proposer.pubkey, message_hash=signed_root(proposal, "signature"), signature=proposal.signature, domain=get_domain(state.fork, get_current_epoch(state), DOMAIN_PROPOSAL))`. #### RANDAO -* Let `proposer = state.validator_registry[get_beacon_proposer_index(state, state.slot)]`. -* Verify that `bls_verify(pubkey=proposer.pubkey, message_hash=int_to_bytes32(get_current_epoch(state)), signature=block.randao_reveal, domain=get_domain(state.fork, get_current_epoch(state), DOMAIN_RANDAO))`. +* Let `randao_reveal = RandaoReveal(epoch=get_current_epoch(state), randao_reveal=block.randao_reveal)`. +* Verify that `bls_verify(pubkey=proposer.pubkey, message_hash=signed_root(randao_reveal, "randao_reveal"), signature=randao_reveal.randao_reveal, domain=get_domain(state.fork, get_current_epoch(state), DOMAIN_RANDAO))`. * Set `state.latest_randao_mixes[get_current_epoch(state) % LATEST_RANDAO_MIXES_LENGTH] = xor(get_randao_mix(state, get_current_epoch(state)), hash(block.randao_reveal))`. #### Eth1 data @@ -1678,12 +1659,12 @@ Verify that `len(block.body.proposer_slashings) <= MAX_PROPOSER_SLASHINGS`. For each `proposer_slashing` in `block.body.proposer_slashings`: * Let `proposer = state.validator_registry[proposer_slashing.proposer_index]`. -* Verify that `proposer_slashing.proposal_data_1.slot == proposer_slashing.proposal_data_2.slot`. -* Verify that `proposer_slashing.proposal_data_1.shard == proposer_slashing.proposal_data_2.shard`. -* Verify that `proposer_slashing.proposal_data_1.block_root != proposer_slashing.proposal_data_2.block_root`. +* Verify that `proposer_slashing.proposal_1.slot == proposer_slashing.proposal_2.slot`. +* Verify that `proposer_slashing.proposal_1.shard == proposer_slashing.proposal_2.shard`. +* Verify that `proposer_slashing.proposal_1.block_root != proposer_slashing.proposal_2.block_root`. * Verify that `proposer.slashed_epoch > get_current_epoch(state)`. -* Verify that `bls_verify(pubkey=proposer.pubkey, message_hash=hash_tree_root(proposer_slashing.proposal_data_1), signature=proposer_slashing.proposal_signature_1, domain=get_domain(state.fork, slot_to_epoch(proposer_slashing.proposal_data_1.slot), DOMAIN_PROPOSAL))`. -* Verify that `bls_verify(pubkey=proposer.pubkey, message_hash=hash_tree_root(proposer_slashing.proposal_data_2), signature=proposer_slashing.proposal_signature_2, domain=get_domain(state.fork, slot_to_epoch(proposer_slashing.proposal_data_2.slot), DOMAIN_PROPOSAL))`. +* Verify that `bls_verify(pubkey=proposer.pubkey, message_hash=signed_root(proposer_slashing.proposal_1, "signature"), signature=proposer_slashing.proposal_1.signature, domain=get_domain(state.fork, slot_to_epoch(proposer_slashing.proposal_1.slot), DOMAIN_PROPOSAL))`. +* Verify that `bls_verify(pubkey=proposer.pubkey, message_hash=signed_root(proposer_slashing.proposal_2, "signature"), signature=proposer_slashing.proposal_2.signature, domain=get_domain(state.fork, slot_to_epoch(proposer_slashing.proposal_2.slot), DOMAIN_PROPOSAL))`. * Run `slash_validator(state, proposer_slashing.proposer_index)`. ##### Attester slashings @@ -1777,13 +1758,7 @@ def verify_merkle_branch(leaf: Bytes32, branch: List[Bytes32], depth: int, index * Run the following: ```python -process_deposit( - state=state, - pubkey=deposit.deposit_data.deposit_input.pubkey, - amount=deposit.deposit_data.amount, - proof_of_possession=deposit.deposit_data.deposit_input.proof_of_possession, - withdrawal_credentials=deposit.deposit_data.deposit_input.withdrawal_credentials, -) +process_deposit(state, deposit) ``` * Set `state.deposit_index += 1`. @@ -1797,8 +1772,7 @@ For each `exit` in `block.body.voluntary_exits`: * Let `validator = state.validator_registry[exit.validator_index]`. * Verify that `validator.exit_epoch > get_entry_exit_effect_epoch(get_current_epoch(state))`. * Verify that `get_current_epoch(state) >= exit.epoch`. -* Let `exit_message = hash_tree_root(Exit(epoch=exit.epoch, validator_index=exit.validator_index, signature=EMPTY_SIGNATURE))`. -* Verify that `bls_verify(pubkey=validator.pubkey, message_hash=exit_message, signature=exit.signature, domain=get_domain(state.fork, exit.epoch, DOMAIN_EXIT))`. +* Verify that `bls_verify(pubkey=validator.pubkey, message_hash=signed_root(exit, "signature"), signature=exit.signature, domain=get_domain(state.fork, exit.epoch, DOMAIN_EXIT))`. * Run `initiate_validator_exit(state, exit.validator_index)`. ##### Transfers @@ -1815,8 +1789,7 @@ For each `transfer` in `block.body.transfers`: * Verify that `state.slot == transfer.slot`. * Verify that `get_current_epoch(state) >= state.validator_registry[transfer.from].withdrawable_epoch`. * Verify that `state.validator_registry[transfer.from].withdrawal_credentials == BLS_WITHDRAWAL_PREFIX_BYTE + hash(transfer.pubkey)[1:]`. -* Let `transfer_message = hash_tree_root(Transfer(from=transfer.from, to=transfer.to, amount=transfer.amount, fee=transfer.fee, slot=transfer.slot, signature=EMPTY_SIGNATURE))`. -* Verify that `bls_verify(pubkey=transfer.pubkey, message_hash=transfer_message, signature=transfer.signature, domain=get_domain(state.fork, slot_to_epoch(transfer.slot), DOMAIN_TRANSFER))`. +* Verify that `bls_verify(pubkey=transfer.pubkey, message_hash=signed_root(transfer, "signature"), signature=transfer.signature, domain=get_domain(state.fork, slot_to_epoch(transfer.slot), DOMAIN_TRANSFER))`. * Set `state.validator_balances[transfer.from] -= transfer.amount + transfer.fee`. * Set `state.validator_balances[transfer.to] += transfer.amount`. * Set `state.validator_balances[get_beacon_proposer_index(state, state.slot)] += transfer.fee`. From 888b06ce4a042c10c3c869f46759e0d685be74c8 Mon Sep 17 00:00:00 2001 From: Justin Date: Fri, 15 Feb 2019 00:24:46 +0000 Subject: [PATCH 2/3] 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 c38b237bc4..bc9e9bcfcd 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -471,7 +471,7 @@ The following data structures are defined as [SimpleSerialize (SSZ)](https://git ```python { # Header - 'slot': Slot, + 'slot': 'uint64', 'parent_root': 'bytes32', 'state_root': 'bytes32', 'randao_reveal': 'bytes96', From 2207fd17f5003f80fbebf6930dfd594c907dcbd0 Mon Sep 17 00:00:00 2001 From: Justin Date: Fri, 15 Feb 2019 13:37:36 +0000 Subject: [PATCH 3/3] Update 0_beacon-chain.md --- specs/core/0_beacon-chain.md | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index bc9e9bcfcd..782e7a72b9 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -44,7 +44,6 @@ - [`BeaconBlock`](#beaconblock) - [`BeaconBlockBody`](#beaconblockbody) - [`Proposal`](#proposal) - - [`RandaoReveal`](#randaoreveal) - [Beacon chain state](#beacon-chain-state) - [`BeaconState`](#beaconstate) - [`Validator`](#validator) @@ -512,17 +511,6 @@ The following data structures are defined as [SimpleSerialize (SSZ)](https://git } ``` -#### `RandaoReveal` - -```python -{ - # Epoch number - 'epoch': 'uint64', - # RANDAO reveal - 'randao_reveal': 'bytes96', -} -``` - ### Beacon chain state #### `BeaconState` @@ -1641,8 +1629,7 @@ Below are the processing steps that happen at every `block`. #### RANDAO -* Let `randao_reveal = RandaoReveal(epoch=get_current_epoch(state), randao_reveal=block.randao_reveal)`. -* Verify that `bls_verify(pubkey=proposer.pubkey, message_hash=signed_root(randao_reveal, "randao_reveal"), signature=randao_reveal.randao_reveal, domain=get_domain(state.fork, get_current_epoch(state), DOMAIN_RANDAO))`. +* Verify that `bls_verify(pubkey=proposer.pubkey, message_hash=hash_tree_root(get_current_epoch(state)), signature=block.randao_reveal, domain=get_domain(state.fork, get_current_epoch(state), DOMAIN_RANDAO))`. * Set `state.latest_randao_mixes[get_current_epoch(state) % LATEST_RANDAO_MIXES_LENGTH] = xor(get_randao_mix(state, get_current_epoch(state)), hash(block.randao_reveal))`. #### Eth1 data