Minor cosmetic cleanups

* remove `BLS_WITHDRAWAL_PREFIX` (it is not used in phase 1, not phase 0)
* avoid inline comment (# Validate state root)
* simplify header inequality check in `process_proposer_slashing` (using uniqueness of BLS signatures)
* add `block = signed_block.message` helper variable for readability
* (typo) clarify that the state transition function consumes a signed block (as opposed to a block)
* generally make comments more consistent
* consistent formatting of container instantiation for `DepositMessage`
* avoid using three lines for `rewards[index] += Gwei(max_attester_reward // attestation.inclusion_delay)`
* introduce `effective_balance` helper variable for readability, and to avoid multi-line statement
* consistent ordering of `MIN_EPOCHS_TO_INACTIVITY_PENALTY` in the time parameters table
* (typo) "Dequeued validators for activation up to churn limit" => Dequeue validators
* "Save current block as the new latest block" => "Cache current block" (for consistent with `process_slot`)
* (typo) "Verify the validator has not yet exited" => "Verify exit has not been initiated"
* Use Pythonic `default=` for `max()` call in `initiate_validator_exit`
This commit is contained in:
Justin 2019-12-15 11:10:43 +00:00 committed by GitHub
parent 88e954a9c7
commit 48317d8ac0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 30 additions and 34 deletions

View File

@ -199,7 +199,6 @@ The following values are (non-configurable) constants used throughout the specif
| - | - | | - | - |
| `GENESIS_SLOT` | `Slot(0)` | | `GENESIS_SLOT` | `Slot(0)` |
| `GENESIS_EPOCH` | `Epoch(0)` | | `GENESIS_EPOCH` | `Epoch(0)` |
| `BLS_WITHDRAWAL_PREFIX` | `Bytes1(b'\x00')` |
### Time parameters ### Time parameters
@ -210,11 +209,11 @@ The following values are (non-configurable) constants used throughout the specif
| `SLOTS_PER_EPOCH` | `2**5` (= 32) | slots | 6.4 minutes | | `SLOTS_PER_EPOCH` | `2**5` (= 32) | slots | 6.4 minutes |
| `MIN_SEED_LOOKAHEAD` | `2**0` (= 1) | epochs | 6.4 minutes | | `MIN_SEED_LOOKAHEAD` | `2**0` (= 1) | epochs | 6.4 minutes |
| `MAX_SEED_LOOKAHEAD` | `2**2` (= 4) | epochs | 25.6 minutes | | `MAX_SEED_LOOKAHEAD` | `2**2` (= 4) | epochs | 25.6 minutes |
| `MIN_EPOCHS_TO_INACTIVITY_PENALTY` | `2**2` (= 4) | epochs | 25.6 minutes |
| `SLOTS_PER_ETH1_VOTING_PERIOD` | `2**10` (= 1,024) | slots | ~3.4 hours | | `SLOTS_PER_ETH1_VOTING_PERIOD` | `2**10` (= 1,024) | slots | ~3.4 hours |
| `SLOTS_PER_HISTORICAL_ROOT` | `2**13` (= 8,192) | slots | ~27 hours | | `SLOTS_PER_HISTORICAL_ROOT` | `2**13` (= 8,192) | slots | ~27 hours |
| `MIN_VALIDATOR_WITHDRAWABILITY_DELAY` | `2**8` (= 256) | epochs | ~27 hours | | `MIN_VALIDATOR_WITHDRAWABILITY_DELAY` | `2**8` (= 256) | epochs | ~27 hours |
| `PERSISTENT_COMMITTEE_PERIOD` | `2**11` (= 2,048) | epochs | 9 days | | `PERSISTENT_COMMITTEE_PERIOD` | `2**11` (= 2,048) | epochs | 9 days |
| `MIN_EPOCHS_TO_INACTIVITY_PENALTY` | `2**2` (= 4) | epochs | 25.6 minutes |
### State list lengths ### State list lengths
@ -223,7 +222,7 @@ The following values are (non-configurable) constants used throughout the specif
| `EPOCHS_PER_HISTORICAL_VECTOR` | `2**16` (= 65,536) | epochs | ~0.8 years | | `EPOCHS_PER_HISTORICAL_VECTOR` | `2**16` (= 65,536) | epochs | ~0.8 years |
| `EPOCHS_PER_SLASHINGS_VECTOR` | `2**13` (= 8,192) | epochs | ~36 days | | `EPOCHS_PER_SLASHINGS_VECTOR` | `2**13` (= 8,192) | epochs | ~36 days |
| `HISTORICAL_ROOTS_LIMIT` | `2**24` (= 16,777,216) | historical roots | ~26,131 years | | `HISTORICAL_ROOTS_LIMIT` | `2**24` (= 16,777,216) | historical roots | ~26,131 years |
| `VALIDATOR_REGISTRY_LIMIT` | `2**40` (= 1,099,511,627,776) | validator spots | | `VALIDATOR_REGISTRY_LIMIT` | `2**40` (= 1,099,511,627,776) | validators |
### Rewards and penalties ### Rewards and penalties
@ -366,7 +365,7 @@ class DepositData(Container):
pubkey: BLSPubkey pubkey: BLSPubkey
withdrawal_credentials: Bytes32 withdrawal_credentials: Bytes32
amount: Gwei amount: Gwei
signature: BLSSignature # signing over DepositMessage signature: BLSSignature # Signing over DepositMessage
``` ```
#### `BeaconBlockHeader` #### `BeaconBlockHeader`
@ -411,7 +410,7 @@ class Attestation(Container):
```python ```python
class Deposit(Container): class Deposit(Container):
proof: Vector[Bytes32, DEPOSIT_CONTRACT_TREE_DEPTH + 1] # Merkle path to deposit data list root proof: Vector[Bytes32, DEPOSIT_CONTRACT_TREE_DEPTH + 1] # Merkle path to deposit root
data: DepositData data: DepositData
``` ```
@ -488,8 +487,6 @@ class BeaconState(Container):
### Signed envelopes ### Signed envelopes
Some messages in the protocol are wrapped in an envelope to better facilitate adding/pruning the signature and to `hash_tree_root` the `message` separate from the signature.
#### `SignedVoluntaryExit` #### `SignedVoluntaryExit`
```python ```python
@ -1016,7 +1013,7 @@ def initiate_validator_exit(state: BeaconState, index: ValidatorIndex) -> None:
# Compute exit queue epoch # Compute exit queue epoch
exit_epochs = [v.exit_epoch for v in state.validators if v.exit_epoch != FAR_FUTURE_EPOCH] exit_epochs = [v.exit_epoch for v in state.validators if v.exit_epoch != FAR_FUTURE_EPOCH]
exit_queue_epoch = max(exit_epochs + [compute_activation_exit_epoch(get_current_epoch(state))]) exit_queue_epoch = max(exit_epochs, default=compute_activation_exit_epoch(get_current_epoch(state)))
exit_queue_churn = len([v for v in state.validators if v.exit_epoch == exit_queue_epoch]) exit_queue_churn = len([v for v in state.validators if v.exit_epoch == exit_queue_epoch])
if exit_queue_churn >= get_validator_churn_limit(state): if exit_queue_churn >= get_validator_churn_limit(state):
exit_queue_epoch += Epoch(1) exit_queue_epoch += Epoch(1)
@ -1111,19 +1108,21 @@ Let `genesis_block = BeaconBlock(state_root=hash_tree_root(genesis_state))`.
## Beacon chain state transition function ## Beacon chain state transition function
The post-state corresponding to a pre-state `state` and a block `block` is defined as `state_transition(state, block)`. State transitions that trigger an unhandled exception (e.g. a failed `assert` or an out-of-range list access) are considered invalid. The post-state corresponding to a pre-state `state` and a signed block `signed_block` is defined as `state_transition(state, signed_block)`. State transitions that trigger an unhandled exception (e.g. a failed `assert` or an out-of-range list access) are considered invalid.
```python ```python
def state_transition(state: BeaconState, signed_block: SignedBeaconBlock, validate_result: bool=True) -> BeaconState: def state_transition(state: BeaconState, signed_block: SignedBeaconBlock, validate_result: bool=True) -> BeaconState:
block = signed_block.message
# Process slots (including those with no blocks) since block # Process slots (including those with no blocks) since block
process_slots(state, signed_block.message.slot) process_slots(state, block.slot)
# Verify signature # Verify signature
if validate_result: if validate_result:
assert verify_block_signature(state, signed_block) assert verify_block_signature(state, signed_block)
# Process block # Process block
process_block(state, signed_block.message) process_block(state, block)
# Verify state root
if validate_result: if validate_result:
assert signed_block.message.state_root == hash_tree_root(state) # Validate state root assert block.state_root == hash_tree_root(state)
# Return post-state # Return post-state
return state return state
``` ```
@ -1299,9 +1298,7 @@ def get_attestation_deltas(state: BeaconState) -> Tuple[Sequence[Gwei], Sequence
proposer_reward = Gwei(get_base_reward(state, index) // PROPOSER_REWARD_QUOTIENT) proposer_reward = Gwei(get_base_reward(state, index) // PROPOSER_REWARD_QUOTIENT)
rewards[attestation.proposer_index] += proposer_reward rewards[attestation.proposer_index] += proposer_reward
max_attester_reward = get_base_reward(state, index) - proposer_reward max_attester_reward = get_base_reward(state, index) - proposer_reward
rewards[index] += Gwei( rewards[index] += Gwei(max_attester_reward // attestation.inclusion_delay)
max_attester_reward // attestation.inclusion_delay
)
# Inactivity penalty # Inactivity penalty
finality_delay = previous_epoch - state.finalized_checkpoint.epoch finality_delay = previous_epoch - state.finalized_checkpoint.epoch
@ -1310,9 +1307,8 @@ def get_attestation_deltas(state: BeaconState) -> Tuple[Sequence[Gwei], Sequence
for index in eligible_validator_indices: for index in eligible_validator_indices:
penalties[index] += Gwei(BASE_REWARDS_PER_EPOCH * get_base_reward(state, index)) penalties[index] += Gwei(BASE_REWARDS_PER_EPOCH * get_base_reward(state, index))
if index not in matching_target_attesting_indices: if index not in matching_target_attesting_indices:
penalties[index] += Gwei( effective_balance = state.validators[index].effective_balance
state.validators[index].effective_balance * finality_delay // INACTIVITY_PENALTY_QUOTIENT penalties[index] += Gwei(effective_balance * finality_delay // INACTIVITY_PENALTY_QUOTIENT)
)
return rewards, penalties return rewards, penalties
``` ```
@ -1412,13 +1408,14 @@ def process_block_header(state: BeaconState, block: BeaconBlock) -> None:
assert block.slot == state.slot assert block.slot == state.slot
# Verify that the parent matches # Verify that the parent matches
assert block.parent_root == hash_tree_root(state.latest_block_header) assert block.parent_root == hash_tree_root(state.latest_block_header)
# Save current block as the new latest block # Cache current block as the new latest block
state.latest_block_header = BeaconBlockHeader( state.latest_block_header = BeaconBlockHeader(
slot=block.slot, slot=block.slot,
parent_root=block.parent_root, parent_root=block.parent_root,
# `state_root` is zeroed and overwritten in the next `process_slot` call state_root=Bytes32(), # Overwritten in the next process_slot call
body_root=hash_tree_root(block.body), body_root=hash_tree_root(block.body),
) )
# Verify proposer is not slashed # Verify proposer is not slashed
proposer = state.validators[get_beacon_proposer_index(state)] proposer = state.validators[get_beacon_proposer_index(state)]
assert not proposer.slashed assert not proposer.slashed
@ -1469,14 +1466,14 @@ def process_operations(state: BeaconState, body: BeaconBlockBody) -> None:
```python ```python
def process_proposer_slashing(state: BeaconState, proposer_slashing: ProposerSlashing) -> None: def process_proposer_slashing(state: BeaconState, proposer_slashing: ProposerSlashing) -> None:
proposer = state.validators[proposer_slashing.proposer_index] # Verify header slots match
# Verify slots match
assert proposer_slashing.signed_header_1.message.slot == proposer_slashing.signed_header_2.message.slot assert proposer_slashing.signed_header_1.message.slot == proposer_slashing.signed_header_2.message.slot
# But the headers are different # Verify the headers are different
assert proposer_slashing.signed_header_1.message != proposer_slashing.signed_header_2.message assert proposer_slashing.signed_header_1 != proposer_slashing.signed_header_2
# Check proposer is slashable # Verify the proposer is slashable
proposer = state.validators[proposer_slashing.proposer_index]
assert is_slashable_validator(proposer, get_current_epoch(state)) assert is_slashable_validator(proposer, get_current_epoch(state))
# Signatures are valid # Verify signatures
for signed_header in (proposer_slashing.signed_header_1, proposer_slashing.signed_header_2): for signed_header in (proposer_slashing.signed_header_1, proposer_slashing.signed_header_2):
domain = get_domain(state, DOMAIN_BEACON_PROPOSER, compute_epoch_at_slot(signed_header.message.slot)) domain = get_domain(state, DOMAIN_BEACON_PROPOSER, compute_epoch_at_slot(signed_header.message.slot))
assert bls_verify(proposer.pubkey, hash_tree_root(signed_header.message), signed_header.signature, domain) assert bls_verify(proposer.pubkey, hash_tree_root(signed_header.message), signed_header.signature, domain)
@ -1530,7 +1527,7 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None:
assert data.source == state.previous_justified_checkpoint assert data.source == state.previous_justified_checkpoint
state.previous_epoch_attestations.append(pending_attestation) state.previous_epoch_attestations.append(pending_attestation)
# Check signature # Verify signature
assert is_valid_indexed_attestation(state, get_indexed_attestation(state, attestation)) assert is_valid_indexed_attestation(state, get_indexed_attestation(state, attestation))
``` ```
@ -1542,7 +1539,7 @@ def process_deposit(state: BeaconState, deposit: Deposit) -> None:
assert is_valid_merkle_branch( assert is_valid_merkle_branch(
leaf=hash_tree_root(deposit.data), leaf=hash_tree_root(deposit.data),
branch=deposit.proof, branch=deposit.proof,
depth=DEPOSIT_CONTRACT_TREE_DEPTH + 1, # Add 1 for the `List` length mix-in depth=DEPOSIT_CONTRACT_TREE_DEPTH + 1, # Add 1 for the List length mix-in
index=state.eth1_deposit_index, index=state.eth1_deposit_index,
root=state.eth1_data.deposit_root, root=state.eth1_data.deposit_root,
) )
@ -1554,14 +1551,13 @@ def process_deposit(state: BeaconState, deposit: Deposit) -> None:
amount = deposit.data.amount amount = deposit.data.amount
validator_pubkeys = [v.pubkey for v in state.validators] validator_pubkeys = [v.pubkey for v in state.validators]
if pubkey not in validator_pubkeys: if pubkey not in validator_pubkeys:
# Verify the deposit signature (proof of possession) for new validators. # Verify the deposit signature (proof of possession) which is not checked by the deposit contract
# Note: The deposit contract does not check signatures.
# Note: Deposits are valid across forks, thus the deposit domain is retrieved directly from `compute_domain`.
domain = compute_domain(DOMAIN_DEPOSIT)
deposit_message = DepositMessage( deposit_message = DepositMessage(
pubkey=deposit.data.pubkey, pubkey=deposit.data.pubkey,
withdrawal_credentials=deposit.data.withdrawal_credentials, withdrawal_credentials=deposit.data.withdrawal_credentials,
amount=deposit.data.amount) amount=deposit.data.amount,
)
domain = compute_domain(DOMAIN_DEPOSIT) # Fork-agnostic domain since deposits are valid across forks
if not bls_verify(pubkey, hash_tree_root(deposit_message), deposit.data.signature, domain): if not bls_verify(pubkey, hash_tree_root(deposit_message), deposit.data.signature, domain):
return return
@ -1590,7 +1586,7 @@ def process_voluntary_exit(state: BeaconState, signed_voluntary_exit: SignedVolu
validator = state.validators[voluntary_exit.validator_index] validator = state.validators[voluntary_exit.validator_index]
# Verify the validator is active # Verify the validator is active
assert is_active_validator(validator, get_current_epoch(state)) assert is_active_validator(validator, get_current_epoch(state))
# Verify the validator has not yet exited # Verify exit has not been initiated
assert validator.exit_epoch == FAR_FUTURE_EPOCH assert validator.exit_epoch == FAR_FUTURE_EPOCH
# Exits must specify an epoch when they become valid; they are not valid before then # Exits must specify an epoch when they become valid; they are not valid before then
assert get_current_epoch(state) >= voluntary_exit.epoch assert get_current_epoch(state) >= voluntary_exit.epoch