diff --git a/.gitignore b/.gitignore index bcd96f8858..ed497112c4 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,7 @@ eth2.0-spec-tests/ # Dynamically built from Markdown spec tests/core/pyspec/eth2spec/phase0/ tests/core/pyspec/eth2spec/phase1/ +tests/core/pyspec/eth2spec/lightclient/ # coverage reports .htmlcov diff --git a/Makefile b/Makefile index 8fa1044445..3d79aea55e 100644 --- a/Makefile +++ b/Makefile @@ -112,7 +112,7 @@ codespell: lint: pyspec . venv/bin/activate; cd $(PY_SPEC_DIR); \ flake8 --config $(LINTER_CONFIG_FILE) ./eth2spec \ - && mypy --config-file $(LINTER_CONFIG_FILE) -p eth2spec.phase0 -p eth2spec.phase1 + && mypy --config-file $(LINTER_CONFIG_FILE) -p eth2spec.phase0 -p eth2spec.phase1 -p eth2spec.lightclient lint_generators: pyspec . venv/bin/activate; cd $(TEST_GENERATORS_DIR); \ diff --git a/setup.py b/setup.py index 9c2de0751b..63266cbe38 100644 --- a/setup.py +++ b/setup.py @@ -156,6 +156,40 @@ def get_spec(file_name: str) -> SpecObject: CONFIG_NAME = 'mainnet' ''' +LIGHTCLIENT_IMPORT = '''from eth2spec.phase0 import spec as phase0 +from eth2spec.config.config_util import apply_constants_config +from typing import ( + Any, Dict, Set, Sequence, NewType, Tuple, TypeVar, Callable, Optional +) + +from dataclasses import ( + dataclass, + field, +) + +from lru import LRU + +from eth2spec.utils.ssz.ssz_impl import hash_tree_root, copy, uint_to_bytes +from eth2spec.utils.ssz.ssz_typing import ( + View, boolean, Container, List, Vector, uint8, uint32, uint64, + Bytes1, Bytes4, Bytes32, Bytes48, Bytes96, Bitlist, +) +from eth2spec.utils import bls + +from eth2spec.utils.hash_function import hash + +# Whenever lightclient is loaded, make sure we have the latest phase0 +from importlib import reload +reload(phase0) + + +SSZVariableName = str +GeneralizedIndex = NewType('GeneralizedIndex', int) +SSZObject = TypeVar('SSZObject', bound=View) + +CONFIG_NAME = 'mainnet' +''' + SUNDRY_CONSTANTS_FUNCTIONS = ''' def ceillog2(x: int) -> uint64: if x < 1: @@ -351,6 +385,7 @@ def combine_spec_objects(spec0: SpecObject, spec1: SpecObject) -> SpecObject: fork_imports = { 'phase0': PHASE0_IMPORTS, 'phase1': PHASE1_IMPORTS, + 'lightclient': LIGHTCLIENT_IMPORT, } @@ -417,6 +452,14 @@ def finalize_options(self): specs/phase1/shard-fork-choice.md specs/phase1/validator.md """ + elif self.spec_fork == "lightclient": + self.md_doc_paths = """ + specs/phase0/beacon-chain.md + specs/phase0/fork-choice.md + specs/phase0/validator.md + specs/phase0/weak-subjectivity.md + specs/lightclient/beacon-chain.md + """ else: raise Exception('no markdown files specified, and spec fork "%s" is unknown', self.spec_fork) diff --git a/specs/lightclient/beacon-chain.md b/specs/lightclient/beacon-chain.md index 4f6e07dd52..2b05f4fbea 100644 --- a/specs/lightclient/beacon-chain.md +++ b/specs/lightclient/beacon-chain.md @@ -70,7 +70,17 @@ This is a standalone beacon chain patch adding light client support via sync com #### `BeaconBlockBody` ```python -class BeaconBlockBody(phase0.BeaconBlockBody): +class BeaconBlockBody(Container): + randao_reveal: BLSSignature + eth1_data: Eth1Data # Eth1 data vote + graffiti: Bytes32 # Arbitrary data + # Operations + proposer_slashings: List[ProposerSlashing, MAX_PROPOSER_SLASHINGS] + attester_slashings: List[AttesterSlashing, MAX_ATTESTER_SLASHINGS] + attestations: List[Attestation, MAX_ATTESTATIONS] + deposits: List[Deposit, MAX_DEPOSITS] + voluntary_exits: List[SignedVoluntaryExit, MAX_VOLUNTARY_EXITS] + # Lightclient sync_committee_bits: Bitlist[MAX_SYNC_COMMITTEE_SIZE] sync_committee_signature: BLSSignature ``` @@ -78,7 +88,7 @@ class BeaconBlockBody(phase0.BeaconBlockBody): #### `BeaconState` ```python -class BeaconState(phase0.BeaconState): +class BeaconState(Container): current_sync_committee: SyncCommittee next_sync_committee: SyncCommittee ``` @@ -133,7 +143,7 @@ def get_sync_committee_indices(state: BeaconState, epoch: Epoch) -> Sequence[Val start_epoch = Epoch((max(epoch // EPOCHS_PER_SYNC_COMMITTEE_PERIOD, 1) - 1) * EPOCHS_PER_SYNC_COMMITTEE_PERIOD) active_validator_count = uint64(len(get_active_validator_indices(state, start_epoch))) sync_committee_size = min(active_validator_count, MAX_SYNC_COMMITTEE_SIZE) - seed = get_seed(state, base_epoch, DOMAIN_SYNC_COMMITTEE) + seed = get_seed(state, start_epoch, DOMAIN_SYNC_COMMITTEE) return [compute_shuffled_index(uint64(i), active_validator_count, seed) for i in range(sync_committee_size)] ``` @@ -148,7 +158,7 @@ def get_sync_committee(state: BeaconState, epoch: Epoch) -> SyncCommittee: validators = [state.validators[index] for index in indices] pubkeys = [validator.pubkey for validator in validators] compact_validators = [compactify_validator(i, v.slashed, v.effective_balance) for i, v in zip(indices, validators)] - return SyncCommittee(pubkeys, bls.AggregatePubkeys(pubkeys), compact_validators) + return SyncCommittee(pubkeys, bls.AggregatePKs(pubkeys), compact_validators) ``` ### Block processing