Merge pull request #1522 from ethereum/master

backport v093 to dev
This commit is contained in:
Diederik Loerakker 2019-12-13 18:56:31 +01:00 committed by GitHub
commit 88e954a9c7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 1038 additions and 420 deletions

View File

@ -103,6 +103,15 @@ jobs:
command: make citest
- store_test_results:
path: test_libs/pyspec/test-reports
table_of_contents:
docker:
- image: circleci/node:10.16.3
working_directory: ~/specs-repo
steps:
- checkout
- run:
name: Check table of contents
command: sudo npm install -g doctoc && make check_toc
lint:
docker:
- image: circleci/python:3.6
@ -148,6 +157,7 @@ workflows:
- test:
requires:
- install_pyspec_test
- table_of_contents
- lint:
requires:
- test

View File

@ -17,18 +17,22 @@ GENERATOR_VENVS = $(patsubst $(GENERATOR_DIR)/%, $(GENERATOR_DIR)/%venv, $(GENER
#$(info $$GENERATOR_TARGETS is [${GENERATOR_TARGETS}])
PY_SPEC_PHASE_0_TARGETS = $(PY_SPEC_DIR)/eth2spec/phase0/spec.py
PY_SPEC_PHASE_0_DEPS = $(SPEC_DIR)/core/0_*.md
PY_SPEC_PHASE_0_DEPS = $(wildcard $(SPEC_DIR)/core/0_*.md)
PY_SPEC_PHASE_1_TARGETS = $(PY_SPEC_DIR)/eth2spec/phase1/spec.py
PY_SPEC_PHASE_1_DEPS = $(SPEC_DIR)/core/1_*.md
PY_SPEC_PHASE_1_DEPS = $(wildcard $(SPEC_DIR)/core/1_*.md)
PY_SPEC_ALL_DEPS = $(PY_SPEC_PHASE_0_DEPS) $(PY_SPEC_PHASE_1_DEPS)
PY_SPEC_ALL_TARGETS = $(PY_SPEC_PHASE_0_TARGETS) $(PY_SPEC_PHASE_1_TARGETS)
MARKDOWN_FILES = $(PY_SPEC_ALL_DEPS) $(wildcard $(SPEC_DIR)/*.md) $(wildcard $(SPEC_DIR)/light_client/*.md) $(wildcard $(SPEC_DIR)/networking/*.md) $(wildcard $(SPEC_DIR)/validator/*.md)
COV_HTML_OUT=.htmlcov
COV_INDEX_FILE=$(PY_SPEC_DIR)/$(COV_HTML_OUT)/index.html
.PHONY: clean partial_clean all test citest lint generate_tests pyspec phase0 phase1 install_test open_cov \
install_deposit_contract_test test_deposit_contract compile_deposit_contract
install_deposit_contract_test test_deposit_contract compile_deposit_contract check_toc
all: $(PY_SPEC_ALL_TARGETS)
@ -65,6 +69,14 @@ citest: $(PY_SPEC_ALL_TARGETS)
open_cov:
((open "$(COV_INDEX_FILE)" || xdg-open "$(COV_INDEX_FILE)") &> /dev/null) &
check_toc: $(MARKDOWN_FILES:=.toc)
%.toc:
cp $* $*.tmp && \
doctoc $* && \
diff -q $* $*.tmp && \
rm $*.tmp
lint: $(PY_SPEC_ALL_TARGETS)
cd $(PY_SPEC_DIR); . venv/bin/activate; \
flake8 --ignore=E252,W504,W503 --max-line-length=120 ./eth2spec \

View File

@ -82,7 +82,7 @@ def get_eth1_data(distance: uint64) -> Bytes32:
return hash(distance)
def hash(x: bytes) -> Bytes32:
def hash(x: bytes) -> Bytes32: # type: ignore
if x not in hash_cache:
hash_cache[x] = Bytes32(_hash(x))
return hash_cache[x]

View File

@ -6,23 +6,25 @@
## Table of contents
<!-- TOC -->
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
- [BLS signature verification](#bls-signature-verification)
- [Table of contents](#table-of-contents)
- [Curve parameters](#curve-parameters)
- [Point representations](#point-representations)
- [G1 points](#g1-points)
- [G2 points](#g2-points)
- [Helpers](#helpers)
- [`hash_to_G2`](#hash_to_g2)
- [`modular_squareroot`](#modular_squareroot)
- [Aggregation operations](#aggregation-operations)
- [`bls_aggregate_pubkeys`](#bls_aggregate_pubkeys)
- [`bls_aggregate_signatures`](#bls_aggregate_signatures)
- [Signature verification](#signature-verification)
- [`bls_verify`](#bls_verify)
- [`bls_verify_multiple`](#bls_verify_multiple)
- [Curve parameters](#curve-parameters)
- [Point representations](#point-representations)
- [G1 points](#g1-points)
- [G2 points](#g2-points)
- [Helpers](#helpers)
- [`hash_to_G2`](#hash_to_g2)
- [`modular_squareroot`](#modular_squareroot)
- [Aggregation operations](#aggregation-operations)
- [`bls_aggregate_pubkeys`](#bls_aggregate_pubkeys)
- [`bls_aggregate_signatures`](#bls_aggregate_signatures)
- [Signature verification](#signature-verification)
- [`bls_verify`](#bls_verify)
- [`bls_verify_multiple`](#bls_verify_multiple)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
<!-- /TOC -->
## Curve parameters

View File

@ -4,119 +4,123 @@
## Table of contents
<!-- TOC -->
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
- [Ethereum 2.0 Phase 0 -- The Beacon Chain](#ethereum-20-phase-0----the-beacon-chain)
- [Table of contents](#table-of-contents)
- [Introduction](#introduction)
- [Notation](#notation)
- [Custom types](#custom-types)
- [Constants](#constants)
- [Configuration](#configuration)
- [Misc](#misc)
- [Gwei values](#gwei-values)
- [Initial values](#initial-values)
- [Time parameters](#time-parameters)
- [State list lengths](#state-list-lengths)
- [Rewards and penalties](#rewards-and-penalties)
- [Max operations per block](#max-operations-per-block)
- [Domain types](#domain-types)
- [Containers](#containers)
- [Misc dependencies](#misc-dependencies)
- [`Fork`](#fork)
- [`Checkpoint`](#checkpoint)
- [`Validator`](#validator)
- [`AttestationData`](#attestationdata)
- [`IndexedAttestation`](#indexedattestation)
- [`PendingAttestation`](#pendingattestation)
- [`Eth1Data`](#eth1data)
- [`HistoricalBatch`](#historicalbatch)
- [`DepositMessage`](#depositmessage)
- [`DepositData`](#depositdata)
- [`BeaconBlockHeader`](#beaconblockheader)
- [Beacon operations](#beacon-operations)
- [`ProposerSlashing`](#proposerslashing)
- [`AttesterSlashing`](#attesterslashing)
- [`Attestation`](#attestation)
- [`Deposit`](#deposit)
- [`VoluntaryExit`](#voluntaryexit)
- [Beacon blocks](#beacon-blocks)
- [`BeaconBlockBody`](#beaconblockbody)
- [`BeaconBlock`](#beaconblock)
- [Beacon state](#beacon-state)
- [`BeaconState`](#beaconstate)
- [Signed envelopes](#signed-envelopes)
- [`SignedVoluntaryExit`](#signedvoluntaryexit)
- [`SignedBeaconBlock`](#signedbeaconblock)
- [`SignedBeaconBlockHeader`](#signedbeaconblockheader)
- [Helper functions](#helper-functions)
- [Math](#math)
- [`integer_squareroot`](#integer_squareroot)
- [`xor`](#xor)
- [`int_to_bytes`](#int_to_bytes)
- [`bytes_to_int`](#bytes_to_int)
- [Crypto](#crypto)
- [`hash`](#hash)
- [`hash_tree_root`](#hash_tree_root)
- [`bls_verify`](#bls_verify)
- [`bls_aggregate_pubkeys`](#bls_aggregate_pubkeys)
- [Predicates](#predicates)
- [`is_active_validator`](#is_active_validator)
- [`is_slashable_validator`](#is_slashable_validator)
- [`is_slashable_attestation_data`](#is_slashable_attestation_data)
- [`is_valid_indexed_attestation`](#is_valid_indexed_attestation)
- [`is_valid_merkle_branch`](#is_valid_merkle_branch)
- [Misc](#misc-1)
- [`compute_shuffled_index`](#compute_shuffled_index)
- [`compute_proposer_index`](#compute_proposer_index)
- [`compute_committee`](#compute_committee)
- [`compute_epoch_at_slot`](#compute_epoch_at_slot)
- [`compute_start_slot_at_epoch`](#compute_start_slot_at_epoch)
- [`compute_activation_exit_epoch`](#compute_activation_exit_epoch)
- [`compute_domain`](#compute_domain)
- [Beacon state accessors](#beacon-state-accessors)
- [`get_current_epoch`](#get_current_epoch)
- [`get_previous_epoch`](#get_previous_epoch)
- [`get_block_root`](#get_block_root)
- [`get_block_root_at_slot`](#get_block_root_at_slot)
- [`get_randao_mix`](#get_randao_mix)
- [`get_active_validator_indices`](#get_active_validator_indices)
- [`get_validator_churn_limit`](#get_validator_churn_limit)
- [`get_seed`](#get_seed)
- [`get_committee_count_at_slot`](#get_committee_count_at_slot)
- [`get_beacon_committee`](#get_beacon_committee)
- [`get_beacon_proposer_index`](#get_beacon_proposer_index)
- [`get_total_balance`](#get_total_balance)
- [`get_total_active_balance`](#get_total_active_balance)
- [`get_domain`](#get_domain)
- [`get_indexed_attestation`](#get_indexed_attestation)
- [`get_attesting_indices`](#get_attesting_indices)
- [Beacon state mutators](#beacon-state-mutators)
- [`increase_balance`](#increase_balance)
- [`decrease_balance`](#decrease_balance)
- [`initiate_validator_exit`](#initiate_validator_exit)
- [`slash_validator`](#slash_validator)
- [Genesis](#genesis)
- [Genesis state](#genesis-state)
- [Genesis block](#genesis-block)
- [Beacon chain state transition function](#beacon-chain-state-transition-function)
- [Epoch processing](#epoch-processing)
- [Helper functions](#helper-functions-1)
- [Justification and finalization](#justification-and-finalization)
- [Rewards and penalties](#rewards-and-penalties-1)
- [Registry updates](#registry-updates)
- [Slashings](#slashings)
- [Final updates](#final-updates)
- [Block processing](#block-processing)
- [Block header](#block-header)
- [RANDAO](#randao)
- [Eth1 data](#eth1-data)
- [Operations](#operations)
- [Proposer slashings](#proposer-slashings)
- [Attester slashings](#attester-slashings)
- [Attestations](#attestations)
- [Deposits](#deposits)
- [Voluntary exits](#voluntary-exits)
- [Introduction](#introduction)
- [Notation](#notation)
- [Custom types](#custom-types)
- [Constants](#constants)
- [Configuration](#configuration)
- [Misc](#misc)
- [Gwei values](#gwei-values)
- [Initial values](#initial-values)
- [Time parameters](#time-parameters)
- [State list lengths](#state-list-lengths)
- [Rewards and penalties](#rewards-and-penalties)
- [Max operations per block](#max-operations-per-block)
- [Domain types](#domain-types)
- [Containers](#containers)
- [Misc dependencies](#misc-dependencies)
- [`Fork`](#fork)
- [`Checkpoint`](#checkpoint)
- [`Validator`](#validator)
- [`AttestationData`](#attestationdata)
- [`IndexedAttestation`](#indexedattestation)
- [`PendingAttestation`](#pendingattestation)
- [`Eth1Data`](#eth1data)
- [`HistoricalBatch`](#historicalbatch)
- [`DepositMessage`](#depositmessage)
- [`DepositData`](#depositdata)
- [`BeaconBlockHeader`](#beaconblockheader)
- [Beacon operations](#beacon-operations)
- [`ProposerSlashing`](#proposerslashing)
- [`AttesterSlashing`](#attesterslashing)
- [`Attestation`](#attestation)
- [`Deposit`](#deposit)
- [`VoluntaryExit`](#voluntaryexit)
- [Beacon blocks](#beacon-blocks)
- [`BeaconBlockBody`](#beaconblockbody)
- [`BeaconBlock`](#beaconblock)
- [Beacon state](#beacon-state)
- [`BeaconState`](#beaconstate)
- [Signed envelopes](#signed-envelopes)
- [`SignedVoluntaryExit`](#signedvoluntaryexit)
- [`SignedBeaconBlock`](#signedbeaconblock)
- [`SignedBeaconBlockHeader`](#signedbeaconblockheader)
- [Helper functions](#helper-functions)
- [Math](#math)
- [`integer_squareroot`](#integer_squareroot)
- [`xor`](#xor)
- [`int_to_bytes`](#int_to_bytes)
- [`bytes_to_int`](#bytes_to_int)
- [Crypto](#crypto)
- [`hash`](#hash)
- [`hash_tree_root`](#hash_tree_root)
- [`bls_verify`](#bls_verify)
- [`bls_aggregate_pubkeys`](#bls_aggregate_pubkeys)
- [Predicates](#predicates)
- [`is_active_validator`](#is_active_validator)
- [`is_eligible_for_activation_queue`](#is_eligible_for_activation_queue)
- [`is_eligible_for_activation`](#is_eligible_for_activation)
- [`is_slashable_validator`](#is_slashable_validator)
- [`is_slashable_attestation_data`](#is_slashable_attestation_data)
- [`is_valid_indexed_attestation`](#is_valid_indexed_attestation)
- [`is_valid_merkle_branch`](#is_valid_merkle_branch)
- [Misc](#misc-1)
- [`compute_shuffled_index`](#compute_shuffled_index)
- [`compute_proposer_index`](#compute_proposer_index)
- [`compute_committee`](#compute_committee)
- [`compute_epoch_at_slot`](#compute_epoch_at_slot)
- [`compute_start_slot_at_epoch`](#compute_start_slot_at_epoch)
- [`compute_activation_exit_epoch`](#compute_activation_exit_epoch)
- [`compute_domain`](#compute_domain)
- [Beacon state accessors](#beacon-state-accessors)
- [`get_current_epoch`](#get_current_epoch)
- [`get_previous_epoch`](#get_previous_epoch)
- [`get_block_root`](#get_block_root)
- [`get_block_root_at_slot`](#get_block_root_at_slot)
- [`get_randao_mix`](#get_randao_mix)
- [`get_active_validator_indices`](#get_active_validator_indices)
- [`get_validator_churn_limit`](#get_validator_churn_limit)
- [`get_seed`](#get_seed)
- [`get_committee_count_at_slot`](#get_committee_count_at_slot)
- [`get_beacon_committee`](#get_beacon_committee)
- [`get_beacon_proposer_index`](#get_beacon_proposer_index)
- [`get_total_balance`](#get_total_balance)
- [`get_total_active_balance`](#get_total_active_balance)
- [`get_domain`](#get_domain)
- [`get_indexed_attestation`](#get_indexed_attestation)
- [`get_attesting_indices`](#get_attesting_indices)
- [Beacon state mutators](#beacon-state-mutators)
- [`increase_balance`](#increase_balance)
- [`decrease_balance`](#decrease_balance)
- [`initiate_validator_exit`](#initiate_validator_exit)
- [`slash_validator`](#slash_validator)
- [Genesis](#genesis)
- [Genesis state](#genesis-state)
- [Genesis block](#genesis-block)
- [Beacon chain state transition function](#beacon-chain-state-transition-function)
- [Epoch processing](#epoch-processing)
- [Helper functions](#helper-functions-1)
- [Justification and finalization](#justification-and-finalization)
- [Rewards and penalties](#rewards-and-penalties-1)
- [Registry updates](#registry-updates)
- [Slashings](#slashings)
- [Final updates](#final-updates)
- [Block processing](#block-processing)
- [Block header](#block-header)
- [RANDAO](#randao)
- [Eth1 data](#eth1-data)
- [Operations](#operations)
- [Proposer slashings](#proposer-slashings)
- [Attester slashings](#attester-slashings)
- [Attestations](#attestations)
- [Deposits](#deposits)
- [Voluntary exits](#voluntary-exits)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
<!-- /TOC -->
## Introduction
@ -484,7 +488,7 @@ class BeaconState(Container):
### Signed envelopes
Some messages in the protocol are wrapped in an envelop to better facilitate adding/pruning the signature and to `hash_tree_root` the `message` separate from the signature.
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`
@ -591,6 +595,34 @@ def is_active_validator(validator: Validator, epoch: Epoch) -> bool:
return validator.activation_epoch <= epoch < validator.exit_epoch
```
#### `is_eligible_for_activation_queue`
```python
def is_eligible_for_activation_queue(validator: Validator) -> bool:
"""
Check if ``validator`` is eligible to be placed into the activation queue.
"""
return (
validator.activation_eligibility_epoch == FAR_FUTURE_EPOCH
and validator.effective_balance == MAX_EFFECTIVE_BALANCE
)
```
#### `is_eligible_for_activation`
```python
def is_eligible_for_activation(state: BeaconState, validator: Validator) -> bool:
"""
Check if ``validator`` is eligible for activation.
"""
return (
# Placement in queue is finalized
validator.activation_eligibility_epoch <= state.finalized_checkpoint.epoch
# Has not yet been activated
and validator.activation_epoch == FAR_FUTURE_EPOCH
)
```
#### `is_slashable_validator`
```python
@ -628,8 +660,8 @@ def is_valid_indexed_attestation(state: BeaconState, indexed_attestation: Indexe
# Verify max number of indices
if not len(indices) <= MAX_VALIDATORS_PER_COMMITTEE:
return False
# Verify indices are sorted
if not indices == sorted(indices):
# Verify indices are sorted and unique
if not indices == sorted(set(indices)):
return False
# Verify aggregate signature
if not bls_verify(
@ -1302,26 +1334,22 @@ def process_rewards_and_penalties(state: BeaconState) -> None:
def process_registry_updates(state: BeaconState) -> None:
# Process activation eligibility and ejections
for index, validator in enumerate(state.validators):
if (
validator.activation_eligibility_epoch == FAR_FUTURE_EPOCH
and validator.effective_balance == MAX_EFFECTIVE_BALANCE
):
validator.activation_eligibility_epoch = get_current_epoch(state)
if is_eligible_for_activation_queue(validator):
validator.activation_eligibility_epoch = get_current_epoch(state) + 1
if is_active_validator(validator, get_current_epoch(state)) and validator.effective_balance <= EJECTION_BALANCE:
initiate_validator_exit(state, ValidatorIndex(index))
# Queue validators eligible for activation and not dequeued for activation prior to finalized epoch
# Queue validators eligible for activation and not yet dequeued for activation
activation_queue = sorted([
index for index, validator in enumerate(state.validators)
if validator.activation_eligibility_epoch != FAR_FUTURE_EPOCH
and validator.activation_epoch >= compute_activation_exit_epoch(state.finalized_checkpoint.epoch)
], key=lambda index: state.validators[index].activation_eligibility_epoch)
# Dequeued validators for activation up to churn limit (without resetting activation epoch)
if is_eligible_for_activation(state, validator)
# Order by the sequence of activation_eligibility_epoch setting and then index
], key=lambda index: (state.validators[index].activation_eligibility_epoch, index))
# Dequeued validators for activation up to churn limit
for index in activation_queue[:get_validator_churn_limit(state)]:
validator = state.validators[index]
if validator.activation_epoch == FAR_FUTURE_EPOCH:
validator.activation_epoch = compute_activation_exit_epoch(get_current_epoch(state))
validator.activation_epoch = compute_activation_exit_epoch(get_current_epoch(state))
```
#### Slashings
@ -1482,6 +1510,7 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None:
data = attestation.data
assert data.index < get_committee_count_at_slot(state, data.slot)
assert data.target.epoch in (get_previous_epoch(state), get_current_epoch(state))
assert data.target.epoch == compute_epoch_at_slot(data.slot)
assert data.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot <= data.slot + SLOTS_PER_EPOCH
committee = get_beacon_committee(state, data.slot, data.index)

View File

@ -4,19 +4,21 @@
## Table of contents
<!-- TOC -->
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
- [Ethereum 2.0 Phase 0 -- Deposit Contract](#ethereum-20-phase-0----deposit-contract)
- [Table of contents](#table-of-contents)
- [Introduction](#introduction)
- [Constants](#constants)
- [Contract](#contract)
- [Ethereum 1.0 deposit contract](#ethereum-10-deposit-contract)
- [`deposit` function](#deposit-function)
- [Deposit amount](#deposit-amount)
- [Withdrawal credentials](#withdrawal-credentials)
- [`DepositEvent` log](#depositevent-log)
- [Vyper code](#vyper-code)
- [Introduction](#introduction)
- [Constants](#constants)
- [Contract](#contract)
- [Ethereum 1.0 deposit contract](#ethereum-10-deposit-contract)
- [`deposit` function](#deposit-function)
- [Deposit amount](#deposit-amount)
- [Withdrawal credentials](#withdrawal-credentials)
- [`DepositEvent` log](#depositevent-log)
- [Vyper code](#vyper-code)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
<!-- /TOC -->
## Introduction

View File

@ -4,23 +4,32 @@
## Table of contents
<!-- TOC -->
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
- [Ethereum 2.0 Phase 0 -- Beacon Chain Fork Choice](#ethereum-20-phase-0----beacon-chain-fork-choice)
- [Table of contents](#table-of-contents)
- [Introduction](#introduction)
- [Fork choice](#fork-choice)
- [Helpers](#helpers)
- [`LatestMessage`](#latestmessage)
- [`Store`](#store)
- [`get_genesis_store`](#get_genesis_store)
- [`get_ancestor`](#get_ancestor)
- [`get_latest_attesting_balance`](#get_latest_attesting_balance)
- [`get_head`](#get_head)
- [Handlers](#handlers)
- [`on_tick`](#on_tick)
- [`on_block`](#on_block)
- [`on_attestation`](#on_attestation)
- [Introduction](#introduction)
- [Fork choice](#fork-choice)
- [Configuration](#configuration)
- [Helpers](#helpers)
- [`LatestMessage`](#latestmessage)
- [`Store`](#store)
- [`get_genesis_store`](#get_genesis_store)
- [`get_slots_since_genesis`](#get_slots_since_genesis)
- [`get_current_slot`](#get_current_slot)
- [`compute_slots_since_epoch_start`](#compute_slots_since_epoch_start)
- [`get_ancestor`](#get_ancestor)
- [`get_latest_attesting_balance`](#get_latest_attesting_balance)
- [`filter_block_tree`](#filter_block_tree)
- [`get_filtered_block_tree`](#get_filtered_block_tree)
- [`get_head`](#get_head)
- [`should_update_justified_checkpoint`](#should_update_justified_checkpoint)
- [Handlers](#handlers)
- [`on_tick`](#on_tick)
- [`on_block`](#on_block)
- [`on_attestation`](#on_attestation)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
<!-- /TOC -->
## Introduction
@ -96,11 +105,18 @@ def get_genesis_store(genesis_state: BeaconState) -> Store:
)
```
#### `get_slots_since_genesis`
```python
def get_slots_since_genesis(store: Store) -> int:
return (store.time - store.genesis_time) // SECONDS_PER_SLOT
```
#### `get_current_slot`
```python
def get_current_slot(store: Store) -> Slot:
return Slot((store.time - store.genesis_time) // SECONDS_PER_SLOT)
return Slot(GENESIS_SLOT + get_slots_since_genesis(store))
```
#### `compute_slots_since_epoch_start`
@ -136,17 +152,72 @@ def get_latest_attesting_balance(store: Store, root: Root) -> Gwei:
))
```
#### `filter_block_tree`
```python
def filter_block_tree(store: Store, block_root: Root, blocks: Dict[Root, BeaconBlock]) -> bool:
block = store.blocks[block_root]
children = [
root for root in store.blocks.keys()
if store.blocks[root].parent_root == block_root
]
# If any children branches contain expected finalized/justified checkpoints,
# add to filtered block-tree and signal viability to parent.
if any(children):
filter_block_tree_result = [filter_block_tree(store, child, blocks) for child in children]
if any(filter_block_tree_result):
blocks[block_root] = block
return True
return False
# If leaf block, check finalized/justified checkpoints as matching latest.
head_state = store.block_states[block_root]
correct_justified = (
store.justified_checkpoint.epoch == GENESIS_EPOCH
or head_state.current_justified_checkpoint == store.justified_checkpoint
)
correct_finalized = (
store.finalized_checkpoint.epoch == GENESIS_EPOCH
or head_state.finalized_checkpoint == store.finalized_checkpoint
)
# If expected finalized/justified, add to viable block-tree and signal viability to parent.
if correct_justified and correct_finalized:
blocks[block_root] = block
return True
# Otherwise, branch not viable
return False
```
#### `get_filtered_block_tree`
```python
def get_filtered_block_tree(store: Store) -> Dict[Root, BeaconBlock]:
"""
Retrieve a filtered block true from ``store``, only returning branches
whose leaf state's justified/finalized info agrees with that in ``store``.
"""
base = store.justified_checkpoint.root
blocks: Dict[Root, BeaconBlock] = {}
filter_block_tree(store, base, blocks)
return blocks
```
#### `get_head`
```python
def get_head(store: Store) -> Root:
# Get filtered block tree that only includes viable branches
blocks = get_filtered_block_tree(store)
# Execute the LMD-GHOST fork choice
head = store.justified_checkpoint.root
justified_slot = compute_start_slot_at_epoch(store.justified_checkpoint.epoch)
while True:
children = [
root for root in store.blocks.keys()
if store.blocks[root].parent_root == head and store.blocks[root].slot > justified_slot
root for root in blocks.keys()
if blocks[root].parent_root == head and blocks[root].slot > justified_slot
]
if len(children) == 0:
return head
@ -172,8 +243,8 @@ def should_update_justified_checkpoint(store: Store, new_justified_checkpoint: C
if new_justified_block.slot <= compute_start_slot_at_epoch(store.justified_checkpoint.epoch):
return False
if not (
get_ancestor(store, new_justified_checkpoint.root, store.blocks[store.justified_checkpoint.root].slot) ==
store.justified_checkpoint.root
get_ancestor(store, new_justified_checkpoint.root, store.blocks[store.justified_checkpoint.root].slot)
== store.justified_checkpoint.root
):
return False
@ -209,7 +280,7 @@ def on_block(store: Store, signed_block: SignedBeaconBlock) -> None:
assert block.parent_root in store.block_states
pre_state = store.block_states[block.parent_root].copy()
# Blocks cannot be in the future. If they are, their consideration must be delayed until the are in the past.
assert store.time >= pre_state.genesis_time + block.slot * SECONDS_PER_SLOT
assert get_current_slot(store) >= block.slot
# Add new block to the store
store.blocks[hash_tree_root(block)] = block
# Check block is a descendant of the finalized block
@ -226,7 +297,8 @@ def on_block(store: Store, signed_block: SignedBeaconBlock) -> None:
# Update justified checkpoint
if state.current_justified_checkpoint.epoch > store.justified_checkpoint.epoch:
store.best_justified_checkpoint = state.current_justified_checkpoint
if state.current_justified_checkpoint.epoch > store.best_justified_checkpoint.epoch:
store.best_justified_checkpoint = state.current_justified_checkpoint
if should_update_justified_checkpoint(store, state.current_justified_checkpoint):
store.justified_checkpoint = state.current_justified_checkpoint
@ -252,12 +324,13 @@ def on_attestation(store: Store, attestation: Attestation) -> None:
# Use GENESIS_EPOCH for previous when genesis to avoid underflow
previous_epoch = current_epoch - 1 if current_epoch > GENESIS_EPOCH else GENESIS_EPOCH
assert target.epoch in [current_epoch, previous_epoch]
assert target.epoch == compute_epoch_at_slot(attestation.data.slot)
# Attestations target be for a known block. If target block is unknown, delay consideration until the block is found
assert target.root in store.blocks
# Attestations cannot be from future epochs. If they are, delay consideration until the epoch arrives
base_state = store.block_states[target.root].copy()
assert store.time >= base_state.genesis_time + compute_start_slot_at_epoch(target.epoch) * SECONDS_PER_SLOT
assert get_current_slot(store) >= compute_start_slot_at_epoch(target.epoch)
# Attestations must be for a known block. If block is unknown, delay consideration until the block is found
assert attestation.data.beacon_block_root in store.blocks
@ -272,7 +345,7 @@ def on_attestation(store: Store, attestation: Attestation) -> None:
# Attestations can only affect the fork choice of subsequent slots.
# Delay consideration in the fork choice until their slot is in the past.
assert store.time >= (attestation.data.slot + 1) * SECONDS_PER_SLOT
assert get_current_slot(store) >= attestation.data.slot + 1
# Get state at the `target` to validate attestation and calculate the committees
indexed_attestation = get_indexed_attestation(target_state, attestation)

View File

@ -3,29 +3,31 @@
## Table of contents
<!-- TOC -->
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
- [Phase 1 miscellaneous beacon chain changes](#phase-1-miscellaneous-beacon-chain-changes)
- [Table of contents](#table-of-contents)
- [Configuration](#configuration)
- [Containers](#containers)
- [`CompactCommittee`](#compactcommittee)
- [`ShardReceiptDelta`](#shardreceiptdelta)
- [`ShardReceiptProof`](#shardreceiptproof)
- [Helper functions](#helper-functions)
- [`pack_compact_validator`](#pack_compact_validator)
- [`unpack_compact_validator`](#unpack_compact_validator)
- [`committee_to_compact_committee`](#committee_to_compact_committee)
- [`verify_merkle_proof`](#verify_merkle_proof)
- [`compute_historical_state_generalized_index`](#compute_historical_state_generalized_index)
- [`get_generalized_index_of_crosslink_header`](#get_generalized_index_of_crosslink_header)
- [`process_shard_receipt_proof`](#process_shard_receipt_proof)
- [Changes](#changes)
- [Phase 0 container updates](#phase-0-container-updates)
- [`BeaconState`](#beaconstate)
- [`BeaconBlockBody`](#beaconblockbody)
- [Persistent committees](#persistent-committees)
- [Shard receipt processing](#shard-receipt-processing)
- [Configuration](#configuration)
- [Containers](#containers)
- [`CompactCommittee`](#compactcommittee)
- [`ShardReceiptDelta`](#shardreceiptdelta)
- [`ShardReceiptProof`](#shardreceiptproof)
- [Helper functions](#helper-functions)
- [`pack_compact_validator`](#pack_compact_validator)
- [`unpack_compact_validator`](#unpack_compact_validator)
- [`committee_to_compact_committee`](#committee_to_compact_committee)
- [`verify_merkle_proof`](#verify_merkle_proof)
- [`compute_historical_state_generalized_index`](#compute_historical_state_generalized_index)
- [`get_generalized_index_of_crosslink_header`](#get_generalized_index_of_crosslink_header)
- [`process_shard_receipt_proof`](#process_shard_receipt_proof)
- [Changes](#changes)
- [Phase 0 container updates](#phase-0-container-updates)
- [`BeaconState`](#beaconstate)
- [`BeaconBlockBody`](#beaconblockbody)
- [Persistent committees](#persistent-committees)
- [Shard receipt processing](#shard-receipt-processing)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
<!-- /TOC -->
## Configuration

View File

@ -5,54 +5,56 @@
## Table of contents
<!-- TOC -->
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
- [Ethereum 2.0 Phase 1 -- Custody Game](#ethereum-20-phase-1----custody-game)
- [Table of contents](#table-of-contents)
- [Introduction](#introduction)
- [Terminology](#terminology)
- [Constants](#constants)
- [Misc](#misc)
- [Custody game parameters](#custody-game-parameters)
- [Time parameters](#time-parameters)
- [Max operations per block](#max-operations-per-block)
- [Reward and penalty quotients](#reward-and-penalty-quotients)
- [Signature domain types](#signature-domain-types)
- [TODO PLACEHOLDER](#todo-placeholder)
- [Data structures](#data-structures)
- [Custody objects](#custody-objects)
- [`CustodyChunkChallenge`](#custodychunkchallenge)
- [`CustodyBitChallenge`](#custodybitchallenge)
- [`CustodyChunkChallengeRecord`](#custodychunkchallengerecord)
- [`CustodyBitChallengeRecord`](#custodybitchallengerecord)
- [`CustodyResponse`](#custodyresponse)
- [New beacon operations](#new-beacon-operations)
- [`CustodyKeyReveal`](#custodykeyreveal)
- [`EarlyDerivedSecretReveal`](#earlyderivedsecretreveal)
- [Phase 0 container updates](#phase-0-container-updates)
- [`Validator`](#validator)
- [`BeaconState`](#beaconstate)
- [`BeaconBlockBody`](#beaconblockbody)
- [Helpers](#helpers)
- [`ceillog2`](#ceillog2)
- [`is_valid_merkle_branch_with_mixin`](#is_valid_merkle_branch_with_mixin)
- [`get_crosslink_chunk_count`](#get_crosslink_chunk_count)
- [`legendre_bit`](#legendre_bit)
- [`custody_subchunkify`](#custody_subchunkify)
- [`get_custody_chunk_bit`](#get_custody_chunk_bit)
- [`get_chunk_bits_root`](#get_chunk_bits_root)
- [`get_randao_epoch_for_custody_period`](#get_randao_epoch_for_custody_period)
- [`get_custody_period_for_validator`](#get_custody_period_for_validator)
- [`replace_empty_or_append`](#replace_empty_or_append)
- [Per-block processing](#per-block-processing)
- [Operations](#operations)
- [Custody key reveals](#custody-key-reveals)
- [Early derived secret reveals](#early-derived-secret-reveals)
- [Chunk challenges](#chunk-challenges)
- [Bit challenges](#bit-challenges)
- [Custody responses](#custody-responses)
- [Per-epoch processing](#per-epoch-processing)
- [Handling of custody-related deadlines](#handling-of-custody-related-deadlines)
- [Introduction](#introduction)
- [Terminology](#terminology)
- [Constants](#constants)
- [Misc](#misc)
- [Custody game parameters](#custody-game-parameters)
- [Time parameters](#time-parameters)
- [Max operations per block](#max-operations-per-block)
- [Reward and penalty quotients](#reward-and-penalty-quotients)
- [Signature domain types](#signature-domain-types)
- [TODO PLACEHOLDER](#todo-placeholder)
- [Data structures](#data-structures)
- [Custody objects](#custody-objects)
- [`CustodyChunkChallenge`](#custodychunkchallenge)
- [`CustodyBitChallenge`](#custodybitchallenge)
- [`CustodyChunkChallengeRecord`](#custodychunkchallengerecord)
- [`CustodyBitChallengeRecord`](#custodybitchallengerecord)
- [`CustodyResponse`](#custodyresponse)
- [New beacon operations](#new-beacon-operations)
- [`CustodyKeyReveal`](#custodykeyreveal)
- [`EarlyDerivedSecretReveal`](#earlyderivedsecretreveal)
- [Phase 0 container updates](#phase-0-container-updates)
- [`Validator`](#validator)
- [`BeaconState`](#beaconstate)
- [`BeaconBlockBody`](#beaconblockbody)
- [Helpers](#helpers)
- [`ceillog2`](#ceillog2)
- [`is_valid_merkle_branch_with_mixin`](#is_valid_merkle_branch_with_mixin)
- [`get_crosslink_chunk_count`](#get_crosslink_chunk_count)
- [`legendre_bit`](#legendre_bit)
- [`custody_subchunkify`](#custody_subchunkify)
- [`get_custody_chunk_bit`](#get_custody_chunk_bit)
- [`get_chunk_bits_root`](#get_chunk_bits_root)
- [`get_randao_epoch_for_custody_period`](#get_randao_epoch_for_custody_period)
- [`get_custody_period_for_validator`](#get_custody_period_for_validator)
- [`replace_empty_or_append`](#replace_empty_or_append)
- [Per-block processing](#per-block-processing)
- [Operations](#operations)
- [Custody key reveals](#custody-key-reveals)
- [Early derived secret reveals](#early-derived-secret-reveals)
- [Chunk challenges](#chunk-challenges)
- [Bit challenges](#bit-challenges)
- [Custody responses](#custody-responses)
- [Per-epoch processing](#per-epoch-processing)
- [Handling of custody-related deadlines](#handling-of-custody-related-deadlines)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
<!-- /TOC -->
## Introduction

View File

@ -5,45 +5,47 @@
## Table of contents
<!-- TOC -->
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
- [Ethereum 2.0 Phase 1 -- Shard Data Chains](#ethereum-20-phase-1----shard-data-chains)
- [Table of contents](#table-of-contents)
- [Introduction](#introduction)
- [Custom types](#custom-types)
- [Configuration](#configuration)
- [Misc](#misc)
- [Initial values](#initial-values)
- [Time parameters](#time-parameters)
- [State list lengths](#state-list-lengths)
- [Rewards and penalties](#rewards-and-penalties)
- [Signature domain types](#signature-domain-types)
- [Containers](#containers)
- [`Crosslink`](#crosslink)
- [`ShardBlock`](#shardblock)
- [`ShardBlockHeader`](#shardblockheader)
- [`ShardState`](#shardstate)
- [`ShardAttestationData`](#shardattestationdata)
- [Helper functions](#helper-functions)
- [Misc](#misc-1)
- [`compute_epoch_of_shard_slot`](#compute_epoch_of_shard_slot)
- [`compute_shard_period_start_epoch`](#compute_shard_period_start_epoch)
- [Beacon state accessors](#beacon-state-accessors)
- [`get_period_committee`](#get_period_committee)
- [`get_shard_committee`](#get_shard_committee)
- [`get_shard_proposer_index`](#get_shard_proposer_index)
- [Shard state mutators](#shard-state-mutators)
- [`process_delta`](#process_delta)
- [Genesis](#genesis)
- [`get_genesis_shard_state`](#get_genesis_shard_state)
- [`get_genesis_shard_block`](#get_genesis_shard_block)
- [Shard state transition function](#shard-state-transition-function)
- [Period processing](#period-processing)
- [Block processing](#block-processing)
- [Block header](#block-header)
- [Attestations](#attestations)
- [Block body](#block-body)
- [Shard fork choice rule](#shard-fork-choice-rule)
- [Introduction](#introduction)
- [Custom types](#custom-types)
- [Configuration](#configuration)
- [Misc](#misc)
- [Initial values](#initial-values)
- [Time parameters](#time-parameters)
- [State list lengths](#state-list-lengths)
- [Rewards and penalties](#rewards-and-penalties)
- [Signature domain types](#signature-domain-types)
- [Containers](#containers)
- [`Crosslink`](#crosslink)
- [`ShardBlock`](#shardblock)
- [`ShardBlockHeader`](#shardblockheader)
- [`ShardState`](#shardstate)
- [`ShardAttestationData`](#shardattestationdata)
- [Helper functions](#helper-functions)
- [Misc](#misc-1)
- [`compute_epoch_of_shard_slot`](#compute_epoch_of_shard_slot)
- [`compute_shard_period_start_epoch`](#compute_shard_period_start_epoch)
- [Beacon state accessors](#beacon-state-accessors)
- [`get_period_committee`](#get_period_committee)
- [`get_shard_committee`](#get_shard_committee)
- [`get_shard_proposer_index`](#get_shard_proposer_index)
- [Shard state mutators](#shard-state-mutators)
- [`process_delta`](#process_delta)
- [Genesis](#genesis)
- [`get_genesis_shard_state`](#get_genesis_shard_state)
- [`get_genesis_shard_block`](#get_genesis_shard_block)
- [Shard state transition function](#shard-state-transition-function)
- [Period processing](#period-processing)
- [Block processing](#block-processing)
- [Block header](#block-header)
- [Attestations](#attestations)
- [Block body](#block-body)
- [Shard fork choice rule](#shard-fork-choice-rule)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
<!-- /TOC -->
## Introduction

View File

@ -4,21 +4,23 @@
## Table of contents
<!-- TOC -->
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
- [Merkle proof formats](#merkle-proof-formats)
- [Table of contents](#table-of-contents)
- [Helper functions](#helper-functions)
- [Generalized Merkle tree index](#generalized-merkle-tree-index)
- [SSZ object to index](#ssz-object-to-index)
- [Helpers for generalized indices](#helpers-for-generalized-indices)
- [`concat_generalized_indices`](#concat_generalized_indices)
- [`get_generalized_index_length`](#get_generalized_index_length)
- [`get_generalized_index_bit`](#get_generalized_index_bit)
- [`generalized_index_sibling`](#generalized_index_sibling)
- [`generalized_index_child`](#generalized_index_child)
- [`generalized_index_parent`](#generalized_index_parent)
- [Merkle multiproofs](#merkle-multiproofs)
- [Helper functions](#helper-functions)
- [Generalized Merkle tree index](#generalized-merkle-tree-index)
- [SSZ object to index](#ssz-object-to-index)
- [Helpers for generalized indices](#helpers-for-generalized-indices)
- [`concat_generalized_indices`](#concat_generalized_indices)
- [`get_generalized_index_length`](#get_generalized_index_length)
- [`get_generalized_index_bit`](#get_generalized_index_bit)
- [`generalized_index_sibling`](#generalized_index_sibling)
- [`generalized_index_child`](#generalized_index_child)
- [`generalized_index_parent`](#generalized_index_parent)
- [Merkle multiproofs](#merkle-multiproofs)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
<!-- /TOC -->
## Helper functions

View File

@ -5,20 +5,22 @@
## Table of contents
<!-- TOC -->
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
- [Minimal Light Client Design](#minimal-light-client-design)
- [Table of contents](#table-of-contents)
- [Introduction](#introduction)
- [Custom types](#custom-types)
- [Constants](#constants)
- [Containers](#containers)
- [`LightClientUpdate`](#lightclientupdate)
- [Helpers](#helpers)
- [`LightClientMemory`](#lightclientmemory)
- [`get_persistent_committee_pubkeys_and_balances`](#get_persistent_committee_pubkeys_and_balances)
- [Light client state updates](#light-client-state-updates)
- [Data overhead](#data-overhead)
- [Introduction](#introduction)
- [Custom types](#custom-types)
- [Constants](#constants)
- [Containers](#containers)
- [`LightClientUpdate`](#lightclientupdate)
- [Helpers](#helpers)
- [`LightClientMemory`](#lightclientmemory)
- [`get_persistent_committee_pubkeys_and_balances`](#get_persistent_committee_pubkeys_and_balances)
- [Light client state updates](#light-client-state-updates)
- [Data overhead](#data-overhead)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
<!-- /TOC -->
## Introduction

View File

@ -18,23 +18,88 @@ It consists of four main sections:
- [Network fundamentals](#network-fundamentals)
- [Transport](#transport)
- [Interop](#interop)
- [Mainnet](#mainnet)
- [Encryption and identification](#encryption-and-identification)
- [Protocol negotiation](#protocol-negotiation)
- [Interop](#interop-1)
- [Mainnet](#mainnet-1)
- [Protocol Negotiation](#protocol-negotiation)
- [Interop](#interop-2)
- [Mainnet](#mainnet-2)
- [Multiplexing](#multiplexing)
- [Eth2 network interaction domains](#eth2-network-interaction-domains)
- [Configuration](#configuration)
- [The gossip domain: gossipsub](#the-gossip-domain-gossipsub)
- [Topics and messages](#topics-and-messages)
- [Global topics](#global-topics)
- [Attestation subnets](#attestation-subnets)
- [Interop](#interop-3)
- [Mainnet](#mainnet-3)
- [Encodings](#encodings)
- [Interop](#interop-4)
- [Mainnet](#mainnet-4)
- [The Req/Resp domain](#the-reqresp-domain)
- [Protocol identification](#protocol-identification)
- [Req/Resp interaction](#reqresp-interaction)
- [Requesting side](#requesting-side)
- [Responding side](#responding-side)
- [Encoding strategies](#encoding-strategies)
- [SSZ-encoding strategy (with or without Snappy)](#ssz-encoding-strategy-with-or-without-snappy)
- [Messages](#messages)
- [Status](#status)
- [Goodbye](#goodbye)
- [BeaconBlocksByRange](#beaconblocksbyrange)
- [BeaconBlocksByRoot](#beaconblocksbyroot)
- [The discovery domain: discv5](#the-discovery-domain-discv5)
- [Integration into libp2p stacks](#integration-into-libp2p-stacks)
- [ENR structure](#enr-structure)
- [Interop](#interop-5)
- [Mainnet](#mainnet-5)
- [Topic advertisement](#topic-advertisement)
- [Interop](#interop-6)
- [Mainnet](#mainnet-6)
- [Design decision rationale](#design-decision-rationale)
- [Transport](#transport-1)
- [Why are we defining specific transports?](#why-are-we-defining-specific-transports)
- [Can clients support other transports/handshakes than the ones mandated by the spec?](#can-clients-support-other-transportshandshakes-than-the-ones-mandated-by-the-spec)
- [What are the advantages of using TCP/QUIC/Websockets?](#what-are-the-advantages-of-using-tcpquicwebsockets)
- [Why do we not just support a single transport?](#why-do-we-not-just-support-a-single-transport)
- [Why are we not using QUIC for mainnet from the start?](#why-are-we-not-using-quic-for-mainnet-from-the-start)
- [Multiplexing](#multiplexing-1)
- [Protocol negotiation](#protocol-negotiation-1)
- [Why are we using mplex/yamux?](#why-are-we-using-mplexyamux)
- [Protocol Negotiation](#protocol-negotiation-1)
- [When is multiselect 2.0 due and why are we using it for mainnet?](#when-is-multiselect-20-due-and-why-are-we-using-it-for-mainnet)
- [What is the difference between connection-level and stream-level protocol negotiation?](#what-is-the-difference-between-connection-level-and-stream-level-protocol-negotiation)
- [Encryption](#encryption)
- [Why are we using SecIO for interop? Why not for mainnet?](#why-are-we-using-secio-for-interop-why-not-for-mainnet)
- [Why are we using Noise/TLS 1.3 for mainnet?](#why-are-we-using-noisetls-13-for-mainnet)
- [Why are we using encryption at all?](#why-are-we-using-encryption-at-all)
- [Will mainnnet networking be untested when it launches?](#will-mainnnet-networking-be-untested-when-it-launches)
- [Gossipsub](#gossipsub)
- [Why are we using a pub/sub algorithm for block and attestation propagation?](#why-are-we-using-a-pubsub-algorithm-for-block-and-attestation-propagation)
- [Why are we using topics to segregate encodings, yet only support one encoding?](#why-are-we-using-topics-to-segregate-encodings-yet-only-support-one-encoding)
- [How do we upgrade gossip channels (e.g. changes in encoding, compression)?](#how-do-we-upgrade-gossip-channels-eg-changes-in-encoding-compression)
- [Why must all clients use the same gossip topic instead of one negotiated between each peer pair?](#why-must-all-clients-use-the-same-gossip-topic-instead-of-one-negotiated-between-each-peer-pair)
- [Why are the topics strings and not hashes?](#why-are-the-topics-strings-and-not-hashes)
- [Why are there `ATTESTATION_SUBNET_COUNT` attestation subnets?](#why-are-there-attestation_subnet_count-attestation-subnets)
- [Why are attestations limited to be broadcast on gossip channels within `SLOTS_PER_EPOCH` slots?](#why-are-attestations-limited-to-be-broadcast-on-gossip-channels-within-slots_per_epoch-slots)
- [Why are aggregate attestations broadcast to the global topic as `AggregateAndProof`s rather than just as `Attestation`s?](#why-are-aggregate-attestations-broadcast-to-the-global-topic-as-aggregateandproofs-rather-than-just-as-attestations)
- [Why are we sending entire objects in the pubsub and not just hashes?](#why-are-we-sending-entire-objects-in-the-pubsub-and-not-just-hashes)
- [Should clients gossip blocks if they *cannot* validate the proposer signature due to not yet being synced, not knowing the head block, etc?](#should-clients-gossip-blocks-if-they-cannot-validate-the-proposer-signature-due-to-not-yet-being-synced-not-knowing-the-head-block-etc)
- [How are we going to discover peers in a gossipsub topic?](#how-are-we-going-to-discover-peers-in-a-gossipsub-topic)
- [Req/Resp](#reqresp)
- [Why segregate requests into dedicated protocol IDs?](#why-segregate-requests-into-dedicated-protocol-ids)
- [Why are messages length-prefixed with a protobuf varint in the SSZ-encoding?](#why-are-messages-length-prefixed-with-a-protobuf-varint-in-the-ssz-encoding)
- [Why do we version protocol strings with ordinals instead of semver?](#why-do-we-version-protocol-strings-with-ordinals-instead-of-semver)
- [Why is it called Req/Resp and not RPC?](#why-is-it-called-reqresp-and-not-rpc)
- [Discovery](#discovery)
- [Why are we using discv5 and not libp2p Kademlia DHT?](#why-are-we-using-discv5-and-not-libp2p-kademlia-dht)
- [What is the difference between an ENR and a multiaddr, and why are we using ENRs?](#what-is-the-difference-between-an-enr-and-a-multiaddr-and-why-are-we-using-enrs)
- [Compression/Encoding](#compressionencoding)
- [Why are we using SSZ for encoding?](#why-are-we-using-ssz-for-encoding)
- [Why are we compressing, and at which layers?](#why-are-we-compressing-and-at-which-layers)
- [Why are using Snappy for compression?](#why-are-using-snappy-for-compression)
- [Can I get access to unencrypted bytes on the wire for debugging purposes?](#can-i-get-access-to-unencrypted-bytes-on-the-wire-for-debugging-purposes)
- [libp2p implementations matrix](#libp2p-implementations-matrix)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
@ -356,7 +421,7 @@ The fields are, as seen by the client at the time of sending the message:
- `head_fork_version`: The beacon_state `Fork` version.
- `finalized_root`: `state.finalized_checkpoint.root` for the state corresponding to the head block.
- `finalized_epoch`: `state.finalized_checkpoint.epoch` for the state corresponding to the head block.
- `head_root`: The signing root of the current head block.
- `head_root`: The hash_tree_root root of the current head block.
- `head_slot`: The slot of the block corresponding to the `head_root`.
The dialing client MUST send a `Status` request upon connection.
@ -567,7 +632,7 @@ Conscious of that, the libp2p community conceptualized [mplex](https://github.co
Overlay multiplexers are not necessary with QUIC since the protocol provides native multiplexing, but they need to be layered atop TCP, WebSockets, and other transports that lack such support.
## Protocol negotiation
## Protocol Negotiation
### When is multiselect 2.0 due and why are we using it for mainnet?

View File

@ -4,30 +4,32 @@
## Table of contents
<!-- TOC -->
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
- [SimpleSerialize (SSZ)](#simpleserialize-ssz)
- [Table of contents](#table-of-contents)
- [Constants](#constants)
- [Typing](#typing)
- [Basic types](#basic-types)
- [Composite types](#composite-types)
- [Variable-size and fixed-size](#variable-size-and-fixed-size)
- [Aliases](#aliases)
- [Default values](#default-values)
- [`is_zero`](#is_zero)
- [Illegal types](#illegal-types)
- [Serialization](#serialization)
- [`uintN`](#uintn)
- [`boolean`](#boolean)
- [`null`](#null)
- [`Bitvector[N]`](#bitvectorn)
- [`Bitlist[N]`](#bitlistn)
- [Vectors, containers, lists, unions](#vectors-containers-lists-unions)
- [Deserialization](#deserialization)
- [Merkleization](#merkleization)
- [Summaries and expansions](#summaries-and-expansions)
- [Implementations](#implementations)
- [Constants](#constants)
- [Typing](#typing)
- [Basic types](#basic-types)
- [Composite types](#composite-types)
- [Variable-size and fixed-size](#variable-size-and-fixed-size)
- [Aliases](#aliases)
- [Default values](#default-values)
- [`is_zero`](#is_zero)
- [Illegal types](#illegal-types)
- [Serialization](#serialization)
- [`uintN`](#uintn)
- [`boolean`](#boolean)
- [`null`](#null)
- [`Bitvector[N]`](#bitvectorn)
- [`Bitlist[N]`](#bitlistn)
- [Vectors, containers, lists, unions](#vectors-containers-lists-unions)
- [Deserialization](#deserialization)
- [Merkleization](#merkleization)
- [Summaries and expansions](#summaries-and-expansions)
- [Implementations](#implementations)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
<!-- /TOC -->
## Constants

View File

@ -37,7 +37,7 @@ Valid has 3 parts: `meta.yaml`, `serialized.ssz`, `value.yaml`
### `meta.yaml`
Valid ssz objects can have a hash-tree-root, and for some types also a signing-root.
Valid ssz objects can have a hash-tree-root.
The expected roots are encoded into the metadata yaml:
```yaml
@ -61,7 +61,6 @@ The conditions are the same for each type:
- Encoding: After encoding the given `value` object, the output should match `serialized`.
- Decoding: After decoding the given `serialized` bytes, it should match the `value` object.
- Hash-tree-root: the root should match the root declared in the metadata.
- Signing-root: if present in metadata, the signing root of the object should match the container.
## `invalid`

View File

@ -5,61 +5,64 @@
## Table of contents
<!-- TOC -->
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
- [Ethereum 2.0 Phase 0 -- Honest Validator](#ethereum-20-phase-0----honest-validator)
- [Table of contents](#table-of-contents)
- [Introduction](#introduction)
- [Prerequisites](#prerequisites)
- [Constants](#constants)
- [Misc](#misc)
- [Becoming a validator](#becoming-a-validator)
- [Initialization](#initialization)
- [BLS public key](#bls-public-key)
- [BLS withdrawal key](#bls-withdrawal-key)
- [Submit deposit](#submit-deposit)
- [Process deposit](#process-deposit)
- [Validator index](#validator-index)
- [Activation](#activation)
- [Validator assignments](#validator-assignments)
- [Lookahead](#lookahead)
- [Beacon chain responsibilities](#beacon-chain-responsibilities)
- [Block proposal](#block-proposal)
- [Block header](#block-header)
- [Slot](#slot)
- [Parent root](#parent-root)
- [State root](#state-root)
- [Randao reveal](#randao-reveal)
- [Eth1 Data](#eth1-data)
- [Signature](#signature)
- [Block body](#block-body)
- [Proposer slashings](#proposer-slashings)
- [Attester slashings](#attester-slashings)
- [Attestations](#attestations)
- [Deposits](#deposits)
- [Voluntary exits](#voluntary-exits)
- [Attesting](#attesting)
- [Attestation data](#attestation-data)
- [General](#general)
- [LMD GHOST vote](#lmd-ghost-vote)
- [FFG vote](#ffg-vote)
- [Construct attestation](#construct-attestation)
- [Data](#data)
- [Aggregation bits](#aggregation-bits)
- [Aggregate signature](#aggregate-signature)
- [Broadcast attestation](#broadcast-attestation)
- [Attestation aggregation](#attestation-aggregation)
- [Aggregation selection](#aggregation-selection)
- [Construct aggregate](#construct-aggregate)
- [Data](#data-1)
- [Aggregation bits](#aggregation-bits-1)
- [Aggregate signature](#aggregate-signature-1)
- [Broadcast aggregate](#broadcast-aggregate)
- [`AggregateAndProof`](#aggregateandproof)
- [Phase 0 attestation subnet stability](#phase-0-attestation-subnet-stability)
- [How to avoid slashing](#how-to-avoid-slashing)
- [Proposer slashing](#proposer-slashing)
- [Attester slashing](#attester-slashing)
- [Introduction](#introduction)
- [Prerequisites](#prerequisites)
- [Constants](#constants)
- [Misc](#misc)
- [Becoming a validator](#becoming-a-validator)
- [Initialization](#initialization)
- [BLS public key](#bls-public-key)
- [BLS withdrawal key](#bls-withdrawal-key)
- [Submit deposit](#submit-deposit)
- [Process deposit](#process-deposit)
- [Validator index](#validator-index)
- [Activation](#activation)
- [Validator assignments](#validator-assignments)
- [Lookahead](#lookahead)
- [Beacon chain responsibilities](#beacon-chain-responsibilities)
- [Block proposal](#block-proposal)
- [Preparing for a `BeaconBlock`](#preparing-for-a-beaconblock)
- [Slot](#slot)
- [Parent root](#parent-root)
- [Constructing the `BeaconBlockBody`](#constructing-the-beaconblockbody)
- [Randao reveal](#randao-reveal)
- [Eth1 Data](#eth1-data)
- [Proposer slashings](#proposer-slashings)
- [Attester slashings](#attester-slashings)
- [Attestations](#attestations)
- [Deposits](#deposits)
- [Voluntary exits](#voluntary-exits)
- [Packaging into a `SignedBeaconBlock`](#packaging-into-a-signedbeaconblock)
- [State root](#state-root)
- [Signature](#signature)
- [Attesting](#attesting)
- [Attestation data](#attestation-data)
- [General](#general)
- [LMD GHOST vote](#lmd-ghost-vote)
- [FFG vote](#ffg-vote)
- [Construct attestation](#construct-attestation)
- [Data](#data)
- [Aggregation bits](#aggregation-bits)
- [Aggregate signature](#aggregate-signature)
- [Broadcast attestation](#broadcast-attestation)
- [Attestation aggregation](#attestation-aggregation)
- [Aggregation selection](#aggregation-selection)
- [Construct aggregate](#construct-aggregate)
- [Data](#data-1)
- [Aggregation bits](#aggregation-bits-1)
- [Aggregate signature](#aggregate-signature-1)
- [Broadcast aggregate](#broadcast-aggregate)
- [`AggregateAndProof`](#aggregateandproof)
- [Phase 0 attestation subnet stability](#phase-0-attestation-subnet-stability)
- [How to avoid slashing](#how-to-avoid-slashing)
- [Proposer slashing](#proposer-slashing)
- [Attester slashing](#attester-slashing)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
<!-- /TOC -->
## Introduction

View File

@ -1,7 +1,11 @@
from eth2spec.test.context import with_all_phases, spec_state_test
from eth2spec.test.helpers.attestations import get_valid_attestation
from eth2spec.test.helpers.block import build_empty_block_for_next_slot
from eth2spec.test.helpers.state import state_transition_and_sign_block
from eth2spec.test.helpers.state import (
next_epoch,
next_epoch_with_attestations,
state_transition_and_sign_block,
)
def add_block_to_store(spec, store, signed_block):
@ -112,3 +116,79 @@ def test_shorter_chain_but_heavier_weight(spec, state):
add_attestation_to_store(spec, store, short_attestation)
assert spec.get_head(store) == spec.hash_tree_root(short_block)
@with_all_phases
@spec_state_test
def test_filtered_block_tree(spec, state):
# Initialization
genesis_state_root = state.hash_tree_root()
store = spec.get_genesis_store(state)
genesis_block = spec.BeaconBlock(state_root=genesis_state_root)
# transition state past initial couple of epochs
next_epoch(spec, state)
next_epoch(spec, state)
assert spec.get_head(store) == spec.hash_tree_root(genesis_block)
# fill in attestations for entire epoch, justifying the recent epoch
prev_state, signed_blocks, state = next_epoch_with_attestations(spec, state, True, False)
attestations = [
attestation for signed_block in signed_blocks
for attestation in signed_block.message.body.attestations
]
assert state.current_justified_checkpoint.epoch > prev_state.current_justified_checkpoint.epoch
# tick time forward and add blocks and attestations to store
current_time = state.slot * spec.SECONDS_PER_SLOT + store.genesis_time
spec.on_tick(store, current_time)
for signed_block in signed_blocks:
spec.on_block(store, signed_block)
for attestation in attestations:
spec.on_attestation(store, attestation)
assert store.justified_checkpoint == state.current_justified_checkpoint
# the last block in the branch should be the head
expected_head_root = spec.hash_tree_root(signed_blocks[-1].message)
assert spec.get_head(store) == expected_head_root
#
# create branch containing the justified block but not containing enough on
# chain votes to justify that block
#
# build a chain without attestations off of previous justified block
non_viable_state = store.block_states[store.justified_checkpoint.root].copy()
# ensure that next wave of votes are for future epoch
next_epoch(spec, non_viable_state)
next_epoch(spec, non_viable_state)
next_epoch(spec, non_viable_state)
assert spec.get_current_epoch(non_viable_state) > store.justified_checkpoint.epoch
# create rogue block that will be attested to in this non-viable branch
rogue_block = build_empty_block_for_next_slot(spec, non_viable_state)
signed_rogue_block = state_transition_and_sign_block(spec, non_viable_state, rogue_block)
# create an epoch's worth of attestations for the rogue block
next_epoch(spec, non_viable_state)
attestations = []
for i in range(spec.SLOTS_PER_EPOCH):
slot = rogue_block.slot + i
for index in range(spec.get_committee_count_at_slot(non_viable_state, slot)):
attestation = get_valid_attestation(spec, non_viable_state, rogue_block.slot + i, index)
attestations.append(attestation)
# tick time forward to be able to include up to the latest attestation
current_time = (attestations[-1].data.slot + 1) * spec.SECONDS_PER_SLOT + store.genesis_time
spec.on_tick(store, current_time)
# include rogue block and associated attestations in the store
spec.on_block(store, signed_rogue_block)
for attestation in attestations:
spec.on_attestation(store, attestation)
# ensure that get_head still returns the head from the previous branch
assert spec.get_head(store) == expected_head_root

View File

@ -84,6 +84,29 @@ def test_on_attestation_past_epoch(spec, state):
run_on_attestation(spec, state, store, attestation, False)
@with_all_phases
@spec_state_test
def test_on_attestation_mismatched_target_and_slot(spec, state):
store = spec.get_genesis_store(state)
spec.on_tick(store, store.time + spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH)
block = build_empty_block_for_next_slot(spec, state)
signed_block = state_transition_and_sign_block(spec, state, block)
# store block in store
spec.on_block(store, signed_block)
attestation = get_valid_attestation(spec, state, slot=block.slot)
attestation.data.target.epoch += 1
sign_attestation(spec, state, attestation)
assert attestation.data.target.epoch == spec.GENESIS_EPOCH + 1
assert spec.compute_epoch_at_slot(attestation.data.slot) == spec.GENESIS_EPOCH
assert spec.compute_epoch_at_slot(spec.get_current_slot(store)) == spec.GENESIS_EPOCH + 1
run_on_attestation(spec, state, store, attestation, False)
@with_all_phases
@spec_state_test
def test_on_attestation_target_not_in_store(spec, state):

View File

@ -168,7 +168,7 @@ def test_on_block_update_justified_checkpoint_within_safe_slots(spec, state):
@with_all_phases
@spec_state_test
def test_on_block_outside_safe_slots_and_old_block(spec, state):
def test_on_block_outside_safe_slots_and_multiple_better_justified(spec, state):
# Initialization
store = spec.get_genesis_store(state)
time = 100
@ -187,20 +187,30 @@ def test_on_block_outside_safe_slots_and_old_block(spec, state):
just_block.slot = spec.compute_start_slot_at_epoch(store.justified_checkpoint.epoch)
store.blocks[just_block.hash_tree_root()] = just_block
# Mock the justified checkpoint
just_state = store.block_states[last_block_root]
new_justified = spec.Checkpoint(
epoch=just_state.current_justified_checkpoint.epoch + 1,
root=just_block.hash_tree_root(),
)
just_state.current_justified_checkpoint = new_justified
block = build_empty_block_for_next_slot(spec, just_state)
signed_block = state_transition_and_sign_block(spec, deepcopy(just_state), block)
# Step time past safe slots
spec.on_tick(store, store.time + spec.SAFE_SLOTS_TO_UPDATE_JUSTIFIED * spec.SECONDS_PER_SLOT)
assert spec.get_current_slot(store) % spec.SLOTS_PER_EPOCH >= spec.SAFE_SLOTS_TO_UPDATE_JUSTIFIED
run_on_block(spec, store, signed_block)
assert store.justified_checkpoint != new_justified
assert store.best_justified_checkpoint == new_justified
previously_justified = store.justified_checkpoint
# Add a series of new blocks with "better" justifications
best_justified_checkpoint = spec.Checkpoint(epoch=0)
for i in range(3, 0, -1):
just_state = store.block_states[last_block_root]
new_justified = spec.Checkpoint(
epoch=previously_justified.epoch + i,
root=just_block.hash_tree_root(),
)
if new_justified.epoch > best_justified_checkpoint.epoch:
best_justified_checkpoint = new_justified
just_state.current_justified_checkpoint = new_justified
block = build_empty_block_for_next_slot(spec, just_state)
signed_block = state_transition_and_sign_block(spec, deepcopy(just_state), block)
run_on_block(spec, store, signed_block)
assert store.justified_checkpoint == previously_justified
# ensure the best from the series was stored
assert store.best_justified_checkpoint == best_justified_checkpoint

View File

@ -177,6 +177,20 @@ def test_invalid_index(spec, state):
yield from run_attestation_processing(spec, state, attestation, False)
@with_all_phases
@spec_state_test
def test_mismatched_target_and_slot(spec, state):
next_epoch(spec, state)
next_epoch(spec, state)
attestation = get_valid_attestation(spec, state)
attestation.data.slot = attestation.data.slot - spec.SLOTS_PER_EPOCH
sign_attestation(spec, state, attestation)
yield from run_attestation_processing(spec, state, attestation, False)
@with_all_phases
@spec_state_test
def test_old_target_epoch(spec, state):

View File

@ -252,6 +252,76 @@ def test_att2_bad_replaced_index(spec, state):
yield from run_attester_slashing_processing(spec, state, attester_slashing, False)
@with_all_phases
@spec_state_test
@always_bls
def test_att1_duplicate_index_normal_signed(spec, state):
attester_slashing = get_valid_attester_slashing(spec, state, signed_1=False, signed_2=True)
indices = attester_slashing.attestation_1.attesting_indices
indices.pop(1) # remove an index, make room for the additional duplicate index.
attester_slashing.attestation_1.attesting_indices = sorted(indices)
# sign it, the signature will be valid for a single occurence. If the transition accidentally ignores the duplicate.
sign_indexed_attestation(spec, state, attester_slashing.attestation_1)
indices.append(indices[0]) # add one of the indices a second time
attester_slashing.attestation_1.attesting_indices = sorted(indices)
# it will just appear normal, unless the double index is spotted
yield from run_attester_slashing_processing(spec, state, attester_slashing, False)
@with_all_phases
@spec_state_test
@always_bls
def test_att2_duplicate_index_normal_signed(spec, state):
attester_slashing = get_valid_attester_slashing(spec, state, signed_1=True, signed_2=False)
indices = attester_slashing.attestation_2.attesting_indices
indices.pop(2) # remove an index, make room for the additional duplicate index.
attester_slashing.attestation_2.attesting_indices = sorted(indices)
# sign it, the signature will be valid for a single occurence. If the transition accidentally ignores the duplicate.
sign_indexed_attestation(spec, state, attester_slashing.attestation_2)
indices.append(indices[1]) # add one of the indices a second time
attester_slashing.attestation_2.attesting_indices = sorted(indices)
# it will just appear normal, unless the double index is spotted
yield from run_attester_slashing_processing(spec, state, attester_slashing, False)
@with_all_phases
@spec_state_test
@always_bls
def test_att1_duplicate_index_double_signed(spec, state):
attester_slashing = get_valid_attester_slashing(spec, state, signed_1=False, signed_2=True)
indices = attester_slashing.attestation_1.attesting_indices
indices.pop(1) # remove an index, make room for the additional duplicate index.
indices.append(indices[2]) # add one of the indices a second time
attester_slashing.attestation_1.attesting_indices = sorted(indices)
sign_indexed_attestation(spec, state, attester_slashing.attestation_1) # will have one attester signing it double
yield from run_attester_slashing_processing(spec, state, attester_slashing, False)
@with_all_phases
@spec_state_test
@always_bls
def test_att2_duplicate_index_double_signed(spec, state):
attester_slashing = get_valid_attester_slashing(spec, state, signed_1=True, signed_2=False)
indices = attester_slashing.attestation_2.attesting_indices
indices.pop(1) # remove an index, make room for the additional duplicate index.
indices.append(indices[2]) # add one of the indices a second time
attester_slashing.attestation_2.attesting_indices = sorted(indices)
sign_indexed_attestation(spec, state, attester_slashing.attestation_2) # will have one attester signing it double
yield from run_attester_slashing_processing(spec, state, attester_slashing, False)
@with_all_phases
@spec_state_test
def test_unsorted_att_1(spec, state):

View File

@ -17,24 +17,80 @@ def mock_deposit(spec, state, index):
@with_all_phases
@spec_state_test
def test_activation(spec, state):
def test_add_to_activation_queue(spec, state):
# move past first two irregular epochs wrt finality
next_epoch(spec, state)
next_epoch(spec, state)
index = 0
mock_deposit(spec, state, index)
for _ in range(spec.MAX_SEED_LOOKAHEAD + 1):
next_epoch(spec, state)
yield from run_process_registry_updates(spec, state)
# validator moved into queue
assert state.validators[index].activation_eligibility_epoch != spec.FAR_FUTURE_EPOCH
assert state.validators[index].activation_epoch == spec.FAR_FUTURE_EPOCH
assert not spec.is_active_validator(state.validators[index], spec.get_current_epoch(state))
@with_all_phases
@spec_state_test
def test_activation_queue_to_activated_if_finalized(spec, state):
# move past first two irregular epochs wrt finality
next_epoch(spec, state)
next_epoch(spec, state)
index = 0
mock_deposit(spec, state, index)
# mock validator as having been in queue since latest finalized
state.finalized_checkpoint.epoch = spec.get_current_epoch(state) - 1
state.validators[index].activation_eligibility_epoch = state.finalized_checkpoint.epoch
assert not spec.is_active_validator(state.validators[index], spec.get_current_epoch(state))
yield from run_process_registry_updates(spec, state)
# validator activated for future epoch
assert state.validators[index].activation_eligibility_epoch != spec.FAR_FUTURE_EPOCH
assert state.validators[index].activation_epoch != spec.FAR_FUTURE_EPOCH
assert spec.is_active_validator(state.validators[index], spec.get_current_epoch(state))
assert not spec.is_active_validator(state.validators[index], spec.get_current_epoch(state))
assert spec.is_active_validator(
state.validators[index],
spec.compute_activation_exit_epoch(spec.get_current_epoch(state))
)
@with_all_phases
@spec_state_test
def test_activation_queue_no_activation_no_finality(spec, state):
# move past first two irregular epochs wrt finality
next_epoch(spec, state)
next_epoch(spec, state)
index = 0
mock_deposit(spec, state, index)
# mock validator as having been in queue only after latest finalized
state.finalized_checkpoint.epoch = spec.get_current_epoch(state) - 1
state.validators[index].activation_eligibility_epoch = state.finalized_checkpoint.epoch + 1
assert not spec.is_active_validator(state.validators[index], spec.get_current_epoch(state))
yield from run_process_registry_updates(spec, state)
# validator not activated
assert state.validators[index].activation_eligibility_epoch != spec.FAR_FUTURE_EPOCH
assert state.validators[index].activation_epoch == spec.FAR_FUTURE_EPOCH
@with_all_phases
@spec_state_test
def test_activation_queue_sorting(spec, state):
mock_activations = 10
churn_limit = spec.get_validator_churn_limit(state)
# try to activate more than the per-epoch churn linmit
mock_activations = churn_limit * 2
epoch = spec.get_current_epoch(state)
for i in range(mock_activations):
@ -44,9 +100,9 @@ def test_activation_queue_sorting(spec, state):
# give the last priority over the others
state.validators[mock_activations - 1].activation_eligibility_epoch = epoch
# make sure we are hitting the churn
churn_limit = spec.get_validator_churn_limit(state)
assert mock_activations > churn_limit
# move state forward and finalize to allow for activations
state.slot += spec.SLOTS_PER_EPOCH * 3
state.finalized_checkpoint.epoch = epoch + 1
yield from run_process_registry_updates(spec, state)
@ -63,6 +119,38 @@ def test_activation_queue_sorting(spec, state):
assert state.validators[churn_limit - 2].activation_epoch != spec.FAR_FUTURE_EPOCH
@with_all_phases
@spec_state_test
def test_activation_queue_efficiency(spec, state):
churn_limit = spec.get_validator_churn_limit(state)
mock_activations = churn_limit * 2
epoch = spec.get_current_epoch(state)
for i in range(mock_activations):
mock_deposit(spec, state, i)
state.validators[i].activation_eligibility_epoch = epoch + 1
# move state forward and finalize to allow for activations
state.slot += spec.SLOTS_PER_EPOCH * 3
state.finalized_checkpoint.epoch = epoch + 1
# Run first registry update. Do not yield test vectors
for _ in run_process_registry_updates(spec, state):
pass
# Half should churn in first run of registry update
for i in range(mock_activations):
if i < mock_activations // 2:
assert state.validators[i].activation_epoch < spec.FAR_FUTURE_EPOCH
else:
assert state.validators[i].activation_epoch == spec.FAR_FUTURE_EPOCH
# Second half should churn in second run of registry update
yield from run_process_registry_updates(spec, state)
for i in range(mock_activations):
assert state.validators[i].activation_epoch < spec.FAR_FUTURE_EPOCH
@with_all_phases
@spec_state_test
def test_ejection(spec, state):
@ -73,13 +161,87 @@ def test_ejection(spec, state):
# Mock an ejection
state.validators[index].effective_balance = spec.EJECTION_BALANCE
for _ in range(spec.MAX_SEED_LOOKAHEAD + 1):
next_epoch(spec, state)
yield from run_process_registry_updates(spec, state)
assert state.validators[index].exit_epoch != spec.FAR_FUTURE_EPOCH
assert spec.is_active_validator(state.validators[index], spec.get_current_epoch(state))
assert not spec.is_active_validator(
state.validators[index],
spec.get_current_epoch(state),
spec.compute_activation_exit_epoch(spec.get_current_epoch(state))
)
@with_all_phases
@spec_state_test
def test_ejection_past_churn_limit(spec, state):
churn_limit = spec.get_validator_churn_limit(state)
# try to eject more than per-epoch churn limit
mock_ejections = churn_limit * 3
for i in range(mock_ejections):
state.validators[i].effective_balance = spec.EJECTION_BALANCE
expected_ejection_epoch = spec.compute_activation_exit_epoch(spec.get_current_epoch(state))
yield from run_process_registry_updates(spec, state)
for i in range(mock_ejections):
# first third ejected in normal speed
if i < mock_ejections // 3:
assert state.validators[i].exit_epoch == expected_ejection_epoch
# second thirdgets delayed by 1 epoch
elif mock_ejections // 3 <= i < mock_ejections * 2 // 3:
assert state.validators[i].exit_epoch == expected_ejection_epoch + 1
# second thirdgets delayed by 2 epochs
else:
assert state.validators[i].exit_epoch == expected_ejection_epoch + 2
@with_all_phases
@spec_state_test
def test_activation_queue_activation_and_ejection(spec, state):
# move past first two irregular epochs wrt finality
next_epoch(spec, state)
next_epoch(spec, state)
# ready for entrance into activation queue
activation_queue_index = 0
mock_deposit(spec, state, activation_queue_index)
# ready for activation
activation_index = 1
mock_deposit(spec, state, activation_index)
state.finalized_checkpoint.epoch = spec.get_current_epoch(state) - 1
state.validators[activation_index].activation_eligibility_epoch = state.finalized_checkpoint.epoch
# ready for ejection
ejection_index = 2
state.validators[ejection_index].effective_balance = spec.EJECTION_BALANCE
yield from run_process_registry_updates(spec, state)
# validator moved into activation queue
validator = state.validators[activation_queue_index]
assert validator.activation_eligibility_epoch != spec.FAR_FUTURE_EPOCH
assert validator.activation_epoch == spec.FAR_FUTURE_EPOCH
assert not spec.is_active_validator(validator, spec.get_current_epoch(state))
# validator activated for future epoch
validator = state.validators[activation_index]
assert validator.activation_eligibility_epoch != spec.FAR_FUTURE_EPOCH
assert validator.activation_epoch != spec.FAR_FUTURE_EPOCH
assert not spec.is_active_validator(validator, spec.get_current_epoch(state))
assert spec.is_active_validator(
validator,
spec.compute_activation_exit_epoch(spec.get_current_epoch(state))
)
# validator ejected for future epoch
validator = state.validators[ejection_index]
assert validator.exit_epoch != spec.FAR_FUTURE_EPOCH
assert spec.is_active_validator(validator, spec.get_current_epoch(state))
assert not spec.is_active_validator(
validator,
spec.compute_activation_exit_epoch(spec.get_current_epoch(state))
)

View File

@ -3,7 +3,7 @@ from copy import deepcopy
from eth2spec.utils.ssz.ssz_impl import hash_tree_root
from eth2spec.utils.bls import bls_sign
from eth2spec.test.helpers.state import get_balance, state_transition_and_sign_block
from eth2spec.test.helpers.state import get_balance, state_transition_and_sign_block, next_slot
from eth2spec.test.helpers.block import build_empty_block_for_next_slot, build_empty_block, sign_block, \
transition_unsigned_block
from eth2spec.test.helpers.keys import privkeys, pubkeys
@ -253,6 +253,58 @@ def test_attester_slashing(spec, state):
)
@with_all_phases
@spec_state_test
def test_proposer_after_inactive_index(spec, state):
# disable some low validator index to check after for
inactive_index = 10
state.validators[inactive_index].exit_epoch = spec.get_current_epoch(state)
# skip forward, get brand new proposers
state.slot = spec.SLOTS_PER_EPOCH * 2
block = build_empty_block_for_next_slot(spec, state)
state_transition_and_sign_block(spec, state, block)
while True:
next_slot(spec, state)
proposer_index = spec.get_beacon_proposer_index(state)
if proposer_index > inactive_index:
# found a proposer that has a higher index than a disabled validator
yield 'pre', state
# test if the proposer can be recognized correctly after the inactive validator
signed_block = state_transition_and_sign_block(spec, state, build_empty_block(spec, state))
yield 'blocks', [signed_block]
yield 'post', state
break
@with_all_phases
@spec_state_test
def test_high_proposer_index(spec, state):
# disable a good amount of validators to make the active count lower, for a faster test
current_epoch = spec.get_current_epoch(state)
for i in range(len(state.validators) // 3):
state.validators[i].exit_epoch = current_epoch
# skip forward, get brand new proposers
state.slot = spec.SLOTS_PER_EPOCH * 2
block = build_empty_block_for_next_slot(spec, state)
state_transition_and_sign_block(spec, state, block)
active_count = len(spec.get_active_validator_indices(state, current_epoch))
while True:
next_slot(spec, state)
proposer_index = spec.get_beacon_proposer_index(state)
if proposer_index >= active_count:
# found a proposer that has a higher index than the active validator count
yield 'pre', state
# test if the proposer can be recognized correctly, even while it has a high index.
signed_block = state_transition_and_sign_block(spec, state, build_empty_block(spec, state))
yield 'blocks', [signed_block]
yield 'post', state
break
@with_all_phases
@spec_state_test
def test_expected_deposit_in_block(spec, state):

View File

@ -2,6 +2,6 @@
pytest>=4.4
../config_helpers
flake8==3.7.7
mypy==0.701
mypy==0.750
pytest-cov
pytest-xdist