Merge branch 'dev' into phase1rebase

This commit is contained in:
Danny Ryan 2020-01-03 07:49:23 -07:00
commit c9f52d0099
No known key found for this signature in database
GPG Key ID: 2765A792E42CE07A
36 changed files with 1208 additions and 451 deletions

View File

@ -48,13 +48,13 @@ commands:
description: "Restore the cache with deposit_contract keys"
steps:
- restore_cached_venv:
venv_name: v6-deposit-contract
venv_name: v7-deposit-contract
reqs_checksum: cache-{{ checksum "test_libs/pyspec/requirements.txt" }}-{{ checksum "deposit_contract/requirements-testing.txt" }}
save_deposit_contract_cached_venv:
description: Save a venv into a cache with deposit_contract keys"
steps:
- save_cached_venv:
venv_name: v6-deposit-contract
venv_name: v7-deposit-contract
reqs_checksum: cache-{{ checksum "test_libs/pyspec/requirements.txt" }}-{{ checksum "deposit_contract/requirements-testing.txt" }}
venv_path: ./deposit_contract/venv
jobs:
@ -103,6 +103,24 @@ 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
codespell:
docker:
- image: circleci/python:3.6
working_directory: ~/specs-repo
steps:
- checkout
- run:
name: Check codespell
command: pip install codespell --user && make codespell
lint:
docker:
- image: circleci/python:3.6
@ -148,6 +166,8 @@ workflows:
- test:
requires:
- install_pyspec_test
- table_of_contents
- codespell
- 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,17 @@ 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
codespell:
codespell . --skip ./.git -I .codespell-whitelist
lint: $(PY_SPEC_ALL_TARGETS)
cd $(PY_SPEC_DIR); . venv/bin/activate; \
flake8 --ignore=E252,W504,W503 --max-line-length=120 ./eth2spec \

View File

@ -142,6 +142,7 @@ DOMAIN_BEACON_ATTESTER: 0x01000000
DOMAIN_RANDAO: 0x02000000
DOMAIN_DEPOSIT: 0x03000000
DOMAIN_VOLUNTARY_EXIT: 0x04000000
DOMAIN_CUSTODY_BIT_CHALLENGE: 0x06000000
DOMAIN_SHARD_PROPOSER: 0x80000000
DOMAIN_SHARD_ATTESTER: 0x81000000
DOMAIN_SHARD_PROPOSAL: 0x80000000
DOMAIN_SHARD_COMMITTEE: 0x81000000
DOMAIN_LIGHT_CLIENT: 0x82000000
DOMAIN_CUSTODY_BIT_SLASHING: 0x83000000

View File

@ -145,9 +145,10 @@ DOMAIN_BEACON_ATTESTER: 0x01000000
DOMAIN_RANDAO: 0x02000000
DOMAIN_DEPOSIT: 0x03000000
DOMAIN_VOLUNTARY_EXIT: 0x04000000
DOMAIN_CUSTODY_BIT_CHALLENGE: 0x06000000
DOMAIN_SHARD_PROPOSER: 0x80000000
DOMAIN_SHARD_ATTESTER: 0x81000000
DOMAIN_SHARD_PROPOSAL: 0x80000000
DOMAIN_SHARD_COMMITTEE: 0x81000000
DOMAIN_LIGHT_CLIENT: 0x82000000
DOMAIN_CUSTODY_BIT_SLASHING: 0x83000000
# Phase 1

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,4 @@
# Vyper target 0.1.0b13
# Vyper target 0.1.0b13.hotfix1761
MIN_DEPOSIT_AMOUNT: constant(uint256) = 1000000000 # Gwei
DEPOSIT_CONTRACT_TREE_DEPTH: constant(uint256) = 32
MAX_DEPOSIT_COUNT: constant(uint256) = 4294967295 # 2**DEPOSIT_CONTRACT_TREE_DEPTH - 1

View File

@ -1,5 +1,5 @@
eth-tester[py-evm]==0.1.0b39
vyper==0.1.0b13
git+https://github.com/vyperlang/vyper@1761-HOTFIX-v0.1.0-beta.13
web3==5.0.0b2
pytest==3.6.1
../test_libs/pyspec

View File

@ -85,7 +85,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]
@ -129,8 +129,6 @@ def objects_to_spec(functions: Dict[str, str],
del functions[k]
functions_spec = '\n\n'.join(functions.values())
for k in list(constants.keys()):
if k.startswith('DOMAIN_'):
constants[k] = f"DomainType(({constants[k]}).to_bytes(length=4, byteorder='little'))"
if k == "BLS12_381_Q":
constants[k] += " # noqa: E501"
constants_spec = '\n'.join(map(lambda x: '%s = %s' % (x, constants[x]), constants))

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
@ -178,7 +182,7 @@ The following values are (non-configurable) constants used throughout the specif
| `MIN_GENESIS_ACTIVE_VALIDATOR_COUNT` | `2**14` (= 16,384) |
| `MIN_GENESIS_TIME` | `1578009600` (Jan 3, 2020) |
- For the safety of committees, `TARGET_COMMITTEE_SIZE` exceeds [the recommended minimum committee size of 111](https://vitalik.ca/files/Ithaca201807_Sharding.pdf); with sufficient active validators (at least `SLOTS_PER_EPOCH * TARGET_COMMITTEE_SIZE`), the shuffling algorithm ensures committee sizes of at least `TARGET_COMMITTEE_SIZE`. (Unbiasable randomness with a Verifiable Delay Function (VDF) will improve committee robustness and lower the safe minimum committee size.)
- For the safety of committees, `TARGET_COMMITTEE_SIZE` exceeds [the recommended minimum committee size of 111](http://web.archive.org/web/20190504131341/https://vitalik.ca/files/Ithaca201807_Sharding.pdf); with sufficient active validators (at least `SLOTS_PER_EPOCH * TARGET_COMMITTEE_SIZE`), the shuffling algorithm ensures committee sizes of at least `TARGET_COMMITTEE_SIZE`. (Unbiasable randomness with a Verifiable Delay Function (VDF) will improve committee robustness and lower the safe minimum committee size.)
### Gwei values
@ -195,7 +199,7 @@ The following values are (non-configurable) constants used throughout the specif
| - | - |
| `GENESIS_SLOT` | `Slot(0)` |
| `GENESIS_EPOCH` | `Epoch(0)` |
| `BLS_WITHDRAWAL_PREFIX` | `Bytes1(b'\x00')` |
| `BLS_WITHDRAWAL_PREFIX` | `Bytes1('0x00')` |
### Time parameters
@ -245,15 +249,13 @@ The following values are (non-configurable) constants used throughout the specif
### Domain types
The following types are defined, mapping into `DomainType` (little endian):
| Name | Value |
| - | - |
| `DOMAIN_BEACON_PROPOSER` | `0` |
| `DOMAIN_BEACON_ATTESTER` | `1` |
| `DOMAIN_RANDAO` | `2` |
| `DOMAIN_DEPOSIT` | `3` |
| `DOMAIN_VOLUNTARY_EXIT` | `4` |
| `DOMAIN_BEACON_PROPOSER` | `DomainType('0x00000000')` |
| `DOMAIN_BEACON_ATTESTER` | `DomainType('0x01000000')` |
| `DOMAIN_RANDAO` | `DomainType('0x02000000')` |
| `DOMAIN_DEPOSIT` | `DomainType('0x03000000')` |
| `DOMAIN_VOLUNTARY_EXIT` | `DomainType('0x04000000')` |
## Containers
@ -484,7 +486,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`
@ -556,7 +558,7 @@ def int_to_bytes(n: uint64, length: uint64) -> bytes:
```python
def bytes_to_int(data: bytes) -> uint64:
"""
Return the integer deserialization of ``data`` intepreted as ``ENDIANNESS``-endian.
Return the integer deserialization of ``data`` interpreted as ``ENDIANNESS``-endian.
"""
return int.from_bytes(data, ENDIANNESS)
```
@ -591,6 +593,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 +658,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(
@ -1296,26 +1326,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
@ -1475,6 +1501,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 tree 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

@ -1,3 +1,68 @@
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
- [Ethereum 2.0 Phase 1 -- The Beacon Chain for Shards](#ethereum-20-phase-1----the-beacon-chain-for-shards)
- [Table of contents](#table-of-contents)
- [Introduction](#introduction)
- [Custom types](#custom-types)
- [Configuration](#configuration)
- [Misc](#misc)
- [Updated containers](#updated-containers)
- [Extended `AttestationData`](#extended-attestationdata)
- [Extended `Attestation`](#extended-attestation)
- [Extended `PendingAttestation`](#extended-pendingattestation)
- [Extended `Validator`](#extended-validator)
- [Extended `BeaconBlockBody`](#extended-beaconblockbody)
- [Extended `BeaconBlock`](#extended-beaconblock)
- [Extended `SignedBeaconBlock`](#extended-signedbeaconblock)
- [Extended `BeaconState`](#extended-beaconstate)
- [New containers](#new-containers)
- [`ShardBlockWrapper`](#shardblockwrapper)
- [`ShardSignableHeader`](#shardsignableheader)
- [`ShardState`](#shardstate)
- [`ShardTransition`](#shardtransition)
- [`AttestationAndCommittee`](#attestationandcommittee)
- [`CompactCommittee`](#compactcommittee)
- [`AttestationCustodyBitWrapper`](#attestationcustodybitwrapper)
- [Helper functions](#helper-functions)
- [Crypto](#crypto)
- [`bls_verify_multiple`](#bls_verify_multiple)
- [Misc](#misc-1)
- [`pack_compact_validator`](#pack_compact_validator)
- [`committee_to_compact_committee`](#committee_to_compact_committee)
- [`chunks_to_body_root`](#chunks_to_body_root)
- [Beacon state accessors](#beacon-state-accessors)
- [`get_previous_slot`](#get_previous_slot)
- [`get_online_validator_indices`](#get_online_validator_indices)
- [`get_shard_committee`](#get_shard_committee)
- [`get_shard_proposer_index`](#get_shard_proposer_index)
- [`get_light_client_committee`](#get_light_client_committee)
- [`get_indexed_attestation`](#get_indexed_attestation)
- [`get_updated_gasprice`](#get_updated_gasprice)
- [`get_start_shard`](#get_start_shard)
- [`get_shard`](#get_shard)
- [`get_next_slot_for_shard`](#get_next_slot_for_shard)
- [`get_offset_slots`](#get_offset_slots)
- [Predicates](#predicates)
- [Updated `is_valid_indexed_attestation`](#updated-is_valid_indexed_attestation)
- [Block processing](#block-processing)
- [Operations](#operations)
- [New Attestation processing](#new-attestation-processing)
- [`validate_attestation`](#validate_attestation)
- [`apply_shard_transition`](#apply_shard_transition)
- [`process_crosslink_for_shard`](#process_crosslink_for_shard)
- [`process_crosslinks`](#process_crosslinks)
- [`process_attestations`](#process_attestations)
- [Shard transition false positives](#shard-transition-false-positives)
- [Light client processing](#light-client-processing)
- [Epoch transition](#epoch-transition)
- [Custody game updates](#custody-game-updates)
- [Online-tracking](#online-tracking)
- [Light client committee updates](#light-client-committee-updates)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
# Ethereum 2.0 Phase 1 -- The Beacon Chain for Shards
**Notice**: This document is a work-in-progress for researchers and implementers.
@ -47,9 +112,9 @@ Configuration is not namespaced. Instead it is strictly an extension;
| `MAX_GASPRICE` | `Gwei(2**14)` (= 16,384) | Gwei | |
| `MIN_GASPRICE` | `Gwei(2**5)` (= 32) | Gwei | |
| `GASPRICE_ADJUSTMENT_COEFFICIENT` | `2**3` (= 8) | |
| `DOMAIN_LIGHT_CLIENT` | `192` | |
| `DOMAIN_SHARD_COMMITTEE` | `192` | |
| `DOMAIN_SHARD_PROPOSAL` | `193` | |
| `DOMAIN_SHARD_PROPOSAL` | `DomainType('0x80000000')` | |
| `DOMAIN_SHARD_COMMITTEE` | `DomainType('0x81000000')` | |
| `DOMAIN_LIGHT_CLIENT` | `DomainType('0x82000000')` | |
## Updated containers

View File

@ -4,39 +4,39 @@
## 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)
- [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)
- [Data structures](#data-structures)
- [New beacon operations](#new-beacon-operations)
- [`CustodySlashing`](#custody-slashing)
- [`CustodyKeyReveal`](#custodykeyreveal)
- [`EarlyDerivedSecretReveal`](#earlyderivedsecretreveal)
- [Helpers](#helpers)
- [`legendre_bit`](#legendre_bit)
- [`get_custody_atoms`](#get_custody_atoms)
- [`compute_custody_bit`](#compute_custody_bit)
- [`get_randao_epoch_for_custody_period`](#get_randao_epoch_for_custody_period)
- [`get_custody_period_for_validator`](#get_custody_period_for_validator)
- [Per-block processing](#per-block-processing)
- [Custody Game Operations](#custody-game-operations)
- [Custody key reveals](#custody-key-reveals)
- [Early derived secret reveals](#early-derived-secret-reveals)
- [Custody Slashings](#custody-slashings)
- [Per-epoch processing](#per-epoch-processing)
- [Handling of reveal deadlines](#handling-of-reveal-deadlines)
- [Final updates](#final-updates)
<!-- /TOC -->
- [Introduction](#introduction)
- [Constants](#constants)
- [Misc](#misc)
- [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)
- [Data structures](#data-structures)
- [New Beacon Chain operations](#new-beacon-chain-operations)
- [`CustodySlashing`](#custodyslashing)
- [`SignedCustodySlashing`](#signedcustodyslashing)
- [`CustodyKeyReveal`](#custodykeyreveal)
- [`EarlyDerivedSecretReveal`](#earlyderivedsecretreveal)
- [Helpers](#helpers)
- [`legendre_bit`](#legendre_bit)
- [`custody_atoms`](#custody_atoms)
- [`compute_custody_bit`](#compute_custody_bit)
- [`get_randao_epoch_for_custody_period`](#get_randao_epoch_for_custody_period)
- [`get_custody_period_for_validator`](#get_custody_period_for_validator)
- [Per-block processing](#per-block-processing)
- [Custody Game Operations](#custody-game-operations)
- [Custody key reveals](#custody-key-reveals)
- [Early derived secret reveals](#early-derived-secret-reveals)
- [Custody Slashings](#custody-slashings)
- [Per-epoch processing](#per-epoch-processing)
- [Handling of reveal deadlines](#handling-of-reveal-deadlines)
- [Final updates](#final-updates)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
## Introduction
@ -81,8 +81,7 @@ The following types are defined, mapping into `DomainType` (little endian):
| Name | Value |
| - | - |
| `DOMAIN_CUSTODY_BIT_SLASHING` | `6` |
| `DOMAIN_CUSTODY_BIT_SLASHING` | `DomainType('0x83000000')` |
## Data structures

View File

@ -1,3 +1,16 @@
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
- [Ethereum 2.0 Phase 1 -- Shard Transition and Fraud Proofs](#ethereum-20-phase-1----shard-transition-and-fraud-proofs)
- [Table of contents](#table-of-contents)
- [Introduction](#introduction)
- [Fraud proofs](#fraud-proofs)
- [Shard state transition function](#shard-state-transition-function)
- [Honest committee member behavior](#honest-committee-member-behavior)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
# Ethereum 2.0 Phase 1 -- Shard Transition and Fraud Proofs
**Notice**: This document is a work-in-progress for researchers and implementers.

View File

@ -1,3 +1,17 @@
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
- [Ethereum 2.0 Phase 1 -- From Phase 0 to Phase 1](#ethereum-20-phase-1----from-phase-0-to-phase-1)
- [Table of contents](#table-of-contents)
- [Introduction](#introduction)
- [Configuration](#configuration)
- [Fork to Phase 1](#fork-to-phase-1)
- [Fork trigger.](#fork-trigger)
- [Upgrading the state](#upgrading-the-state)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
# Ethereum 2.0 Phase 1 -- From Phase 0 to Phase 1
**Notice**: This document is a work-in-progress for researchers and implementers.

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,89 @@ 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)
- [Attestation subnet bitfield](#attestation-subnet-bitfield)
- [Interop](#interop-5)
- [Mainnet](#mainnet-5)
- [Topic advertisement](#topic-advertisement)
- [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 we overriding the default libp2p pubsub `message-id`?](#why-are-we-overriding-the-default-libp2p-pubsub-message-id)
- [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 -->
@ -147,6 +213,13 @@ Topics are plain UTF-8 strings and are encoded on the wire as determined by prot
Each gossipsub [message](https://github.com/libp2p/go-libp2p-pubsub/blob/master/pb/rpc.proto#L17-L24) has a maximum size of `GOSSIP_MAX_SIZE`. Clients MUST reject (fail validation) messages that are over this size limit. Likewise, clients MUST NOT emit or propagate messages larger than this limit.
The `message-id` of a gossipsub message MUST be:
```python
message-id: base64(SHA256(message.data))
```
where `base64` is the [URL-safe base64 alphabet](https://tools.ietf.org/html/rfc4648#section-3.2) with padding characters omitted.
The payload is carried in the `data` field of a gossipsub message, and varies depending on the topic:
| Topic | Message Type |
@ -356,7 +429,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.
@ -372,6 +445,8 @@ Clients SHOULD immediately disconnect from one another following the handshake a
Once the handshake completes, the client with the lower `finalized_epoch` or `head_slot` (if the clients have equal `finalized_epoch`s) SHOULD request beacon blocks from its counterparty via the `BeaconBlocksByRange` request.
*Note*: Under abnormal network condition or after some rounds of `BeaconBlocksByRange` requests, the client might need to send `Status` request again to learn if the peer has a higher head. Implementers are free to implement such behavior in their own way.
#### Goodbye
**Protocol ID:** ``/eth2/beacon_chain/req/goodbye/1/``
@ -492,6 +567,14 @@ The Ethereum Node Record (ENR) for an Ethereum 2.0 client MUST contain the follo
Specifications of these parameters can be found in the [ENR Specification](http://eips.ethereum.org/EIPS/eip-778).
#### Attestation subnet bitfield
The ENR MAY contain an entry (`attnets`) signifying the attestation subnet bitfield with the following form to more easily discover peers participating in particular attestation gossip subnets.
| Key | Value |
|:-------------|:-------------------------------------------------|
| `attnets` | SSZ `Bitvector[ATTESTATION_SUBNET_COUNT]` |
#### Interop
In the interoperability testnet, all peers will support all capabilities defined in this document (gossip, full Req/Resp suite, discovery protocol), therefore the ENR record does not need to carry Eth2 capability information, as it would be superfluous.
@ -504,13 +587,11 @@ On mainnet, ENRs MUST include a structure enumerating the capabilities offered b
### Topic advertisement
#### Interop
This feature will not be used in the interoperability testnet.
#### Mainnet
In mainnet, we plan to use discv5s topic advertisement feature as a rendezvous facility for peers on shards (thus subscribing to the relevant gossipsub topics).
discv5's topic advertisement feature is not expected to be ready for mainnet launch of Phase 0.
Once this feature is built out and stable, we expect to use topic advertisement as a rendezvous facility for peers on shards. Until then, the ENR [attestation subnet bitfield](#attestation-subnet-bitfield) will be used for discovery of peers on particular subnets.
# Design decision rationale
@ -567,7 +648,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?
@ -673,6 +754,16 @@ No security or privacy guarantees are lost as a result of choosing plaintext top
Furthermore, the Eth2 topic names are shorter than their digest equivalents (assuming SHA-256 hash), so hashing topics would bloat messages unnecessarily.
## Why are we overriding the default libp2p pubsub `message-id`?
For our current purposes, there is no need to address messages based on source peer, and it seems likely we might even override the message `from` to obfuscate the peer. By overriding the default `message-id` to use content-addressing we can filter unnecessary duplicates before hitting the application layer.
Some examples of where messages could be duplicated:
* A validator client connected to multiple beacon nodes publishing duplicate gossip messages
* Attestation aggregation strategies where clients partially aggregate attestations and propagate them. Partial aggregates could be duplicated
* Clients re-publishing seen messages
### Why are there `ATTESTATION_SUBNET_COUNT` attestation subnets?
Depending on the number of validators, it may be more efficient to group shard subnets and might provide better stability for the gossipsub channel. The exact grouping will be dependent on more involved network tests. This constant allows for more flexibility in setting up the network topology for attestation aggregation (as aggregation should happen on each subnet). The value is currently set to to be equal `MAX_COMMITTEES_PER_SLOT` until network tests indicate otherwise.
@ -699,9 +790,9 @@ The prohibition of unverified-block-gossiping extends to nodes that cannot verif
### How are we going to discover peers in a gossipsub topic?
Via discv5 topics. ENRs should not be used for this purpose, as they store identity, location, and capability information, not volatile [advertisements](#topic-advertisement).
In Phase 0, peers for attestation subnets will be found using the `attnets` entry in the ENR.
In the interoperability testnet, all peers will be subscribed to all global beacon chain topics, so discovering peers in specific shard topics will be unnecessary.
Although this method will be sufficient for early phases of Eth2, we aim to use the more appropriate discv5 topics for this and other similar tasks in the future. ENRs should ultimately not be used for this purpose. They are best suited to store identity, location, and capability information, rather than more volatile advertisements.
## Req/Resp

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,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
@ -99,8 +101,8 @@ This document describes the shard transition function (data layer only) and the
| Name | Value |
| - | - |
| `DOMAIN_SHARD_PROPOSER` | `128` |
| `DOMAIN_SHARD_ATTESTER` | `129` |
| `DOMAIN_SHARD_PROPOSER` | `DomainType('0x80000000')` |
| `DOMAIN_SHARD_ATTESTER` | `DomainType('0x81000000')` |
## Containers

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`
@ -151,7 +150,7 @@ Template:
Data:
{container name}: Any of the container names listed below (exluding the `(Container)` python super type)
{container name}: Any of the container names listed below (excluding the `(Container)` python super type)
```
```python

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
@ -194,8 +197,8 @@ The beacon chain shufflings are designed to provide a minimum of 1 epoch lookahe
Specifically a validator should:
* Call `get_committee_assignment(state, next_epoch, validator_index)` when checking for next epoch assignments.
* Join the pubsub topic -- `committee_index{committee_index % ATTESTATION_SUBNET_COUNT}_beacon_attestation`.
* If any current peers are subscribed to the topic, the validator simply sends `subscribe` messages for the new topic.
* If no current peers are subscribed to the topic, the validator must discover new peers on this topic. If "topic discovery" is available, use topic discovery to find peers that advertise subscription to the topic. If not, "guess and check" by connecting with a number of random new peers, persisting connections with peers subscribed to the topic and (potentially) dropping the new peers otherwise.
* For any current peer subscribed to the topic, the validator simply sends a `subscribe` message for the new topic.
* If an _insufficient_ number of current peers are subscribed to the topic, the validator must discover new peers on this topic. Via the discovery protocol, find peers with an ENR containing the `attnets` entry such that `ENR["attnets"][committee_index % ATTESTATION_SUBNET_COUNT] == True`.
## Beacon chain responsibilities
@ -440,7 +443,11 @@ Where
## Phase 0 attestation subnet stability
Because Phase 0 does not have shards and thus does not have Shard Committees, there is no stable backbone to the attestation subnets (`committee_index{subnet_id}_beacon_attestation`). To provide this stability, each validator must randomly select and remain subscribed to `RANDOM_SUBNETS_PER_VALIDATOR` attestation subnets. The lifetime of each random subscription should be a random number of epochs between `EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION` and `2 * EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION]`.
Because Phase 0 does not have shards and thus does not have Shard Committees, there is no stable backbone to the attestation subnets (`committee_index{subnet_id}_beacon_attestation`). To provide this stability, each validator must:
* Randomly select and remain subscribed to `RANDOM_SUBNETS_PER_VALIDATOR` attestation subnets
* Maintain advertisement of the randomly selected subnets in their node's ENR `attnets` entry by setting the randomly selected `subnet_id` bits to `True` (e.g. `ENR["attnets"][subnet_id] = True`) for all persistent attestation subnets
* Set the lifetime of each random subscription to a random number of epochs between `EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION` and `2 * EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION]`. At the end of life for a subscription, select a new random subnet, update subnet subscriptions, and publish an updated ENR
## How to avoid slashing

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)
# The signature will be valid for a single occurrence. 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)
# The signature will be valid for a single occurrence. 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

@ -155,7 +155,7 @@ def test_duplicate_attestation(spec, state):
next_epoch(spec, single_state)
next_epoch(spec, dup_state)
# Run non-duplicate inclusion rewards for comparision. Do not yield test vectors
# Run non-duplicate inclusion rewards for comparison. Do not yield test vectors
for _ in run_process_rewards_and_penalties(spec, single_state):
pass

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
@ -83,7 +83,7 @@ def test_invalid_state_root(spec, state):
expect_assertion_error(lambda: spec.state_transition(state, signed_block))
yield 'blocks', [block]
yield 'blocks', [signed_block]
yield 'post', None
@ -91,6 +91,8 @@ def test_invalid_state_root(spec, state):
@spec_state_test
@always_bls
def test_zero_block_sig(spec, state):
yield 'pre', state
block = build_empty_block_for_next_slot(spec, state)
invalid_signed_block = spec.SignedBeaconBlock(message=block)
expect_assertion_error(lambda: spec.state_transition(state, invalid_signed_block))
@ -103,6 +105,8 @@ def test_zero_block_sig(spec, state):
@spec_state_test
@always_bls
def test_invalid_block_sig(spec, state):
yield 'pre', state
block = build_empty_block_for_next_slot(spec, state)
invalid_signed_block = spec.SignedBeaconBlock(
message=block,
@ -253,6 +257,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

@ -451,10 +451,15 @@ class BaseBytes(bytes, Elements, metaclass=BytesType):
@classmethod
def extract_args(cls, *args):
x = args
if len(x) == 1 and isinstance(x[0], (GeneratorType, bytes)):
if len(x) == 1 and isinstance(x[0], (GeneratorType, bytes, str)):
x = x[0]
if isinstance(x, bytes): # Includes BytesLike
return x
if isinstance(x, str):
if x[:2] == '0x':
return bytes.fromhex(x[2:])
else:
return bytes.fromhex(x)
else:
return bytes(x) # E.g. GeneratorType put into bytes.

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

View File

@ -1,6 +1,6 @@
eth-utils>=1.3.0,<2
eth-typing>=2.1.0,<3.0.0
pycryptodome==3.7.3
pycryptodome==3.9.4
py_ecc==1.7.1
dataclasses==0.6
ssz==0.1.3

View File

@ -7,7 +7,7 @@ setup(
install_requires=[
"eth-utils>=1.3.0,<2",
"eth-typing>=2.1.0,<3.0.0",
"pycryptodome==3.7.3",
"pycryptodome==3.9.4",
"py_ecc==1.7.1",
"ssz==0.1.3",
"dataclasses==0.6",