From 4c90c357b728b4e486f29cb4ed169d4652ec52a0 Mon Sep 17 00:00:00 2001 From: protolambda Date: Thu, 8 Oct 2020 20:34:59 +0200 Subject: [PATCH 01/56] remove yaml duplicates, compress SSZ test outputs --- tests/core/gen_helpers/gen_base/gen_runner.py | 6 ++++-- tests/core/gen_helpers/requirements.txt | 1 + tests/core/gen_helpers/setup.py | 1 + tests/core/pyspec/eth2spec/test/utils.py | 6 +----- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/core/gen_helpers/gen_base/gen_runner.py b/tests/core/gen_helpers/gen_base/gen_runner.py index a22073c00..1cf8ba8cf 100644 --- a/tests/core/gen_helpers/gen_base/gen_runner.py +++ b/tests/core/gen_helpers/gen_base/gen_runner.py @@ -9,6 +9,7 @@ from ruamel.yaml import ( ) from gen_base.gen_typing import TestProvider +from snappy import compress from eth2spec.test import context from eth2spec.test.exceptions import SkippedTest @@ -180,7 +181,8 @@ def dump_yaml_fn(data: Any, name: str, file_mode: str, yaml_encoder: YAML): def dump_ssz_fn(data: AnyStr, name: str, file_mode: str): def dump(case_path: Path): - out_path = case_path / Path(name + '.ssz') + out_path = case_path / Path(name + '.ssz_snappy') + compressed = compress(data) with out_path.open(file_mode + 'b') as f: # write in raw binary mode - f.write(data) + f.write(compressed) return dump diff --git a/tests/core/gen_helpers/requirements.txt b/tests/core/gen_helpers/requirements.txt index e7cdd30ea..a2c194dea 100644 --- a/tests/core/gen_helpers/requirements.txt +++ b/tests/core/gen_helpers/requirements.txt @@ -1,3 +1,4 @@ ruamel.yaml==0.16.5 eth-utils==1.6.0 pytest>=4.4 +python-snappy==0.5.4 diff --git a/tests/core/gen_helpers/setup.py b/tests/core/gen_helpers/setup.py index e9fc1a787..d26530642 100644 --- a/tests/core/gen_helpers/setup.py +++ b/tests/core/gen_helpers/setup.py @@ -7,5 +7,6 @@ setup( "ruamel.yaml==0.16.5", "eth-utils==1.6.0", "pytest>=4.4", + "python-snappy==0.5.4", ] ) diff --git a/tests/core/pyspec/eth2spec/test/utils.py b/tests/core/pyspec/eth2spec/test/utils.py index 12ff68443..306f7d892 100644 --- a/tests/core/pyspec/eth2spec/test/utils.py +++ b/tests/core/pyspec/eth2spec/test/utils.py @@ -39,24 +39,20 @@ def vector_test(description: str = None): if value is None: continue if isinstance(value, View): - yield key, 'data', encode(value) yield key, 'ssz', serialize(value) elif isinstance(value, bytes): - yield key, 'data', encode(value) yield key, 'ssz', value elif isinstance(value, list) and all([isinstance(el, (View, bytes)) for el in value]): for i, el in enumerate(value): if isinstance(el, View): - yield f'{key}_{i}', 'data', encode(el) yield f'{key}_{i}', 'ssz', serialize(el) elif isinstance(el, bytes): - yield f'{key}_{i}', 'data', encode(el) yield f'{key}_{i}', 'ssz', el yield f'{key}_count', 'meta', len(value) else: # Not a ssz value. # The data will now just be yielded as any python data, - # something that should be encodeable by the generator runner. + # something that should be encodable by the generator runner. yield key, 'data', value # check generator mode, may be None/else. From 8bbc5f7fc3967fe2d65680c6450497795aab0b67 Mon Sep 17 00:00:00 2001 From: protolambda Date: Thu, 8 Oct 2020 21:02:18 +0200 Subject: [PATCH 02/56] update test format docs --- tests/formats/README.md | 28 ++++++++++-------- tests/formats/epoch_processing/README.md | 13 +++------ tests/formats/finality/README.md | 14 ++++----- tests/formats/genesis/initialization.md | 17 ++++------- tests/formats/genesis/validity.md | 5 ++-- tests/formats/operations/README.md | 18 ++++-------- tests/formats/rewards/README.md | 36 ++++++++---------------- tests/formats/sanity/blocks.md | 18 ++++-------- tests/formats/sanity/slots.md | 4 +-- tests/formats/ssz_generic/README.md | 8 +++--- tests/formats/ssz_static/core.md | 8 +++--- 11 files changed, 68 insertions(+), 101 deletions(-) diff --git a/tests/formats/README.md b/tests/formats/README.md index 36a5ec21b..d3933abdd 100644 --- a/tests/formats/README.md +++ b/tests/formats/README.md @@ -132,21 +132,25 @@ Cases are split up too. This enables diffing of parts of the test case, tracking ### `` -E.g. `pre.yaml`, `deposit.yaml`, `post.yaml`. - -Diffing a `pre.yaml` and `post.yaml` provides all the information for testing, good for readability of the change. -Then the difference between pre and post can be compared to anything that changes the pre state, e.g. `deposit.yaml` - These files allow for custom formats for some parts of the test. E.g. something encoded in SSZ. +Or to avoid large files, the SSZ can be compressed with Snappy. +E.g. `pre.ssz_snappy_snappy`, `deposit.ssz_snappy_snappy`, `post.ssz_snappy_snappy`. -Some yaml files have copies, but formatted as raw SSZ bytes: `pre.ssz`, `deposit.ssz`, `post.ssz`. -The yaml files are intended to be deprecated, and clients should shift to ssz inputs for efficiency. -Deprecation will start once a viewer of SSZ test-cases is in place, to maintain a standard of readable test cases. -This also means that some clients can drop legacy YAML -> JSON/other -> SSZ work-arounds. -(These were implemented to support the uint64 YAML, hex strings, etc. Things that were not idiomatic to their language.) +Diffing a `pre.ssz_snappy_snappy` and `post.ssz_snappy_snappy` provides all the information for testing, when decompressed and decoded. +Then the difference between pre and post can be compared to anything that changes the pre state, e.g. `deposit.ssz_snappy_snappy` + +YAML is generally used for test metadata, and for tests that do not use SSZ: e.g. shuffling and BLS tests. +In this case, there is no point in adding special SSZ types. And the size and efficiency of YAML is acceptable. + +#### Common output formats + +Between all types of tests, a few formats are common: + +- **`.yaml`**: A YAML file containing structured data to describe settings or test contents. +- **`.ssz_snappy`**: A file containing raw SSZ-encoded data. Previously widely used in tests, but replaced with compressed variant. +- **`.ssz_snappy_snappy`**: Like `.ssz_snappy`, but compressed with Snappy block compression. + Snappy block compression is already applied to SSZ in Eth2 gossip, available in client implementations, and thus chosen as compression method. -Yaml will not be deprecated for tests that do not use SSZ: e.g. shuffling and BLS tests. -In this case, there is no work around for loading necessary anyway, and the size and efficiency of yaml is acceptable. #### Special output parts diff --git a/tests/formats/epoch_processing/README.md b/tests/formats/epoch_processing/README.md index 57c9441c8..bc15e64b6 100644 --- a/tests/formats/epoch_processing/README.md +++ b/tests/formats/epoch_processing/README.md @@ -15,18 +15,13 @@ description: string -- Optional description of test case, purely for debuggin bls_setting: int -- see general test-format spec. ``` -### `pre.yaml` +### `pre.ssz_snappy` -A YAML-encoded `BeaconState`, the state before running the epoch sub-transition. +A SSZ-snappy encoded `BeaconState`, the state before running the epoch sub-transition. -Also available as `pre.ssz`. +### `post.ssz_snappy` - -### `post.yaml` - -A YAML-encoded `BeaconState`, the state after applying the epoch sub-transition. - -Also available as `post.ssz`. +A SSZ-snappy encoded `BeaconState`, the state after applying the epoch sub-transition. ## Condition diff --git a/tests/formats/finality/README.md b/tests/formats/finality/README.md index da9108a6a..2d279b441 100644 --- a/tests/formats/finality/README.md +++ b/tests/formats/finality/README.md @@ -14,11 +14,11 @@ bls_setting: int -- see general test-format spec. blocks_count: int -- the number of blocks processed in this test. ``` -### `pre.yaml` +### `pre.ssz_snappy` -A YAML-encoded `BeaconState`, the state before running the block transitions. +A SSZ-snappy encoded `BeaconState`, the state before running the block transitions. -Also available as `pre.ssz`. +Also available as `pre.ssz_snappy`. ### `blocks_.yaml` @@ -28,13 +28,11 @@ A series of files, with `` in range `[0, blocks_count)`. Blocks need to b Each file is a YAML-encoded `SignedBeaconBlock`. -Each block is also available as `blocks_.ssz` +Each block is also available as `blocks_.ssz_snappy` -### `post.yaml` +### `post.ssz_snappy` -A YAML-encoded `BeaconState`, the state after applying the block transitions. - -Also available as `post.ssz`. +A SSZ-snappy encoded `BeaconState`, the state after applying the block transitions. ## Condition diff --git a/tests/formats/genesis/initialization.md b/tests/formats/genesis/initialization.md index 428abb5bd..2e5452821 100644 --- a/tests/formats/genesis/initialization.md +++ b/tests/formats/genesis/initialization.md @@ -4,11 +4,9 @@ Tests the initialization of a genesis state based on Eth1 data. ## Test case format -### `eth1_block_hash.yaml` +### `eth1_block_hash.ssz_snappy` -A `Bytes32` hex encoded, with prefix 0x. The root of the Eth1 block. - -Also available as `eth1_block_hash.ssz`. +A SSZ-snappy encoded root of the Eth1 block. ### `eth1_timestamp.yaml` @@ -22,18 +20,15 @@ A yaml file to help read the deposit count: deposits_count: int -- Amount of deposits. ``` -### `deposits_.yaml` +### `deposits_.ssz_snappy` A series of files, with `` in range `[0, deposits_count)`. Deposits need to be processed in order. -Each file is a YAML-encoded `Deposit` object. +Each file is a SSZ-snappy encoded `Deposit` object. -Each deposit is also available as `deposits_.ssz`. +### `state.ssz_snappy` -### `state.yaml` +The expected genesis state. A SSZ-snappy encoded `BeaconState` object. -The expected genesis state. A YAML-encoded `BeaconState` object. - -Also available as `state.ssz`. ## Processing diff --git a/tests/formats/genesis/validity.md b/tests/formats/genesis/validity.md index 38f2b1b1f..1b3f79879 100644 --- a/tests/formats/genesis/validity.md +++ b/tests/formats/genesis/validity.md @@ -4,11 +4,10 @@ Tests if a genesis state is valid, i.e. if it counts as trigger to launch. ## Test case format -### `genesis.yaml` +### `genesis.ssz_snappy` -A `BeaconState`, the state to validate as genesis candidate. +A SSZ-snappy encoded `BeaconState`, the state to validate as genesis candidate. -Also available as `genesis.ssz`. ### `is_valid.yaml` diff --git a/tests/formats/operations/README.md b/tests/formats/operations/README.md index bb4636ec0..ca77ab966 100644 --- a/tests/formats/operations/README.md +++ b/tests/formats/operations/README.md @@ -12,23 +12,17 @@ description: string -- Optional description of test case, purely for debuggin bls_setting: int -- see general test-format spec. ``` -### `pre.yaml` +### `pre.ssz_snappy` -A YAML-encoded `BeaconState`, the state before applying the operation. +A SSZ-snappy encoded `BeaconState`, the state before applying the operation. -Also available as `pre.ssz`. +### `.ssz_snappy` -### `.yaml` +A SSZ-snappy encoded operation object, e.g. a `ProposerSlashing`, or `Deposit`. -A YAML-encoded operation object, e.g. a `ProposerSlashing`, or `Deposit`. +### `post.ssz_snappy` -Also available as `.ssz`. - -### `post.yaml` - -A YAML-encoded `BeaconState`, the state after applying the operation. No value if operation processing is aborted. - -Also available as `post.ssz`. +A SSZ-snappy encoded `BeaconState`, the state after applying the operation. No value if operation processing is aborted. ## Condition diff --git a/tests/formats/rewards/README.md b/tests/formats/rewards/README.md index b229d9f98..aee23c3e9 100644 --- a/tests/formats/rewards/README.md +++ b/tests/formats/rewards/README.md @@ -23,41 +23,29 @@ description: string -- Optional description of test case, purely for debuggin _Note_: No signature verification happens within rewards sub-functions. These tests can safely be run with or without BLS enabled. -### `pre.yaml` +### `pre.ssz_snappy` -A YAML-encoded `BeaconState`, the state before running the rewards sub-function. +A SSZ-snappy encoded `BeaconState`, the state before running the rewards sub-function. -Also available as `pre.ssz`. +### `source_deltas.ssz_snappy` -### `source_deltas.yaml` +A SSZ-snappy encoded `Deltas` representing the rewards and penalties returned by the rewards the `get_source_deltas` function -A YAML-encoded `Deltas` representing the rewards and penalties returned by the rewards the `get_source_deltas` function +### `target_deltas.ssz_snappy` -Also available as `source_deltas.ssz`. +A SSZ-snappy encoded `Deltas` representing the rewards and penalties returned by the rewards the `get_target_deltas` function -### `target_deltas.yaml` +### `head_deltas.ssz_snappy` -A YAML-encoded `Deltas` representing the rewards and penalties returned by the rewards the `get_target_deltas` function +A SSZ-snappy encoded `Deltas` representing the rewards and penalties returned by the rewards the `get_head_deltas` function -Also available as `target_deltas.ssz`. +### `inclusion_delay_deltas.ssz_snappy` -### `head_deltas.yaml` +A SSZ-snappy encoded `Deltas` representing the rewards and penalties returned by the rewards the `get_inclusion_delay_deltas` function -A YAML-encoded `Deltas` representing the rewards and penalties returned by the rewards the `get_head_deltas` function +### `inactivity_penalty_deltas.ssz_snappy` -Also available as `head_deltas.ssz`. - -### `inclusion_delay_deltas.yaml` - -A YAML-encoded `Deltas` representing the rewards and penalties returned by the rewards the `get_inclusion_delay_deltas` function - -Also available as `inclusion_delay_deltas.ssz`. - -### `inactivity_penalty_deltas.yaml` - -A YAML-encoded `Deltas` representing the rewards and penalties returned by the rewards the `get_inactivity_penalty_deltas` function - -Also available as `inactivity_penalty_deltas.ssz`. +A SSZ-snappy encoded `Deltas` representing the rewards and penalties returned by the rewards the `get_inactivity_penalty_deltas` function ## Condition diff --git a/tests/formats/sanity/blocks.md b/tests/formats/sanity/blocks.md index 44b37ed5e..a8b38ccae 100644 --- a/tests/formats/sanity/blocks.md +++ b/tests/formats/sanity/blocks.md @@ -14,27 +14,21 @@ blocks_count: int -- the number of blocks processed in this test. ``` -### `pre.yaml` +### `pre.ssz_snappy` -A YAML-encoded `BeaconState`, the state before running the block transitions. - -Also available as `pre.ssz`. +A SSZ-snappy encoded `BeaconState`, the state before running the block transitions. -### `blocks_.yaml` +### `blocks_.ssz_snappy` A series of files, with `` in range `[0, blocks_count)`. Blocks need to be processed in order, following the main transition function (i.e. process slot and epoch transitions in between blocks as normal) -Each file is a YAML-encoded `SignedBeaconBlock`. +Each file is a SSZ-snappy encoded `SignedBeaconBlock`. -Each block is also available as `blocks_.ssz` +### `post.ssz_snappy` -### `post.yaml` - -A YAML-encoded `BeaconState`, the state after applying the block transitions. - -Also available as `post.ssz`. +A SSZ-snappy encoded `BeaconState`, the state after applying the block transitions. ## Condition diff --git a/tests/formats/sanity/slots.md b/tests/formats/sanity/slots.md index 353287ee2..72a24da51 100644 --- a/tests/formats/sanity/slots.md +++ b/tests/formats/sanity/slots.md @@ -16,7 +16,7 @@ bls_setting: int -- see general test-format spec. A YAML-encoded `BeaconState`, the state before running the transitions. -Also available as `pre.ssz`. +Also available as `pre.ssz_snappy`. ### `slots.yaml` @@ -27,7 +27,7 @@ An integer. The amount of slots to process (i.e. the difference in slots between A YAML-encoded `BeaconState`, the state after applying the transitions. -Also available as `post.ssz`. +Also available as `post.ssz_snappy`. ### Processing diff --git a/tests/formats/ssz_generic/README.md b/tests/formats/ssz_generic/README.md index 68bdbc15f..85a507985 100644 --- a/tests/formats/ssz_generic/README.md +++ b/tests/formats/ssz_generic/README.md @@ -33,7 +33,7 @@ Each of the handlers encodes the SSZ type declaration in the file-name. See [Typ ### `valid` -Valid has 3 parts: `meta.yaml`, `serialized.ssz`, `value.yaml` +Valid has 3 parts: `meta.yaml`, `serialized.ssz_snappy`, `value.yaml` ### `meta.yaml` @@ -46,9 +46,9 @@ root: Bytes32 -- Hash-tree-root of the object The `Bytes32` is encoded as a string, hexadecimal encoding, prefixed with `0x`. -### `serialized.ssz` +### `serialized.ssz_snappy` -The serialized form of the object, as raw SSZ bytes. +The serialized form of the object, as snappy-compressed SSZ bytes. ### `value.yaml` @@ -64,7 +64,7 @@ The conditions are the same for each type: ## `invalid` -Test cases in the `invalid` suite only include the `serialized.ssz` +Test cases in the `invalid` suite only include the `serialized.ssz_snappy` #### Condition diff --git a/tests/formats/ssz_static/core.md b/tests/formats/ssz_static/core.md index d6f99a32b..09ff04e20 100644 --- a/tests/formats/ssz_static/core.md +++ b/tests/formats/ssz_static/core.md @@ -18,7 +18,7 @@ One can iterate over the handlers, and select the type based on the handler name Suites are then the same format, but each specialized in one randomization mode. Some randomization modes may only produce a single test case (e.g. the all-zeroes case). -The output parts are: `roots.yaml`, `serialized.ssz`, `value.yaml` +The output parts are: `roots.yaml`, `serialized.ssz_snappy`, `value.yaml` ### `roots.yaml` @@ -26,13 +26,13 @@ The output parts are: `roots.yaml`, `serialized.ssz`, `value.yaml` root: bytes32 -- string, hash-tree-root of the value, hex encoded, with prefix 0x ``` -### `serialized.ssz` +### `serialized.ssz_snappy` -The raw encoded bytes. +The SSZ-snappy encoded bytes. ### `value.yaml` -The same value as `serialized.ssz`, represented as YAML. +The same value as `serialized.ssz_snappy`, represented as YAML. ## Condition From 3fb9b155518c68222fcef8af36b2bc7c81c230eb Mon Sep 17 00:00:00 2001 From: protolambda Date: Thu, 8 Oct 2020 21:17:13 +0200 Subject: [PATCH 03/56] remove unused imports --- tests/core/pyspec/eth2spec/test/utils.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/core/pyspec/eth2spec/test/utils.py b/tests/core/pyspec/eth2spec/test/utils.py index 306f7d892..bad6c867b 100644 --- a/tests/core/pyspec/eth2spec/test/utils.py +++ b/tests/core/pyspec/eth2spec/test/utils.py @@ -1,5 +1,4 @@ from typing import Dict, Any -from eth2spec.debug.encode import encode from eth2spec.utils.ssz.ssz_typing import View from eth2spec.utils.ssz.ssz_impl import serialize From 2b8b0d9e2bcd301c012d09a6ce0d4680cd17ab6f Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Thu, 11 Feb 2021 14:53:29 -0700 Subject: [PATCH 04/56] update penalty config values for hf1 --- configs/mainnet/lightclient_patch.yaml | 10 +++ configs/minimal/lightclient_patch.yaml | 10 +++ specs/lightclient/beacon-chain.md | 77 ++++++++++++++++++- .../test_process_slashings.py | 48 ++++++++++-- 4 files changed, 134 insertions(+), 11 deletions(-) diff --git a/configs/mainnet/lightclient_patch.yaml b/configs/mainnet/lightclient_patch.yaml index 64c05a720..6c5b16edf 100644 --- a/configs/mainnet/lightclient_patch.yaml +++ b/configs/mainnet/lightclient_patch.yaml @@ -2,6 +2,16 @@ CONFIG_NAME: "mainnet" +# Updated penalty values +# --------------------------------------------------------------- +# 3 * 2**24) (= 50,331,648) +HF1_INACTIVITY_PENALTY_QUOTIENT: 50331648 +# 2**6 (= 64) +HF1_MIN_SLASHING_PENALTY_QUOTIENT: 64 +# 2 +HF1_PROPORTIONAL_SLASHING_MULTIPLIER: 2 + + # Misc # --------------------------------------------------------------- # 2**10 (=1,024) diff --git a/configs/minimal/lightclient_patch.yaml b/configs/minimal/lightclient_patch.yaml index afe7d897e..7ab5f34ba 100644 --- a/configs/minimal/lightclient_patch.yaml +++ b/configs/minimal/lightclient_patch.yaml @@ -2,6 +2,16 @@ CONFIG_NAME: "minimal" +# Updated penalty values +# --------------------------------------------------------------- +# 3 * 2**24) (= 50,331,648) +HF1_INACTIVITY_PENALTY_QUOTIENT: 50331648 +# 2**6 (= 64) +HF1_MIN_SLASHING_PENALTY_QUOTIENT: 64 +# 2 +HF1_PROPORTIONAL_SLASHING_MULTIPLIER: 2 + + # Misc # --------------------------------------------------------------- # [customized] diff --git a/specs/lightclient/beacon-chain.md b/specs/lightclient/beacon-chain.md index fff8726bf..ccf9b2ebc 100644 --- a/specs/lightclient/beacon-chain.md +++ b/specs/lightclient/beacon-chain.md @@ -13,6 +13,7 @@ - [Participation rewards](#participation-rewards) - [Misc](#misc) - [Configuration](#configuration) + - [Updated penalty values](#updated-penalty-values) - [Misc](#misc-1) - [Time parameters](#time-parameters) - [Domain types](#domain-types) @@ -34,6 +35,8 @@ - [`get_unslashed_participating_indices`](#get_unslashed_participating_indices) - [`get_flag_deltas`](#get_flag_deltas) - [New `get_inactivity_penalty_deltas`](#new-get_inactivity_penalty_deltas) + - [Beacon state mutators](#beacon-state-mutators) + - [New `slash_validator`](#new-slash_validator) - [Block processing](#block-processing) - [New `process_attestation`](#new-process_attestation) - [New `process_deposit`](#new-process_deposit) @@ -41,6 +44,7 @@ - [Epoch processing](#epoch-processing) - [New `process_justification_and_finalization`](#new-process_justification_and_finalization) - [New `process_rewards_and_penalties`](#new-process_rewards_and_penalties) + - [New `process_slashings`](#new-process_slashings) - [Sync committee updates](#sync-committee-updates) - [Participation flags updates](#participation-flags-updates) @@ -49,7 +53,8 @@ ## Introduction -This is a patch implementing the first hard fork to the beacon chain, tentatively named HF1 pending a permanent name. It has three main features: +This is a patch implementing the first hard fork to the beacon chain, tentatively named HF1 pending a permanent name. +It has three main features: * Light client support via sync committees * Incentive accounting reforms, reducing spec complexity @@ -97,6 +102,18 @@ The reward fractions add up to 7/8, leaving the remaining 1/8 for proposer rewar ## Configuration +### Updated penalty values + +This patch updates a few configuration values to move penalty constants toward their final, maxmium security values. + +*Note*: The spec does *not* override previous configuration values but instead creates new values and replaces usage throughout. + +| Name | Value | +| - | - | +| `HF1_INACTIVITY_PENALTY_QUOTIENT` | `uint64(3 * 2**24)` (= 50,331,648) | +| `HF1_MIN_SLASHING_PENALTY_QUOTIENT` | `uint64(2**6)` (=64) | +| `HF1_PROPORTIONAL_SLASHING_MULTIPLIER` | `uint64(2)` | + ### Misc | Name | Value | @@ -328,7 +345,8 @@ def get_flag_deltas(state: BeaconState, #### New `get_inactivity_penalty_deltas` -*Note*: The function `get_inactivity_penalty_deltas` is modified in the selection of matching target indices and the removal of `BASE_REWARDS_PER_EPOCH`. +*Note*: The function `get_inactivity_penalty_deltas` is modified in the selection of matching target indices +and the removal of `BASE_REWARDS_PER_EPOCH`. ```python def get_inactivity_penalty_deltas(state: BeaconState) -> Tuple[Sequence[Gwei], Sequence[Gwei]]: @@ -348,12 +366,47 @@ def get_inactivity_penalty_deltas(state: BeaconState) -> Tuple[Sequence[Gwei], S penalties[index] += Gwei(get_base_reward(state, index) * reward_numerator_sum // REWARD_DENOMINATOR) if index not in matching_target_attesting_indices: effective_balance = state.validators[index].effective_balance - penalties[index] += Gwei(effective_balance * get_finality_delay(state) // INACTIVITY_PENALTY_QUOTIENT) + penalties[index] += Gwei( + effective_balance * get_finality_delay(state) + // HF1_INACTIVITY_PENALTY_QUOTIENT + ) rewards = [Gwei(0) for _ in range(len(state.validators))] return rewards, penalties ``` +### Beacon state mutators + +#### New `slash_validator` + +*Note*: The function `slash_validator` is modified +with the substitution of `MIN_SLASHING_PENALTY_QUOTIENT` with `HF1_MIN_SLASHING_PENALTY_QUOTIENT`. + +```python +def slash_validator(state: BeaconState, + slashed_index: ValidatorIndex, + whistleblower_index: ValidatorIndex=None) -> None: + """ + Slash the validator with index ``slashed_index``. + """ + epoch = get_current_epoch(state) + initiate_validator_exit(state, slashed_index) + validator = state.validators[slashed_index] + validator.slashed = True + validator.withdrawable_epoch = max(validator.withdrawable_epoch, Epoch(epoch + EPOCHS_PER_SLASHINGS_VECTOR)) + state.slashings[epoch % EPOCHS_PER_SLASHINGS_VECTOR] += validator.effective_balance + decrease_balance(state, slashed_index, validator.effective_balance // HF1_MIN_SLASHING_PENALTY_QUOTIENT) + + # Apply proposer and whistleblower rewards + proposer_index = get_beacon_proposer_index(state) + if whistleblower_index is None: + whistleblower_index = proposer_index + whistleblower_reward = Gwei(validator.effective_balance // WHISTLEBLOWER_REWARD_QUOTIENT) + proposer_reward = Gwei(whistleblower_reward // PROPOSER_REWARD_QUOTIENT) + increase_balance(state, proposer_index, proposer_reward) + increase_balance(state, whistleblower_index, Gwei(whistleblower_reward - proposer_reward)) +``` + ### Block processing ```python @@ -576,6 +629,24 @@ def process_rewards_and_penalties(state: BeaconState) -> None: decrease_balance(state, ValidatorIndex(index), penalties[index]) ``` +#### New `process_slashings` + +*Note*: The function `process_slashings` is modified +with the substitution of `PROPORTIONAL_SLASHING_MULTIPLIER` with `HF1_PROPORTIONAL_SLASHING_MULTIPLIER`. + +```python +def process_slashings(state: BeaconState) -> None: + epoch = get_current_epoch(state) + total_balance = get_total_active_balance(state) + adjusted_total_slashing_balance = min(sum(state.slashings) * HF1_PROPORTIONAL_SLASHING_MULTIPLIER, total_balance) + for index, validator in enumerate(state.validators): + if validator.slashed and epoch + EPOCHS_PER_SLASHINGS_VECTOR // 2 == validator.withdrawable_epoch: + increment = EFFECTIVE_BALANCE_INCREMENT # Factored out from penalty numerator to avoid uint64 overflow + penalty_numerator = validator.effective_balance // increment * adjusted_total_slashing_balance + penalty = penalty_numerator // total_balance * increment + decrease_balance(state, ValidatorIndex(index), penalty) +``` + #### Sync committee updates ```python diff --git a/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_slashings.py b/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_slashings.py index 2e09f5c8a..8bb4ac218 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_slashings.py +++ b/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_slashings.py @@ -1,4 +1,4 @@ -from eth2spec.test.context import spec_state_test, with_all_phases +from eth2spec.test.context import spec_state_test, with_all_phases, is_post_lightclient_patch from eth2spec.test.helpers.epoch_processing import ( run_epoch_processing_with, run_epoch_processing_to ) @@ -23,12 +23,19 @@ def slash_validators(spec, state, indices, out_epochs): ] = total_slashed_balance +def get_slashing_multipler(spec): + if is_post_lightclient_patch(spec): + return spec.HF1_PROPORTIONAL_SLASHING_MULTIPLIER + else: + return spec.PROPORTIONAL_SLASHING_MULTIPLIER + + @with_all_phases @spec_state_test def test_max_penalties(spec, state): # Slashed count to ensure that enough validators are slashed to induce maximum penalties slashed_count = min( - (len(state.validators) // spec.PROPORTIONAL_SLASHING_MULTIPLIER) + 1, + (len(state.validators) // get_slashing_multipler(spec)) + 1, # Can't slash more than validator count! len(state.validators) ) @@ -40,7 +47,7 @@ def test_max_penalties(spec, state): total_balance = spec.get_total_active_balance(state) total_penalties = sum(state.slashings) - assert total_balance // spec.PROPORTIONAL_SLASHING_MULTIPLIER <= total_penalties + assert total_balance // get_slashing_multipler(spec) <= total_penalties yield from run_process_slashings(spec, state) @@ -50,7 +57,30 @@ def test_max_penalties(spec, state): @with_all_phases @spec_state_test -def test_small_penalty(spec, state): +def test_low_penalty(spec, state): + # Slashed count is one tenth of validator set + slashed_count = (len(state.validators) // 10) + 1 + out_epoch = spec.get_current_epoch(state) + (spec.EPOCHS_PER_SLASHINGS_VECTOR // 2) + + slashed_indices = list(range(slashed_count)) + slash_validators(spec, state, slashed_indices, [out_epoch] * slashed_count) + + pre_state = state.copy() + + yield from run_process_slashings(spec, state) + + for i in slashed_indices: + assert 0 < state.balances[i] < pre_state.balances[i] + + +@with_all_phases +@spec_state_test +def test_minimal_penalty(spec, state): + # + # When very few slashings, the resulting slashing penalty gets rounded down + # to zero so the result of `process_slashings` is null + # + # Just the bare minimum for this one validator state.balances[0] = state.validators[0].effective_balance = spec.EJECTION_BALANCE # All the other validators get the maximum. @@ -74,11 +104,13 @@ def test_small_penalty(spec, state): expected_penalty = ( state.validators[0].effective_balance // spec.EFFECTIVE_BALANCE_INCREMENT - * (3 * total_penalties) + * (get_slashing_multipler(spec) * total_penalties) // total_balance * spec.EFFECTIVE_BALANCE_INCREMENT ) - assert state.balances[0] == pre_slash_balances[0] - expected_penalty + + assert expected_penalty == 0 + assert state.balances[0] == pre_slash_balances[0] @with_all_phases @@ -96,7 +128,7 @@ def test_scaled_penalties(spec, state): state.slashings[5] = base + (incr * 6) state.slashings[spec.EPOCHS_PER_SLASHINGS_VECTOR - 1] = base + (incr * 7) - slashed_count = len(state.validators) // (spec.PROPORTIONAL_SLASHING_MULTIPLIER + 1) + slashed_count = len(state.validators) // (get_slashing_multipler(spec) + 1) assert slashed_count > 10 @@ -134,7 +166,7 @@ def test_scaled_penalties(spec, state): v = state.validators[i] expected_penalty = ( v.effective_balance // spec.EFFECTIVE_BALANCE_INCREMENT - * (spec.PROPORTIONAL_SLASHING_MULTIPLIER * total_penalties) + * (get_slashing_multipler(spec) * total_penalties) // (total_balance) * spec.EFFECTIVE_BALANCE_INCREMENT ) From 24a244eb9b340fe707888180e02bcb3918cd7998 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Sat, 13 Feb 2021 22:48:34 +0800 Subject: [PATCH 05/56] Fix typo: `get_slashing_multipler` -> `get_slashing_multiplier` --- .../epoch_processing/test_process_slashings.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_slashings.py b/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_slashings.py index 8bb4ac218..34f1e89c6 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_slashings.py +++ b/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_slashings.py @@ -23,7 +23,7 @@ def slash_validators(spec, state, indices, out_epochs): ] = total_slashed_balance -def get_slashing_multipler(spec): +def get_slashing_multiplier(spec): if is_post_lightclient_patch(spec): return spec.HF1_PROPORTIONAL_SLASHING_MULTIPLIER else: @@ -35,7 +35,7 @@ def get_slashing_multipler(spec): def test_max_penalties(spec, state): # Slashed count to ensure that enough validators are slashed to induce maximum penalties slashed_count = min( - (len(state.validators) // get_slashing_multipler(spec)) + 1, + (len(state.validators) // get_slashing_multiplier(spec)) + 1, # Can't slash more than validator count! len(state.validators) ) @@ -47,7 +47,7 @@ def test_max_penalties(spec, state): total_balance = spec.get_total_active_balance(state) total_penalties = sum(state.slashings) - assert total_balance // get_slashing_multipler(spec) <= total_penalties + assert total_balance // get_slashing_multiplier(spec) <= total_penalties yield from run_process_slashings(spec, state) @@ -104,7 +104,7 @@ def test_minimal_penalty(spec, state): expected_penalty = ( state.validators[0].effective_balance // spec.EFFECTIVE_BALANCE_INCREMENT - * (get_slashing_multipler(spec) * total_penalties) + * (get_slashing_multiplier(spec) * total_penalties) // total_balance * spec.EFFECTIVE_BALANCE_INCREMENT ) @@ -128,7 +128,7 @@ def test_scaled_penalties(spec, state): state.slashings[5] = base + (incr * 6) state.slashings[spec.EPOCHS_PER_SLASHINGS_VECTOR - 1] = base + (incr * 7) - slashed_count = len(state.validators) // (get_slashing_multipler(spec) + 1) + slashed_count = len(state.validators) // (get_slashing_multiplier(spec) + 1) assert slashed_count > 10 @@ -166,7 +166,7 @@ def test_scaled_penalties(spec, state): v = state.validators[i] expected_penalty = ( v.effective_balance // spec.EFFECTIVE_BALANCE_INCREMENT - * (get_slashing_multipler(spec) * total_penalties) + * (get_slashing_multiplier(spec) * total_penalties) // (total_balance) * spec.EFFECTIVE_BALANCE_INCREMENT ) From dda7010c0c02f2bd740509e315b5985db7590f84 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Sat, 13 Feb 2021 23:02:06 +0800 Subject: [PATCH 06/56] Fix the tests that use `MIN_SLASHING_PENALTY_QUOTIENT`. (The mainnet tests failed before this fix) --- .../pyspec/eth2spec/test/helpers/proposer_slashings.py | 10 +++++++++- .../block_processing/test_process_attester_slashing.py | 3 ++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/helpers/proposer_slashings.py b/tests/core/pyspec/eth2spec/test/helpers/proposer_slashings.py index 87b4f5ca0..89acb3417 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/proposer_slashings.py +++ b/tests/core/pyspec/eth2spec/test/helpers/proposer_slashings.py @@ -1,8 +1,16 @@ +from eth2spec.test.context import is_post_lightclient_patch from eth2spec.test.helpers.block_header import sign_block_header from eth2spec.test.helpers.keys import pubkey_to_privkey from eth2spec.test.helpers.state import get_balance +def get_min_slashing_penalty_quotient(spec): + if is_post_lightclient_patch(spec): + return spec.HF1_MIN_SLASHING_PENALTY_QUOTIENT + else: + return spec.MIN_SLASHING_PENALTY_QUOTIENT + + def check_proposer_slashing_effect(spec, pre_state, state, slashed_index): slashed_validator = state.validators[slashed_index] assert slashed_validator.slashed @@ -10,7 +18,7 @@ def check_proposer_slashing_effect(spec, pre_state, state, slashed_index): assert slashed_validator.withdrawable_epoch < spec.FAR_FUTURE_EPOCH proposer_index = spec.get_beacon_proposer_index(state) - slash_penalty = state.validators[slashed_index].effective_balance // spec.MIN_SLASHING_PENALTY_QUOTIENT + slash_penalty = state.validators[slashed_index].effective_balance // get_min_slashing_penalty_quotient(spec) whistleblower_reward = state.validators[slashed_index].effective_balance // spec.WHISTLEBLOWER_REWARD_QUOTIENT if proposer_index != slashed_index: # slashed validator lost initial slash penalty diff --git a/tests/core/pyspec/eth2spec/test/phase0/block_processing/test_process_attester_slashing.py b/tests/core/pyspec/eth2spec/test/phase0/block_processing/test_process_attester_slashing.py index 82d490311..21d9363f7 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/block_processing/test_process_attester_slashing.py +++ b/tests/core/pyspec/eth2spec/test/phase0/block_processing/test_process_attester_slashing.py @@ -4,6 +4,7 @@ from eth2spec.test.context import ( from eth2spec.test.helpers.attestations import sign_indexed_attestation from eth2spec.test.helpers.attester_slashings import get_valid_attester_slashing, \ get_indexed_attestation_participants, get_attestation_2_data, get_attestation_1_data +from eth2spec.test.helpers.proposer_slashings import get_min_slashing_penalty_quotient from eth2spec.test.helpers.state import ( get_balance, next_epoch_via_block, @@ -70,7 +71,7 @@ def run_attester_slashing_processing(spec, state, attester_slashing, valid=True) expected_balance = ( pre_proposer_balance + total_proposer_rewards - - pre_slashings[proposer_index] // spec.MIN_SLASHING_PENALTY_QUOTIENT + - pre_slashings[proposer_index] // get_min_slashing_penalty_quotient(spec) ) assert get_balance(state, proposer_index) == expected_balance From 600a4daddf1456778b71a86f9dad7e25d25aaf52 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Mon, 15 Feb 2021 18:38:20 +0800 Subject: [PATCH 07/56] Turn off phase1 testgen and turn on lightclient_patch testgen --- tests/core/gen_helpers/gen_from_tests/gen.py | 12 +++++- tests/core/pyspec/eth2spec/test/context.py | 4 ++ .../test/lightclient_patch/sanity/__init__.py | 0 tests/generators/epoch_processing/main.py | 37 +++++++++++------- tests/generators/finality/main.py | 39 ++++++++++++------- tests/generators/operations/main.py | 37 +++++++++++------- tests/generators/rewards/main.py | 34 +++++++++------- tests/generators/sanity/main.py | 34 +++++++++------- 8 files changed, 126 insertions(+), 71 deletions(-) create mode 100644 tests/core/pyspec/eth2spec/test/lightclient_patch/sanity/__init__.py diff --git a/tests/core/gen_helpers/gen_from_tests/gen.py b/tests/core/gen_helpers/gen_from_tests/gen.py index 902b0954a..c09b477bb 100644 --- a/tests/core/gen_helpers/gen_from_tests/gen.py +++ b/tests/core/gen_helpers/gen_from_tests/gen.py @@ -1,5 +1,5 @@ from inspect import getmembers, isfunction -from typing import Any, Iterable +from typing import Any, Iterable, Dict from gen_base.gen_typing import TestCase @@ -38,3 +38,13 @@ def generate_from_tests(runner_name: str, handler_name: str, src: Any, # TODO: with_all_phases and other per-phase tooling, should be replaced with per-fork equivalent. case_fn=lambda: tfn(generator_mode=True, phase=fork_name, bls_active=bls_active) ) + + +def get_provider(create_provider_fn, config_name, fork_name, all_mods): + for key, mod_name in all_mods[fork_name].items(): + yield create_provider_fn( + fork_name=fork_name, + handler_name=key, + tests_src_mod_name=mod_name, + config_name=config_name, + ) diff --git a/tests/core/pyspec/eth2spec/test/context.py b/tests/core/pyspec/eth2spec/test/context.py index d19547477..75832794f 100644 --- a/tests/core/pyspec/eth2spec/test/context.py +++ b/tests/core/pyspec/eth2spec/test/context.py @@ -37,6 +37,10 @@ ALL_PHASES = (PHASE0, PHASE1, LIGHTCLIENT_PATCH) MAINNET = ConfigName('mainnet') MINIMAL = ConfigName('minimal') +ALL_CONFIGS = (MINIMAL, MAINNET) + +# The forks that output to the test vectors. +TESTGEN_FORKS = (PHASE0, LIGHTCLIENT_PATCH) # TODO: currently phases are defined as python modules. # It would be better if they would be more well-defined interfaces for stronger typing. diff --git a/tests/core/pyspec/eth2spec/test/lightclient_patch/sanity/__init__.py b/tests/core/pyspec/eth2spec/test/lightclient_patch/sanity/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/generators/epoch_processing/main.py b/tests/generators/epoch_processing/main.py index ea7639605..835fe0087 100644 --- a/tests/generators/epoch_processing/main.py +++ b/tests/generators/epoch_processing/main.py @@ -1,12 +1,13 @@ from typing import Iterable from gen_base import gen_runner, gen_typing -from gen_from_tests.gen import generate_from_tests +from gen_from_tests.gen import generate_from_tests, get_provider from importlib import reload, import_module from eth2spec.config import config_util from eth2spec.phase0 import spec as spec_phase0 +from eth2spec.lightclient_patch import spec as spec_lightclient_patch from eth2spec.phase1 import spec as spec_phase1 -from eth2spec.test.context import PHASE0, PHASE1 +from eth2spec.test.context import PHASE0, PHASE1, LIGHTCLIENT_PATCH, TESTGEN_FORKS, ALL_CONFIGS from eth2spec.utils import bls @@ -15,6 +16,7 @@ def create_provider(fork_name: str, handler_name: str, def prepare_fn(configs_path: str) -> str: config_util.prepare_config(configs_path, config_name) reload(spec_phase0) + reload(spec_lightclient_patch) reload(spec_phase1) bls.use_milagro() return config_name @@ -44,21 +46,28 @@ if __name__ == "__main__": 'historical_roots_update', 'participation_record_updates', ]} + lightclient_patch_mods = { + **{key: 'eth2spec.test.lightclient_patch.epoch_processing.test_process_' + key for key in [ + 'sync_committee_updates', + ]}, + **phase_0_mods, + } # also run the previous phase 0 tests phase_1_mods = {**{key: 'eth2spec.test.phase1.epoch_processing.test_process_' + key for key in [ 'reveal_deadlines', 'challenge_deadlines', 'custody_final_updates', ]}, **phase_0_mods} # also run the previous phase 0 tests (but against phase 1 spec) - gen_runner.run_generator(f"epoch_processing", [ - create_provider(PHASE0, key, mod_name, 'minimal') for key, mod_name in phase_0_mods.items() - ]) - gen_runner.run_generator(f"epoch_processing", [ - create_provider(PHASE0, key, mod_name, 'mainnet') for key, mod_name in phase_0_mods.items() - ]) - gen_runner.run_generator(f"epoch_processing", [ - create_provider(PHASE1, key, mod_name, 'minimal') for key, mod_name in phase_1_mods.items() - ]) - gen_runner.run_generator(f"epoch_processing", [ - create_provider(PHASE1, key, mod_name, 'mainnet') for key, mod_name in phase_1_mods.items() - ]) + all_mods = { + PHASE0: phase_0_mods, + LIGHTCLIENT_PATCH: lightclient_patch_mods, + PHASE1: phase_1_mods, + } + + for config_name in ALL_CONFIGS: + for fork_name in TESTGEN_FORKS: + if fork_name in all_mods: + gen_runner.run_generator(f"epoch_processing", get_provider( + create_provider_fn=create_provider, config_name=config_name, + fork_name=fork_name, all_mods=all_mods, + )) diff --git a/tests/generators/finality/main.py b/tests/generators/finality/main.py index ef2d8293f..6ea3d82c8 100644 --- a/tests/generators/finality/main.py +++ b/tests/generators/finality/main.py @@ -1,27 +1,30 @@ from typing import Iterable -from importlib import reload +from importlib import reload, import_module from gen_base import gen_runner, gen_typing -from gen_from_tests.gen import generate_from_tests +from gen_from_tests.gen import generate_from_tests, get_provider -from eth2spec.test.context import PHASE0, PHASE1 -from eth2spec.test.phase0.finality import test_finality +from eth2spec.test.context import PHASE0, PHASE1, LIGHTCLIENT_PATCH, TESTGEN_FORKS, ALL_CONFIGS from eth2spec.config import config_util from eth2spec.phase0 import spec as spec_phase0 +from eth2spec.lightclient_patch import spec as spec_lightclient_patch from eth2spec.phase1 import spec as spec_phase1 from eth2spec.utils import bls -def create_provider(fork_name: str, handler_name: str, tests_src, config_name: str) -> gen_typing.TestProvider: +def create_provider(fork_name: str, handler_name: str, + tests_src_mod_name: str, config_name: str) -> gen_typing.TestProvider: def prepare_fn(configs_path: str) -> str: config_util.prepare_config(configs_path, config_name) reload(spec_phase0) + reload(spec_lightclient_patch) reload(spec_phase1) bls.use_milagro() return config_name def cases_fn() -> Iterable[gen_typing.TestCase]: + tests_src = import_module(tests_src_mod_name) return generate_from_tests( runner_name='finality', handler_name=handler_name, @@ -33,11 +36,21 @@ def create_provider(fork_name: str, handler_name: str, tests_src, config_name: s if __name__ == "__main__": - # No additional phase 1 specific rewards tests, yet. - key = 'finality' - gen_runner.run_generator("finality", [ - create_provider(PHASE0, 'finality', test_finality, 'minimal'), - create_provider(PHASE0, 'finality', test_finality, 'mainnet'), - create_provider(PHASE1, 'finality', test_finality, 'minimal'), - create_provider(PHASE1, 'finality', test_finality, 'mainnet'), - ]) + phase_0_mods = {'finality': 'eth2spec.test.phase0.finality.test_finality'} + # No additional lightclient_patch or phase 1 specific finality tests, yet. + lightclient_patch_mods = phase_0_mods + phase_1_mods = phase_0_mods + + all_mods = { + PHASE0: phase_0_mods, + LIGHTCLIENT_PATCH: lightclient_patch_mods, + PHASE1: phase_1_mods, + } + + for config_name in ALL_CONFIGS: + for fork_name in TESTGEN_FORKS: + if fork_name in all_mods: + gen_runner.run_generator(f"finality", get_provider( + create_provider_fn=create_provider, config_name=config_name, + fork_name=fork_name, all_mods=all_mods, + )) diff --git a/tests/generators/operations/main.py b/tests/generators/operations/main.py index 1acf45e47..20643f8d7 100644 --- a/tests/generators/operations/main.py +++ b/tests/generators/operations/main.py @@ -1,12 +1,13 @@ from typing import Iterable from gen_base import gen_runner, gen_typing -from gen_from_tests.gen import generate_from_tests +from gen_from_tests.gen import generate_from_tests, get_provider from importlib import reload, import_module from eth2spec.config import config_util from eth2spec.phase0 import spec as spec_phase0 +from eth2spec.lightclient_patch import spec as spec_lightclient_patch from eth2spec.phase1 import spec as spec_phase1 -from eth2spec.test.context import PHASE0, PHASE1 +from eth2spec.test.context import PHASE0, PHASE1, LIGHTCLIENT_PATCH, TESTGEN_FORKS, ALL_CONFIGS from eth2spec.utils import bls @@ -15,6 +16,7 @@ def create_provider(fork_name: str, handler_name: str, def prepare_fn(configs_path: str) -> str: config_util.prepare_config(configs_path, config_name) reload(spec_phase0) + reload(spec_lightclient_patch) reload(spec_phase1) bls.use_milagro() return config_name @@ -40,6 +42,12 @@ if __name__ == "__main__": 'proposer_slashing', 'voluntary_exit', ]} + lightclient_patch_mods = { + **{key: 'eth2spec.test.lightclient_patch.block_processing.test_process_' + key for key in [ + 'sync_committee', + ]}, + **phase_0_mods, + } # also run the previous phase 0 tests phase_1_mods = {**{key: 'eth2spec.test.phase1.block_processing.test_process_' + key for key in [ 'attestation', 'chunk_challenge', @@ -49,15 +57,16 @@ if __name__ == "__main__": 'shard_transition', ]}, **phase_0_mods} # also run the previous phase 0 tests (but against phase 1 spec) - gen_runner.run_generator(f"operations", [ - create_provider(PHASE0, key, mod_name, 'minimal') for key, mod_name in phase_0_mods.items() - ]) - gen_runner.run_generator(f"operations", [ - create_provider(PHASE0, key, mod_name, 'mainnet') for key, mod_name in phase_0_mods.items() - ]) - gen_runner.run_generator(f"operations", [ - create_provider(PHASE1, key, mod_name, 'minimal') for key, mod_name in phase_1_mods.items() - ]) - gen_runner.run_generator(f"operations", [ - create_provider(PHASE1, key, mod_name, 'mainnet') for key, mod_name in phase_1_mods.items() - ]) + all_mods = { + PHASE0: phase_0_mods, + LIGHTCLIENT_PATCH: lightclient_patch_mods, + PHASE1: phase_1_mods, + } + + for config_name in ALL_CONFIGS: + for fork_name in TESTGEN_FORKS: + if fork_name in all_mods: + gen_runner.run_generator(f"operations", get_provider( + create_provider_fn=create_provider, config_name=config_name, + fork_name=fork_name, all_mods=all_mods, + )) diff --git a/tests/generators/rewards/main.py b/tests/generators/rewards/main.py index 23d0633b0..cd3206a3f 100644 --- a/tests/generators/rewards/main.py +++ b/tests/generators/rewards/main.py @@ -1,12 +1,13 @@ from typing import Iterable from gen_base import gen_runner, gen_typing -from gen_from_tests.gen import generate_from_tests +from gen_from_tests.gen import generate_from_tests, get_provider from importlib import reload, import_module from eth2spec.config import config_util from eth2spec.phase0 import spec as spec_phase0 +from eth2spec.lightclient_patch import spec as spec_lightclient_patch from eth2spec.phase1 import spec as spec_phase1 -from eth2spec.test.context import PHASE0, PHASE1 +from eth2spec.test.context import PHASE0, PHASE1, LIGHTCLIENT_PATCH, TESTGEN_FORKS, ALL_CONFIGS from eth2spec.utils import bls @@ -15,6 +16,7 @@ def create_provider(fork_name: str, handler_name: str, def prepare_fn(configs_path: str) -> str: config_util.prepare_config(configs_path, config_name) reload(spec_phase0) + reload(spec_lightclient_patch) reload(spec_phase1) bls.use_milagro() return config_name @@ -37,18 +39,20 @@ if __name__ == "__main__": 'leak', 'random', ]} - # No additional phase 1 specific rewards tests, yet. + # No additional lightclient_patch or phase 1 specific rewards tests, yet. + lightclient_patch_mods = phase_0_mods phase_1_mods = phase_0_mods - gen_runner.run_generator(f"rewards", [ - create_provider(PHASE0, key, mod_name, 'minimal') for key, mod_name in phase_0_mods.items() - ]) - gen_runner.run_generator(f"rewards", [ - create_provider(PHASE0, key, mod_name, 'mainnet') for key, mod_name in phase_0_mods.items() - ]) - gen_runner.run_generator(f"rewards", [ - create_provider(PHASE1, key, mod_name, 'minimal') for key, mod_name in phase_1_mods.items() - ]) - gen_runner.run_generator(f"rewards", [ - create_provider(PHASE1, key, mod_name, 'mainnet') for key, mod_name in phase_1_mods.items() - ]) + all_mods = { + PHASE0: phase_0_mods, + LIGHTCLIENT_PATCH: lightclient_patch_mods, + PHASE1: phase_1_mods, + } + + for config_name in ALL_CONFIGS: + for fork_name in TESTGEN_FORKS: + if fork_name in all_mods: + gen_runner.run_generator(f"rewards", get_provider( + create_provider_fn=create_provider, config_name=config_name, + fork_name=fork_name, all_mods=all_mods, + )) diff --git a/tests/generators/sanity/main.py b/tests/generators/sanity/main.py index 83166f0cf..0aabf5d4c 100644 --- a/tests/generators/sanity/main.py +++ b/tests/generators/sanity/main.py @@ -1,12 +1,13 @@ from typing import Iterable from gen_base import gen_runner, gen_typing -from gen_from_tests.gen import generate_from_tests +from gen_from_tests.gen import generate_from_tests, get_provider from importlib import reload, import_module from eth2spec.config import config_util from eth2spec.phase0 import spec as spec_phase0 +from eth2spec.lightclient_patch import spec as spec_lightclient_patch from eth2spec.phase1 import spec as spec_phase1 -from eth2spec.test.context import PHASE0, PHASE1 +from eth2spec.test.context import PHASE0, PHASE1, LIGHTCLIENT_PATCH, TESTGEN_FORKS, ALL_CONFIGS from eth2spec.utils import bls @@ -15,6 +16,7 @@ def create_provider(fork_name: str, handler_name: str, def prepare_fn(configs_path: str) -> str: config_util.prepare_config(configs_path, config_name) reload(spec_phase0) + reload(spec_lightclient_patch) reload(spec_phase1) bls.use_milagro() return config_name @@ -36,20 +38,24 @@ if __name__ == "__main__": 'blocks', 'slots', ]} + lightclient_patch_mods = {**{key: 'eth2spec.test.lightclient_patch.sanity.test_' + key for key in [ + 'blocks', + ]}, **phase_0_mods} # also run the previous phase 0 tests phase_1_mods = {**{key: 'eth2spec.test.phase1.sanity.test_' + key for key in [ 'blocks', # more phase 1 specific block tests 'shard_blocks', ]}, **phase_0_mods} # also run the previous phase 0 tests (but against phase 1 spec) - gen_runner.run_generator(f"sanity", [ - create_provider(PHASE0, key, mod_name, 'minimal') for key, mod_name in phase_0_mods.items() - ]) - gen_runner.run_generator(f"sanity", [ - create_provider(PHASE0, key, mod_name, 'mainnet') for key, mod_name in phase_0_mods.items() - ]) - gen_runner.run_generator(f"sanity", [ - create_provider(PHASE1, key, mod_name, 'minimal') for key, mod_name in phase_1_mods.items() - ]) - gen_runner.run_generator(f"sanity", [ - create_provider(PHASE1, key, mod_name, 'mainnet') for key, mod_name in phase_1_mods.items() - ]) + all_mods = { + PHASE0: phase_0_mods, + LIGHTCLIENT_PATCH: lightclient_patch_mods, + PHASE1: phase_1_mods, + } + + for config_name in ALL_CONFIGS: + for fork_name in TESTGEN_FORKS: + if fork_name in all_mods: + gen_runner.run_generator(f"sanity", get_provider( + create_provider_fn=create_provider, config_name=config_name, + fork_name=fork_name, all_mods=all_mods, + )) From c7d975981c04626b72cdc3566914af0aa552b7bb Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Mon, 15 Feb 2021 22:25:58 +0800 Subject: [PATCH 08/56] Refactor state tests generators --- tests/core/gen_helpers/gen_from_tests/gen.py | 53 ++++++++++++++++++-- tests/generators/epoch_processing/main.py | 39 ++------------ tests/generators/finality/main.py | 41 ++------------- tests/generators/operations/main.py | 39 ++------------ tests/generators/rewards/main.py | 39 ++------------ tests/generators/sanity/main.py | 39 ++------------ 6 files changed, 69 insertions(+), 181 deletions(-) diff --git a/tests/core/gen_helpers/gen_from_tests/gen.py b/tests/core/gen_helpers/gen_from_tests/gen.py index c09b477bb..3ec8904fc 100644 --- a/tests/core/gen_helpers/gen_from_tests/gen.py +++ b/tests/core/gen_helpers/gen_from_tests/gen.py @@ -1,11 +1,17 @@ +from importlib import reload, import_module from inspect import getmembers, isfunction -from typing import Any, Iterable, Dict +from typing import Any, Callable, Dict, Iterable -from gen_base.gen_typing import TestCase +from eth2spec.config import config_util +from eth2spec.utils import bls + +from eth2spec.test.context import ALL_CONFIGS, TESTGEN_FORKS, SpecForkName, ConfigName +from gen_base import gen_runner +from gen_base.gen_typing import TestCase, TestProvider def generate_from_tests(runner_name: str, handler_name: str, src: Any, - fork_name: str, bls_active: bool = True) -> Iterable[TestCase]: + fork_name: SpecForkName, bls_active: bool = True) -> Iterable[TestCase]: """ Generate a list of test cases by running tests from the given src in generator-mode. :param runner_name: to categorize the test in general as. @@ -40,7 +46,10 @@ def generate_from_tests(runner_name: str, handler_name: str, src: Any, ) -def get_provider(create_provider_fn, config_name, fork_name, all_mods): +def get_provider(create_provider_fn: Callable[[SpecForkName, str, str, ConfigName], TestProvider], + config_name: ConfigName, + fork_name: SpecForkName, + all_mods: Dict[str, Dict[str, str]]) -> Iterable[TestProvider]: for key, mod_name in all_mods[fork_name].items(): yield create_provider_fn( fork_name=fork_name, @@ -48,3 +57,39 @@ def get_provider(create_provider_fn, config_name, fork_name, all_mods): tests_src_mod_name=mod_name, config_name=config_name, ) + + +def get_create_provider_fn(runner_name: str, config_name: ConfigName, specs: Iterable[Any] + ) -> Callable[[SpecForkName, str, str, ConfigName], TestProvider]: + def prepare_fn(configs_path: str) -> str: + config_util.prepare_config(configs_path, config_name) + for spec in specs: + reload(spec) + bls.use_milagro() + return config_name + + def create_provider(fork_name: SpecForkName, handler_name: str, + tests_src_mod_name: str, config_name: ConfigName) -> TestProvider: + def cases_fn() -> Iterable[TestCase]: + tests_src = import_module(tests_src_mod_name) + return generate_from_tests( + runner_name=runner_name, + handler_name=handler_name, + src=tests_src, + fork_name=fork_name, + ) + + return TestProvider(prepare=prepare_fn, make_cases=cases_fn) + return create_provider + + +def run_state_test_generators(runner_name: str, specs: Iterable[Any], all_mods: Dict[str, Dict[str, str]]) -> None: + for config_name in ALL_CONFIGS: + for fork_name in TESTGEN_FORKS: + if fork_name in all_mods: + gen_runner.run_generator(runner_name, get_provider( + create_provider_fn=get_create_provider_fn(runner_name, config_name, specs), + config_name=config_name, + fork_name=fork_name, + all_mods=all_mods, + )) diff --git a/tests/generators/epoch_processing/main.py b/tests/generators/epoch_processing/main.py index 835fe0087..1306da523 100644 --- a/tests/generators/epoch_processing/main.py +++ b/tests/generators/epoch_processing/main.py @@ -1,36 +1,11 @@ -from typing import Iterable - -from gen_base import gen_runner, gen_typing -from gen_from_tests.gen import generate_from_tests, get_provider -from importlib import reload, import_module -from eth2spec.config import config_util +from gen_from_tests.gen import run_state_test_generators from eth2spec.phase0 import spec as spec_phase0 from eth2spec.lightclient_patch import spec as spec_lightclient_patch from eth2spec.phase1 import spec as spec_phase1 -from eth2spec.test.context import PHASE0, PHASE1, LIGHTCLIENT_PATCH, TESTGEN_FORKS, ALL_CONFIGS -from eth2spec.utils import bls +from eth2spec.test.context import PHASE0, PHASE1, LIGHTCLIENT_PATCH -def create_provider(fork_name: str, handler_name: str, - tests_src_mod_name: str, config_name: str) -> gen_typing.TestProvider: - def prepare_fn(configs_path: str) -> str: - config_util.prepare_config(configs_path, config_name) - reload(spec_phase0) - reload(spec_lightclient_patch) - reload(spec_phase1) - bls.use_milagro() - return config_name - - def cases_fn() -> Iterable[gen_typing.TestCase]: - tests_src = import_module(tests_src_mod_name) - return generate_from_tests( - runner_name='epoch_processing', - handler_name=handler_name, - src=tests_src, - fork_name=fork_name, - ) - - return gen_typing.TestProvider(prepare=prepare_fn, make_cases=cases_fn) +specs = (spec_phase0, spec_lightclient_patch, spec_phase1) if __name__ == "__main__": @@ -64,10 +39,4 @@ if __name__ == "__main__": PHASE1: phase_1_mods, } - for config_name in ALL_CONFIGS: - for fork_name in TESTGEN_FORKS: - if fork_name in all_mods: - gen_runner.run_generator(f"epoch_processing", get_provider( - create_provider_fn=create_provider, config_name=config_name, - fork_name=fork_name, all_mods=all_mods, - )) + run_state_test_generators(runner_name="epoch_processing", specs=specs, all_mods=all_mods) diff --git a/tests/generators/finality/main.py b/tests/generators/finality/main.py index 6ea3d82c8..0a62b1aa5 100644 --- a/tests/generators/finality/main.py +++ b/tests/generators/finality/main.py @@ -1,38 +1,11 @@ -from typing import Iterable -from importlib import reload, import_module - -from gen_base import gen_runner, gen_typing -from gen_from_tests.gen import generate_from_tests, get_provider - -from eth2spec.test.context import PHASE0, PHASE1, LIGHTCLIENT_PATCH, TESTGEN_FORKS, ALL_CONFIGS -from eth2spec.config import config_util +from gen_from_tests.gen import run_state_test_generators from eth2spec.phase0 import spec as spec_phase0 from eth2spec.lightclient_patch import spec as spec_lightclient_patch from eth2spec.phase1 import spec as spec_phase1 -from eth2spec.utils import bls +from eth2spec.test.context import PHASE0, PHASE1, LIGHTCLIENT_PATCH -def create_provider(fork_name: str, handler_name: str, - tests_src_mod_name: str, config_name: str) -> gen_typing.TestProvider: - - def prepare_fn(configs_path: str) -> str: - config_util.prepare_config(configs_path, config_name) - reload(spec_phase0) - reload(spec_lightclient_patch) - reload(spec_phase1) - bls.use_milagro() - return config_name - - def cases_fn() -> Iterable[gen_typing.TestCase]: - tests_src = import_module(tests_src_mod_name) - return generate_from_tests( - runner_name='finality', - handler_name=handler_name, - src=tests_src, - fork_name=fork_name, - ) - - return gen_typing.TestProvider(prepare=prepare_fn, make_cases=cases_fn) +specs = (spec_phase0, spec_lightclient_patch, spec_phase1) if __name__ == "__main__": @@ -47,10 +20,4 @@ if __name__ == "__main__": PHASE1: phase_1_mods, } - for config_name in ALL_CONFIGS: - for fork_name in TESTGEN_FORKS: - if fork_name in all_mods: - gen_runner.run_generator(f"finality", get_provider( - create_provider_fn=create_provider, config_name=config_name, - fork_name=fork_name, all_mods=all_mods, - )) + run_state_test_generators(runner_name="finality", specs=specs, all_mods=all_mods) diff --git a/tests/generators/operations/main.py b/tests/generators/operations/main.py index 20643f8d7..d40dbe9cd 100644 --- a/tests/generators/operations/main.py +++ b/tests/generators/operations/main.py @@ -1,36 +1,11 @@ -from typing import Iterable - -from gen_base import gen_runner, gen_typing -from gen_from_tests.gen import generate_from_tests, get_provider -from importlib import reload, import_module -from eth2spec.config import config_util +from gen_from_tests.gen import run_state_test_generators from eth2spec.phase0 import spec as spec_phase0 from eth2spec.lightclient_patch import spec as spec_lightclient_patch from eth2spec.phase1 import spec as spec_phase1 -from eth2spec.test.context import PHASE0, PHASE1, LIGHTCLIENT_PATCH, TESTGEN_FORKS, ALL_CONFIGS -from eth2spec.utils import bls +from eth2spec.test.context import PHASE0, PHASE1, LIGHTCLIENT_PATCH -def create_provider(fork_name: str, handler_name: str, - tests_src_mod_name: str, config_name: str) -> gen_typing.TestProvider: - def prepare_fn(configs_path: str) -> str: - config_util.prepare_config(configs_path, config_name) - reload(spec_phase0) - reload(spec_lightclient_patch) - reload(spec_phase1) - bls.use_milagro() - return config_name - - def cases_fn() -> Iterable[gen_typing.TestCase]: - tests_src = import_module(tests_src_mod_name) - return generate_from_tests( - runner_name='operations', - handler_name=handler_name, - src=tests_src, - fork_name=fork_name, - ) - - return gen_typing.TestProvider(prepare=prepare_fn, make_cases=cases_fn) +specs = (spec_phase0, spec_lightclient_patch, spec_phase1) if __name__ == "__main__": @@ -63,10 +38,4 @@ if __name__ == "__main__": PHASE1: phase_1_mods, } - for config_name in ALL_CONFIGS: - for fork_name in TESTGEN_FORKS: - if fork_name in all_mods: - gen_runner.run_generator(f"operations", get_provider( - create_provider_fn=create_provider, config_name=config_name, - fork_name=fork_name, all_mods=all_mods, - )) + run_state_test_generators(runner_name="operations", specs=specs, all_mods=all_mods) diff --git a/tests/generators/rewards/main.py b/tests/generators/rewards/main.py index cd3206a3f..addb6aef0 100644 --- a/tests/generators/rewards/main.py +++ b/tests/generators/rewards/main.py @@ -1,36 +1,11 @@ -from typing import Iterable - -from gen_base import gen_runner, gen_typing -from gen_from_tests.gen import generate_from_tests, get_provider -from importlib import reload, import_module -from eth2spec.config import config_util +from gen_from_tests.gen import run_state_test_generators from eth2spec.phase0 import spec as spec_phase0 from eth2spec.lightclient_patch import spec as spec_lightclient_patch from eth2spec.phase1 import spec as spec_phase1 -from eth2spec.test.context import PHASE0, PHASE1, LIGHTCLIENT_PATCH, TESTGEN_FORKS, ALL_CONFIGS -from eth2spec.utils import bls +from eth2spec.test.context import PHASE0, PHASE1, LIGHTCLIENT_PATCH -def create_provider(fork_name: str, handler_name: str, - tests_src_mod_name: str, config_name: str) -> gen_typing.TestProvider: - def prepare_fn(configs_path: str) -> str: - config_util.prepare_config(configs_path, config_name) - reload(spec_phase0) - reload(spec_lightclient_patch) - reload(spec_phase1) - bls.use_milagro() - return config_name - - def cases_fn() -> Iterable[gen_typing.TestCase]: - tests_src = import_module(tests_src_mod_name) - return generate_from_tests( - runner_name='rewards', - handler_name=handler_name, - src=tests_src, - fork_name=fork_name, - ) - - return gen_typing.TestProvider(prepare=prepare_fn, make_cases=cases_fn) +specs = (spec_phase0, spec_lightclient_patch, spec_phase1) if __name__ == "__main__": @@ -49,10 +24,4 @@ if __name__ == "__main__": PHASE1: phase_1_mods, } - for config_name in ALL_CONFIGS: - for fork_name in TESTGEN_FORKS: - if fork_name in all_mods: - gen_runner.run_generator(f"rewards", get_provider( - create_provider_fn=create_provider, config_name=config_name, - fork_name=fork_name, all_mods=all_mods, - )) + run_state_test_generators(runner_name="rewards", specs=specs, all_mods=all_mods) diff --git a/tests/generators/sanity/main.py b/tests/generators/sanity/main.py index 0aabf5d4c..fc5227a53 100644 --- a/tests/generators/sanity/main.py +++ b/tests/generators/sanity/main.py @@ -1,36 +1,11 @@ -from typing import Iterable - -from gen_base import gen_runner, gen_typing -from gen_from_tests.gen import generate_from_tests, get_provider -from importlib import reload, import_module -from eth2spec.config import config_util +from gen_from_tests.gen import run_state_test_generators from eth2spec.phase0 import spec as spec_phase0 from eth2spec.lightclient_patch import spec as spec_lightclient_patch from eth2spec.phase1 import spec as spec_phase1 -from eth2spec.test.context import PHASE0, PHASE1, LIGHTCLIENT_PATCH, TESTGEN_FORKS, ALL_CONFIGS -from eth2spec.utils import bls +from eth2spec.test.context import PHASE0, PHASE1, LIGHTCLIENT_PATCH -def create_provider(fork_name: str, handler_name: str, - tests_src_mod_name: str, config_name: str) -> gen_typing.TestProvider: - def prepare_fn(configs_path: str) -> str: - config_util.prepare_config(configs_path, config_name) - reload(spec_phase0) - reload(spec_lightclient_patch) - reload(spec_phase1) - bls.use_milagro() - return config_name - - def cases_fn() -> Iterable[gen_typing.TestCase]: - tests_src = import_module(tests_src_mod_name) - return generate_from_tests( - runner_name='sanity', - handler_name=handler_name, - src=tests_src, - fork_name=fork_name, - ) - - return gen_typing.TestProvider(prepare=prepare_fn, make_cases=cases_fn) +specs = (spec_phase0, spec_lightclient_patch, spec_phase1) if __name__ == "__main__": @@ -52,10 +27,4 @@ if __name__ == "__main__": PHASE1: phase_1_mods, } - for config_name in ALL_CONFIGS: - for fork_name in TESTGEN_FORKS: - if fork_name in all_mods: - gen_runner.run_generator(f"sanity", get_provider( - create_provider_fn=create_provider, config_name=config_name, - fork_name=fork_name, all_mods=all_mods, - )) + run_state_test_generators(runner_name="sanity", specs=specs, all_mods=all_mods) From c9ba641800dfba8a4838d5030260b1b6e5c7efd4 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Mon, 15 Feb 2021 11:22:11 -0700 Subject: [PATCH 09/56] note penalties in hf1 list --- specs/lightclient/beacon-chain.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/specs/lightclient/beacon-chain.md b/specs/lightclient/beacon-chain.md index ccf9b2ebc..bf9b6a092 100644 --- a/specs/lightclient/beacon-chain.md +++ b/specs/lightclient/beacon-chain.md @@ -54,11 +54,12 @@ ## Introduction This is a patch implementing the first hard fork to the beacon chain, tentatively named HF1 pending a permanent name. -It has three main features: +It has four main features: * Light client support via sync committees * Incentive accounting reforms, reducing spec complexity and [TODO] reducing the cost of processing chains that have very little or zero participation for a long span of epochs +* Update penalty configuration values, moving them toward their planned maximally punitive configuration * Fork choice rule changes to address weaknesses recently discovered in the existing fork choice ## Custom types From 9cc8567d682ee831adf4a019de31fd0ebbdd30bb Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Thu, 18 Feb 2021 15:17:47 +0800 Subject: [PATCH 10/56] Move `gen_helpers` into a module of `eth2spec` package --- .../{ => pyspec/eth2spec}/gen_helpers/README.md | 0 .../eth2spec/gen_helpers}/__init__.py | 0 .../eth2spec/gen_helpers/gen_base}/__init__.py | 0 .../eth2spec}/gen_helpers/gen_base/gen_runner.py | 13 +++++++------ .../eth2spec}/gen_helpers/gen_base/gen_typing.py | 0 .../eth2spec/gen_helpers/gen_from_tests/__init__.py | 0 .../eth2spec}/gen_helpers/gen_from_tests/gen.py | 13 +++++++------ .../eth2spec}/gen_helpers/requirements.txt | 0 .../core/{ => pyspec/eth2spec}/gen_helpers/setup.py | 0 tests/generators/README.md | 2 +- tests/generators/bls/main.py | 2 +- tests/generators/bls/requirements.txt | 4 +--- tests/generators/epoch_processing/main.py | 2 +- tests/generators/epoch_processing/requirements.txt | 4 ++-- tests/generators/finality/main.py | 2 +- tests/generators/finality/requirements.txt | 4 ++-- tests/generators/genesis/main.py | 4 ++-- tests/generators/genesis/requirements.txt | 4 ++-- tests/generators/operations/main.py | 2 +- tests/generators/operations/requirements.txt | 5 ++--- tests/generators/rewards/main.py | 2 +- tests/generators/rewards/requirements.txt | 4 ++-- tests/generators/sanity/main.py | 3 ++- tests/generators/sanity/requirements.txt | 4 ++-- tests/generators/shuffling/main.py | 2 +- tests/generators/ssz_generic/main.py | 2 +- tests/generators/ssz_generic/requirements.txt | 3 +-- tests/generators/ssz_static/main.py | 2 +- tests/generators/ssz_static/requirements.txt | 4 ++-- 29 files changed, 43 insertions(+), 44 deletions(-) rename tests/core/{ => pyspec/eth2spec}/gen_helpers/README.md (100%) rename tests/core/{gen_helpers/gen_base => pyspec/eth2spec/gen_helpers}/__init__.py (100%) rename tests/core/{gen_helpers/gen_from_tests => pyspec/eth2spec/gen_helpers/gen_base}/__init__.py (100%) rename tests/core/{ => pyspec/eth2spec}/gen_helpers/gen_base/gen_runner.py (95%) rename tests/core/{ => pyspec/eth2spec}/gen_helpers/gen_base/gen_typing.py (100%) create mode 100644 tests/core/pyspec/eth2spec/gen_helpers/gen_from_tests/__init__.py rename tests/core/{ => pyspec/eth2spec}/gen_helpers/gen_from_tests/gen.py (92%) rename tests/core/{ => pyspec/eth2spec}/gen_helpers/requirements.txt (100%) rename tests/core/{ => pyspec/eth2spec}/gen_helpers/setup.py (100%) diff --git a/tests/core/gen_helpers/README.md b/tests/core/pyspec/eth2spec/gen_helpers/README.md similarity index 100% rename from tests/core/gen_helpers/README.md rename to tests/core/pyspec/eth2spec/gen_helpers/README.md diff --git a/tests/core/gen_helpers/gen_base/__init__.py b/tests/core/pyspec/eth2spec/gen_helpers/__init__.py similarity index 100% rename from tests/core/gen_helpers/gen_base/__init__.py rename to tests/core/pyspec/eth2spec/gen_helpers/__init__.py diff --git a/tests/core/gen_helpers/gen_from_tests/__init__.py b/tests/core/pyspec/eth2spec/gen_helpers/gen_base/__init__.py similarity index 100% rename from tests/core/gen_helpers/gen_from_tests/__init__.py rename to tests/core/pyspec/eth2spec/gen_helpers/gen_base/__init__.py diff --git a/tests/core/gen_helpers/gen_base/gen_runner.py b/tests/core/pyspec/eth2spec/gen_helpers/gen_base/gen_runner.py similarity index 95% rename from tests/core/gen_helpers/gen_base/gen_runner.py rename to tests/core/pyspec/eth2spec/gen_helpers/gen_base/gen_runner.py index a22073c00..26427c6f8 100644 --- a/tests/core/gen_helpers/gen_base/gen_runner.py +++ b/tests/core/pyspec/eth2spec/gen_helpers/gen_base/gen_runner.py @@ -8,11 +8,11 @@ from ruamel.yaml import ( YAML, ) -from gen_base.gen_typing import TestProvider - from eth2spec.test import context from eth2spec.test.exceptions import SkippedTest +from .gen_typing import TestProvider + # Flag that the runner does NOT run test via pytest context.is_pytest = False @@ -119,10 +119,11 @@ def run_generator(generator_name, test_providers: Iterable[TestProvider]): print(f"generating tests with config '{config_name}' ...") for test_case in tprov.make_cases(): - case_dir = Path(output_dir) / Path(config_name) / Path(test_case.fork_name) \ - / Path(test_case.runner_name) / Path(test_case.handler_name) \ - / Path(test_case.suite_name) / Path(test_case.case_name) - + case_dir = ( + Path(output_dir) / Path(config_name) / Path(test_case.fork_name) + / Path(test_case.runner_name) / Path(test_case.handler_name) + / Path(test_case.suite_name) / Path(test_case.case_name) + ) if case_dir.exists(): if not args.force: print(f'Skipping already existing test: {case_dir}') diff --git a/tests/core/gen_helpers/gen_base/gen_typing.py b/tests/core/pyspec/eth2spec/gen_helpers/gen_base/gen_typing.py similarity index 100% rename from tests/core/gen_helpers/gen_base/gen_typing.py rename to tests/core/pyspec/eth2spec/gen_helpers/gen_base/gen_typing.py diff --git a/tests/core/pyspec/eth2spec/gen_helpers/gen_from_tests/__init__.py b/tests/core/pyspec/eth2spec/gen_helpers/gen_from_tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/core/gen_helpers/gen_from_tests/gen.py b/tests/core/pyspec/eth2spec/gen_helpers/gen_from_tests/gen.py similarity index 92% rename from tests/core/gen_helpers/gen_from_tests/gen.py rename to tests/core/pyspec/eth2spec/gen_helpers/gen_from_tests/gen.py index 3ec8904fc..f5a0f378b 100644 --- a/tests/core/gen_helpers/gen_from_tests/gen.py +++ b/tests/core/pyspec/eth2spec/gen_helpers/gen_from_tests/gen.py @@ -4,10 +4,10 @@ from typing import Any, Callable, Dict, Iterable from eth2spec.config import config_util from eth2spec.utils import bls - from eth2spec.test.context import ALL_CONFIGS, TESTGEN_FORKS, SpecForkName, ConfigName -from gen_base import gen_runner -from gen_base.gen_typing import TestCase, TestProvider + +from eth2spec.gen_helpers.gen_base import gen_runner +from eth2spec.gen_helpers.gen_base.gen_typing import TestCase, TestProvider def generate_from_tests(runner_name: str, handler_name: str, src: Any, @@ -56,11 +56,12 @@ def get_provider(create_provider_fn: Callable[[SpecForkName, str, str, ConfigNam handler_name=key, tests_src_mod_name=mod_name, config_name=config_name, - ) + ) -def get_create_provider_fn(runner_name: str, config_name: ConfigName, specs: Iterable[Any] - ) -> Callable[[SpecForkName, str, str, ConfigName], TestProvider]: +def get_create_provider_fn( + runner_name: str, config_name: ConfigName, specs: Iterable[Any] +) -> Callable[[SpecForkName, str, str, ConfigName], TestProvider]: def prepare_fn(configs_path: str) -> str: config_util.prepare_config(configs_path, config_name) for spec in specs: diff --git a/tests/core/gen_helpers/requirements.txt b/tests/core/pyspec/eth2spec/gen_helpers/requirements.txt similarity index 100% rename from tests/core/gen_helpers/requirements.txt rename to tests/core/pyspec/eth2spec/gen_helpers/requirements.txt diff --git a/tests/core/gen_helpers/setup.py b/tests/core/pyspec/eth2spec/gen_helpers/setup.py similarity index 100% rename from tests/core/gen_helpers/setup.py rename to tests/core/pyspec/eth2spec/gen_helpers/setup.py diff --git a/tests/generators/README.md b/tests/generators/README.md index 077a8443c..b819d93b8 100644 --- a/tests/generators/README.md +++ b/tests/generators/README.md @@ -103,7 +103,7 @@ Write a `main.py` file. The shuffling test generator is a good minimal starting ```python from eth2spec.phase0 import spec as spec from eth_utils import to_tuple -from gen_base import gen_runner, gen_typing +from eth2spec.gen_helpers.gen_base import gen_runner, gen_typing from preset_loader import loader from typing import Iterable diff --git a/tests/generators/bls/main.py b/tests/generators/bls/main.py index 6552b8654..fecc2df7d 100644 --- a/tests/generators/bls/main.py +++ b/tests/generators/bls/main.py @@ -13,7 +13,7 @@ import milagro_bls_binding as milagro_bls from eth2spec.utils import bls from eth2spec.test.context import PHASE0 -from gen_base import gen_runner, gen_typing +from eth2spec.gen_helpers.gen_base import gen_runner, gen_typing def to_bytes(i): diff --git a/tests/generators/bls/requirements.txt b/tests/generators/bls/requirements.txt index 5f830773a..df386450b 100644 --- a/tests/generators/bls/requirements.txt +++ b/tests/generators/bls/requirements.txt @@ -1,4 +1,2 @@ -py_ecc==5.1.0 -eth-utils==1.6.0 -../../core/gen_helpers +pytest>=4.4 ../../../ diff --git a/tests/generators/epoch_processing/main.py b/tests/generators/epoch_processing/main.py index 1306da523..50a1e2b57 100644 --- a/tests/generators/epoch_processing/main.py +++ b/tests/generators/epoch_processing/main.py @@ -1,4 +1,4 @@ -from gen_from_tests.gen import run_state_test_generators +from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators from eth2spec.phase0 import spec as spec_phase0 from eth2spec.lightclient_patch import spec as spec_lightclient_patch from eth2spec.phase1 import spec as spec_phase1 diff --git a/tests/generators/epoch_processing/requirements.txt b/tests/generators/epoch_processing/requirements.txt index b82314298..df386450b 100644 --- a/tests/generators/epoch_processing/requirements.txt +++ b/tests/generators/epoch_processing/requirements.txt @@ -1,2 +1,2 @@ -../../core/gen_helpers -../../../ \ No newline at end of file +pytest>=4.4 +../../../ diff --git a/tests/generators/finality/main.py b/tests/generators/finality/main.py index 0a62b1aa5..8b961f9f4 100644 --- a/tests/generators/finality/main.py +++ b/tests/generators/finality/main.py @@ -1,4 +1,4 @@ -from gen_from_tests.gen import run_state_test_generators +from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators from eth2spec.phase0 import spec as spec_phase0 from eth2spec.lightclient_patch import spec as spec_lightclient_patch from eth2spec.phase1 import spec as spec_phase1 diff --git a/tests/generators/finality/requirements.txt b/tests/generators/finality/requirements.txt index b82314298..df386450b 100644 --- a/tests/generators/finality/requirements.txt +++ b/tests/generators/finality/requirements.txt @@ -1,2 +1,2 @@ -../../core/gen_helpers -../../../ \ No newline at end of file +pytest>=4.4 +../../../ diff --git a/tests/generators/genesis/main.py b/tests/generators/genesis/main.py index ce055b44a..854af6572 100644 --- a/tests/generators/genesis/main.py +++ b/tests/generators/genesis/main.py @@ -3,8 +3,8 @@ from typing import Iterable from eth2spec.test.context import PHASE0 from eth2spec.test.phase0.genesis import test_initialization, test_validity -from gen_base import gen_runner, gen_typing -from gen_from_tests.gen import generate_from_tests +from eth2spec.gen_helpers.gen_base import gen_runner, gen_typing +from eth2spec.gen_helpers.gen_from_tests.gen import generate_from_tests from eth2spec.phase0 import spec as spec from importlib import reload from eth2spec.config import config_util diff --git a/tests/generators/genesis/requirements.txt b/tests/generators/genesis/requirements.txt index b82314298..df386450b 100644 --- a/tests/generators/genesis/requirements.txt +++ b/tests/generators/genesis/requirements.txt @@ -1,2 +1,2 @@ -../../core/gen_helpers -../../../ \ No newline at end of file +pytest>=4.4 +../../../ diff --git a/tests/generators/operations/main.py b/tests/generators/operations/main.py index d40dbe9cd..00a58288f 100644 --- a/tests/generators/operations/main.py +++ b/tests/generators/operations/main.py @@ -1,4 +1,4 @@ -from gen_from_tests.gen import run_state_test_generators +from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators from eth2spec.phase0 import spec as spec_phase0 from eth2spec.lightclient_patch import spec as spec_lightclient_patch from eth2spec.phase1 import spec as spec_phase1 diff --git a/tests/generators/operations/requirements.txt b/tests/generators/operations/requirements.txt index a6ea61aea..df386450b 100644 --- a/tests/generators/operations/requirements.txt +++ b/tests/generators/operations/requirements.txt @@ -1,3 +1,2 @@ -eth-utils==1.6.0 -../../core/gen_helpers -../../../ \ No newline at end of file +pytest>=4.4 +../../../ diff --git a/tests/generators/rewards/main.py b/tests/generators/rewards/main.py index addb6aef0..4124587cc 100644 --- a/tests/generators/rewards/main.py +++ b/tests/generators/rewards/main.py @@ -1,4 +1,4 @@ -from gen_from_tests.gen import run_state_test_generators +from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators from eth2spec.phase0 import spec as spec_phase0 from eth2spec.lightclient_patch import spec as spec_lightclient_patch from eth2spec.phase1 import spec as spec_phase1 diff --git a/tests/generators/rewards/requirements.txt b/tests/generators/rewards/requirements.txt index b82314298..df386450b 100644 --- a/tests/generators/rewards/requirements.txt +++ b/tests/generators/rewards/requirements.txt @@ -1,2 +1,2 @@ -../../core/gen_helpers -../../../ \ No newline at end of file +pytest>=4.4 +../../../ diff --git a/tests/generators/sanity/main.py b/tests/generators/sanity/main.py index fc5227a53..5155798ff 100644 --- a/tests/generators/sanity/main.py +++ b/tests/generators/sanity/main.py @@ -1,9 +1,10 @@ -from gen_from_tests.gen import run_state_test_generators from eth2spec.phase0 import spec as spec_phase0 from eth2spec.lightclient_patch import spec as spec_lightclient_patch from eth2spec.phase1 import spec as spec_phase1 from eth2spec.test.context import PHASE0, PHASE1, LIGHTCLIENT_PATCH +from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators + specs = (spec_phase0, spec_lightclient_patch, spec_phase1) diff --git a/tests/generators/sanity/requirements.txt b/tests/generators/sanity/requirements.txt index b82314298..df386450b 100644 --- a/tests/generators/sanity/requirements.txt +++ b/tests/generators/sanity/requirements.txt @@ -1,2 +1,2 @@ -../../core/gen_helpers -../../../ \ No newline at end of file +pytest>=4.4 +../../../ diff --git a/tests/generators/shuffling/main.py b/tests/generators/shuffling/main.py index 6069de77a..091207bca 100644 --- a/tests/generators/shuffling/main.py +++ b/tests/generators/shuffling/main.py @@ -2,7 +2,7 @@ from eth_utils import to_tuple from typing import Iterable from importlib import reload -from gen_base import gen_runner, gen_typing +from eth2spec.gen_helpers.gen_base import gen_runner, gen_typing from eth2spec.config import config_util from eth2spec.phase0 import spec as spec diff --git a/tests/generators/ssz_generic/main.py b/tests/generators/ssz_generic/main.py index 8cfb2e3eb..737f8cda6 100644 --- a/tests/generators/ssz_generic/main.py +++ b/tests/generators/ssz_generic/main.py @@ -1,5 +1,5 @@ from typing import Iterable -from gen_base import gen_runner, gen_typing +from eth2spec.gen_helpers.gen_base import gen_runner, gen_typing import ssz_basic_vector import ssz_bitlist import ssz_bitvector diff --git a/tests/generators/ssz_generic/requirements.txt b/tests/generators/ssz_generic/requirements.txt index af061a3b1..df386450b 100644 --- a/tests/generators/ssz_generic/requirements.txt +++ b/tests/generators/ssz_generic/requirements.txt @@ -1,3 +1,2 @@ -eth-utils==1.6.0 -../../core/gen_helpers +pytest>=4.4 ../../../ diff --git a/tests/generators/ssz_static/main.py b/tests/generators/ssz_static/main.py index 38ff18615..8b18705e7 100644 --- a/tests/generators/ssz_static/main.py +++ b/tests/generators/ssz_static/main.py @@ -3,7 +3,7 @@ from typing import Iterable from importlib import reload from inspect import getmembers, isclass -from gen_base import gen_runner, gen_typing +from eth2spec.gen_helpers.gen_base import gen_runner, gen_typing from eth2spec.debug import random_value, encode from eth2spec.config import config_util diff --git a/tests/generators/ssz_static/requirements.txt b/tests/generators/ssz_static/requirements.txt index b82314298..df386450b 100644 --- a/tests/generators/ssz_static/requirements.txt +++ b/tests/generators/ssz_static/requirements.txt @@ -1,2 +1,2 @@ -../../core/gen_helpers -../../../ \ No newline at end of file +pytest>=4.4 +../../../ From e58dcb40acc4348047e681fc069b1c7abb33fa16 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Thu, 18 Feb 2021 17:51:01 +0800 Subject: [PATCH 11/56] Clean up and kick the cache --- setup.py | 3 +-- .../core/pyspec/eth2spec/gen_helpers/requirements.txt | 3 --- tests/core/pyspec/eth2spec/gen_helpers/setup.py | 11 ----------- 3 files changed, 1 insertion(+), 16 deletions(-) delete mode 100644 tests/core/pyspec/eth2spec/gen_helpers/requirements.txt delete mode 100644 tests/core/pyspec/eth2spec/gen_helpers/setup.py diff --git a/setup.py b/setup.py index 6b8520075..9c2696006 100644 --- a/setup.py +++ b/setup.py @@ -562,13 +562,12 @@ setup( url="https://github.com/ethereum/eth2.0-specs", include_package_data=False, package_data={'configs': ['*.yaml'], - 'specs': ['**/*.md'], 'eth2spec': ['VERSION.txt']}, package_dir={ "eth2spec": "tests/core/pyspec/eth2spec", "configs": "configs", - "specs": "specs" + "specs": "specs", }, packages=find_packages(where='tests/core/pyspec') + ['configs', 'specs'], py_modules=["eth2spec"], diff --git a/tests/core/pyspec/eth2spec/gen_helpers/requirements.txt b/tests/core/pyspec/eth2spec/gen_helpers/requirements.txt deleted file mode 100644 index e7cdd30ea..000000000 --- a/tests/core/pyspec/eth2spec/gen_helpers/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -ruamel.yaml==0.16.5 -eth-utils==1.6.0 -pytest>=4.4 diff --git a/tests/core/pyspec/eth2spec/gen_helpers/setup.py b/tests/core/pyspec/eth2spec/gen_helpers/setup.py deleted file mode 100644 index e9fc1a787..000000000 --- a/tests/core/pyspec/eth2spec/gen_helpers/setup.py +++ /dev/null @@ -1,11 +0,0 @@ -from distutils.core import setup - -setup( - name='gen_helpers', - packages=['gen_base', 'gen_from_tests'], - install_requires=[ - "ruamel.yaml==0.16.5", - "eth-utils==1.6.0", - "pytest>=4.4", - ] -) From a28b2d73493f8a978c6afec967156a752fe87fbd Mon Sep 17 00:00:00 2001 From: Justin Date: Sat, 20 Feb 2021 15:29:34 +0000 Subject: [PATCH 12/56] Bump Milagro dependency for M1 support --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 6b8520075..df95d99d3 100644 --- a/setup.py +++ b/setup.py @@ -583,7 +583,7 @@ setup( "eth-typing>=2.1.0,<3.0.0", "pycryptodome==3.9.4", "py_ecc==5.1.0", - "milagro_bls_binding==1.6.2", + "milagro_bls_binding==1.6.3", "dataclasses==0.6", "remerkleable==0.1.18", "ruamel.yaml==0.16.5", From de4cad5d3596abbcb0f3bb74d9cd478933b89f2e Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Mon, 22 Feb 2021 18:29:31 +0800 Subject: [PATCH 13/56] Update docs --- .../pyspec/eth2spec/gen_helpers/README.md | 2 +- .../gen_helpers/gen_from_tests/gen.py | 3 + tests/generators/README.md | 57 ++++++++++--------- 3 files changed, 34 insertions(+), 28 deletions(-) diff --git a/tests/core/pyspec/eth2spec/gen_helpers/README.md b/tests/core/pyspec/eth2spec/gen_helpers/README.md index 20b48db83..d39ee66ae 100644 --- a/tests/core/pyspec/eth2spec/gen_helpers/README.md +++ b/tests/core/pyspec/eth2spec/gen_helpers/README.md @@ -4,7 +4,7 @@ A util to quickly write new test suite generators with. -See [Generators documentation](../../generators/README.md) for integration details. +See [Generators documentation](../../../../generators/README.md) for integration details. Options: diff --git a/tests/core/pyspec/eth2spec/gen_helpers/gen_from_tests/gen.py b/tests/core/pyspec/eth2spec/gen_helpers/gen_from_tests/gen.py index f5a0f378b..67d29b194 100644 --- a/tests/core/pyspec/eth2spec/gen_helpers/gen_from_tests/gen.py +++ b/tests/core/pyspec/eth2spec/gen_helpers/gen_from_tests/gen.py @@ -85,6 +85,9 @@ def get_create_provider_fn( def run_state_test_generators(runner_name: str, specs: Iterable[Any], all_mods: Dict[str, Dict[str, str]]) -> None: + """ + Generate all available state tests of `TESTGEN_FORKS` forks of `ALL_CONFIGS` configs of the given runner. + """ for config_name in ALL_CONFIGS: for fork_name in TESTGEN_FORKS: if fork_name in all_mods: diff --git a/tests/generators/README.md b/tests/generators/README.md index b819d93b8..26094bbae 100644 --- a/tests/generators/README.md +++ b/tests/generators/README.md @@ -78,9 +78,8 @@ It's recommended to extend the base-generator. Create a `requirements.txt` in the root of your generator directory: ``` -../../core/gen_helpers -../../core/config_helpers -../../core/pyspec +pytest>=4.4 +../../../ ``` The config helper and pyspec is optional, but preferred. We encourage generators to derive tests from the spec itself in order to prevent code duplication and outdated tests. @@ -163,35 +162,40 @@ To extend this, one could decide to parametrize the `shuffling_test_cases` funct Another example, to generate tests from pytests: ```python -def create_provider(handler_name: str, tests_src, config_name: str) -> gen_typing.TestProvider: +from eth2spec.phase0 import spec as spec_phase0 +from eth2spec.lightclient_patch import spec as spec_lightclient_patch +from eth2spec.phase1 import spec as spec_phase1 +from eth2spec.test.context import PHASE0, PHASE1, LIGHTCLIENT_PATCH - def prepare_fn(configs_path: str) -> str: - presets = loader.load_presets(configs_path, config_name) - spec_phase0.apply_constants_preset(presets) - spec_phase1.apply_constants_preset(presets) - return config_name +from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators - def cases_fn() -> Iterable[gen_typing.TestCase]: - return generate_from_tests( - runner_name='epoch_processing', - handler_name=handler_name, - src=tests_src, - fork_name='phase0' - ) - return gen_typing.TestProvider(prepare=prepare_fn, make_cases=cases_fn) +specs = (spec_phase0, spec_lightclient_patch, spec_phase1) if __name__ == "__main__": - gen_runner.run_generator("epoch_processing", [ - create_provider('justification_and_finalization', test_process_justification_and_finalization, 'minimal'), - ... - ]) + phase_0_mods = {key: 'eth2spec.test.phase0.sanity.test_' + key for key in [ + 'blocks', + 'slots', + ]} + lightclient_patch_mods = {**{key: 'eth2spec.test.lightclient_patch.sanity.test_' + key for key in [ + 'blocks', + ]}, **phase_0_mods} # also run the previous phase 0 tests + phase_1_mods = {**{key: 'eth2spec.test.phase1.sanity.test_' + key for key in [ + 'blocks', # more phase 1 specific block tests + 'shard_blocks', + ]}, **phase_0_mods} # also run the previous phase 0 tests (but against phase 1 spec) + all_mods = { + PHASE0: phase_0_mods, + LIGHTCLIENT_PATCH: lightclient_patch_mods, + PHASE1: phase_1_mods, + } + + run_state_test_generators(runner_name="sanity", specs=specs, all_mods=all_mods) ``` -Here multiple phases load the configuration, and the stream of test cases is derived from a pytest file using the `generate_from_tests` utility. - +Here multiple phases load the configuration, and the stream of test cases is derived from a pytest file using the `eth2spec.gen_helpers.gen_from_tests.gen.run_state_test_generators` utility. Note that this helper generates all available tests of `TESTGEN_FORKS` forks of `ALL_CONFIGS` configs of the given runner. Recommendations: - You can have more than just one test provider. @@ -200,8 +204,7 @@ Recommendations: - Use config `minimal` for performance and simplicity, but also implement a suite with the `mainnet` config where necessary. - You may be able to write your test case provider in a way where it does not make assumptions on constants. If so, you can generate test cases with different configurations for the same scenario (see example). -- See [`tests/core/gen_helpers/README.md`](../core/gen_helpers/README.md) for command line options for generators. - +- See [`tests/core/gen_helpers/README.md`](../core/pyspec/eth2spec/gen_helpers/README.md) for command line options for generators. ## How to add a new test generator @@ -216,8 +219,8 @@ To add a new test generator that builds `New Tests`: 4. Your generator is called with `-o some/file/path/for_testing/can/be_anything -c some/other/path/to_configs/`. The base generator helps you handle this; you only have to define test case providers. 5. Finally, add any linting or testing commands to the - [circleci config file](../.circleci/config.yml) if desired to increase code quality. - Or add it to the [`Makefile`](../Makefile), if it can be run locally. + [circleci config file](../../.circleci/config.yml) if desired to increase code quality. + Or add it to the [`Makefile`](../../Makefile), if it can be run locally. *Note*: You do not have to change the makefile. However, if necessary (e.g. not using Python, or mixing in other languages), submit an issue, and it can be a special case. From f6b8171350f702501c997abf9bd837489b89dfb6 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Mon, 22 Feb 2021 19:45:10 +0800 Subject: [PATCH 14/56] Update shuffling generator requirements.txt --- tests/generators/shuffling/requirements.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/generators/shuffling/requirements.txt b/tests/generators/shuffling/requirements.txt index a6ea61aea..df386450b 100644 --- a/tests/generators/shuffling/requirements.txt +++ b/tests/generators/shuffling/requirements.txt @@ -1,3 +1,2 @@ -eth-utils==1.6.0 -../../core/gen_helpers -../../../ \ No newline at end of file +pytest>=4.4 +../../../ From 9f634dc6f6d269339d8e5fd7d069286fa75c2687 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marin=20Petruni=C4=87?= Date: Tue, 23 Feb 2021 09:56:38 +0100 Subject: [PATCH 15/56] Update test generation docs --- tests/generators/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/generators/README.md b/tests/generators/README.md index 26094bbae..7d0b5240c 100644 --- a/tests/generators/README.md +++ b/tests/generators/README.md @@ -36,7 +36,7 @@ Prerequisites: ### Cleaning -This removes the existing virtual environments (`/test_generators//venv`) and generated tests (`/yaml_tests/`). +This removes the existing virtual environments (`/tests/generators//venv`) and generated tests (`../eth2.0-spec-tests/tests`). ```bash make clean @@ -47,7 +47,7 @@ make clean This runs all of the generators. ```bash -make -j 4 gen_yaml_tests +make -j 4 generate_tests ``` The `-j N` flag makes the generators run in parallel, with `N` being the amount of cores. @@ -55,7 +55,7 @@ The `-j N` flag makes the generators run in parallel, with `N` being the amount ### Running a single generator -The makefile auto-detects generators in the `test_generators` directory and provides a tests-gen target for each generator. See example: +The makefile auto-detects generators in the `tests/generators` directory and provides a tests-gen target for each generator. See example: ```bash make ./eth2.0-spec-tests/tests/shuffling/ @@ -210,7 +210,7 @@ Recommendations: To add a new test generator that builds `New Tests`: -1. Create a new directory `new_tests` within the `test_generators` directory. +1. Create a new directory `new_tests` within the `tests/generators` directory. Note that `new_tests` is also the name of the directory in which the tests will appear in the tests repository later. 2. Your generator is assumed to have a `requirements.txt` file, with any dependencies it may need. Leave it empty if your generator has none. From e63754e6293b73cf056c3e5edc54569dba35439e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marin=20Petruni=C4=87?= Date: Tue, 23 Feb 2021 13:23:32 +0100 Subject: [PATCH 16/56] change how generator targets are invoked --- tests/generators/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/generators/README.md b/tests/generators/README.md index 7d0b5240c..0f1ed478f 100644 --- a/tests/generators/README.md +++ b/tests/generators/README.md @@ -55,10 +55,10 @@ The `-j N` flag makes the generators run in parallel, with `N` being the amount ### Running a single generator -The makefile auto-detects generators in the `tests/generators` directory and provides a tests-gen target for each generator. See example: +The makefile auto-detects generators in the `tests/generators` directory and provides a tests-gen target (gen_) for each generator. See example: ```bash -make ./eth2.0-spec-tests/tests/shuffling/ +make gen_ssz_static ``` ## Developing a generator From 1d4f467516436d0eb9d97692aef2fcd891f79a29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marin=20Petruni=C4=87?= Date: Tue, 23 Feb 2021 13:30:26 +0100 Subject: [PATCH 17/56] disable phase1/enable lightclient ssz static types test --- tests/generators/ssz_static/main.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/generators/ssz_static/main.py b/tests/generators/ssz_static/main.py index 8b18705e7..854961ae4 100644 --- a/tests/generators/ssz_static/main.py +++ b/tests/generators/ssz_static/main.py @@ -9,7 +9,8 @@ from eth2spec.debug import random_value, encode from eth2spec.config import config_util from eth2spec.phase0 import spec as spec_phase0 from eth2spec.phase1 import spec as spec_phase1 -from eth2spec.test.context import PHASE0, PHASE1 +from eth2spec.lightclient_patch import spec as spec_lightclient_patch +from eth2spec.test.context import PHASE0, PHASE1, LIGHTCLIENT_PATCH from eth2spec.utils.ssz.ssz_typing import Container from eth2spec.utils.ssz.ssz_impl import ( hash_tree_root, @@ -64,6 +65,7 @@ def create_provider(fork_name, config_name: str, seed: int, mode: random_value.R config_util.prepare_config(configs_path, config_name) reload(spec_phase0) reload(spec_phase1) + reload(spec_lightclient_patch) return config_name def cases_fn() -> Iterable[gen_typing.TestCase]: @@ -71,6 +73,8 @@ def create_provider(fork_name, config_name: str, seed: int, mode: random_value.R spec = spec_phase0 if fork_name == PHASE1: spec = spec_phase1 + if fork_name == LIGHTCLIENT_PATCH: + spec = spec_lightclient_patch for (i, (name, ssz_type)) in enumerate(get_spec_ssz_types(spec)): yield from ssz_static_cases(fork_name, seed * 1000 + i, name, ssz_type, mode, chaos, count) @@ -90,7 +94,7 @@ if __name__ == "__main__": settings.append((seed, "mainnet", random_value.RandomizationMode.mode_random, False, 5)) seed += 1 - for fork in [PHASE0, PHASE1]: + for fork in [PHASE0, LIGHTCLIENT_PATCH]: gen_runner.run_generator("ssz_static", [ create_provider(fork, config_name, seed, mode, chaos, cases_if_random) for (seed, config_name, mode, chaos, cases_if_random) in settings From 993bcdf082dbdbf2103bae608d409f54f75b3088 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Tue, 23 Feb 2021 21:17:12 +0800 Subject: [PATCH 18/56] Use constants --- tests/generators/ssz_static/main.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/generators/ssz_static/main.py b/tests/generators/ssz_static/main.py index 854961ae4..fb8635fa0 100644 --- a/tests/generators/ssz_static/main.py +++ b/tests/generators/ssz_static/main.py @@ -10,7 +10,7 @@ from eth2spec.config import config_util from eth2spec.phase0 import spec as spec_phase0 from eth2spec.phase1 import spec as spec_phase1 from eth2spec.lightclient_patch import spec as spec_lightclient_patch -from eth2spec.test.context import PHASE0, PHASE1, LIGHTCLIENT_PATCH +from eth2spec.test.context import PHASE0, PHASE1, LIGHTCLIENT_PATCH, TESTGEN_FORKS, MINIMAL, MAINNET from eth2spec.utils.ssz.ssz_typing import Container from eth2spec.utils.ssz.ssz_impl import ( hash_tree_root, @@ -87,14 +87,14 @@ if __name__ == "__main__": settings = [] seed = 1 for mode in random_value.RandomizationMode: - settings.append((seed, "minimal", mode, False, 30)) + settings.append((seed, MINIMAL, mode, False, 30)) seed += 1 - settings.append((seed, "minimal", random_value.RandomizationMode.mode_random, True, 30)) + settings.append((seed, MINIMAL, random_value.RandomizationMode.mode_random, True, 30)) seed += 1 - settings.append((seed, "mainnet", random_value.RandomizationMode.mode_random, False, 5)) + settings.append((seed, MAINNET, random_value.RandomizationMode.mode_random, False, 5)) seed += 1 - for fork in [PHASE0, LIGHTCLIENT_PATCH]: + for fork in TESTGEN_FORKS: gen_runner.run_generator("ssz_static", [ create_provider(fork, config_name, seed, mode, chaos, cases_if_random) for (seed, config_name, mode, chaos, cases_if_random) in settings From d28ec2fc75dc744d4d41201c2554b728c8e1d29a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marin=20Petruni=C4=87?= Date: Tue, 23 Feb 2021 14:46:53 +0100 Subject: [PATCH 19/56] fix lint --- tests/generators/ssz_static/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/generators/ssz_static/main.py b/tests/generators/ssz_static/main.py index fb8635fa0..e21fc4141 100644 --- a/tests/generators/ssz_static/main.py +++ b/tests/generators/ssz_static/main.py @@ -10,7 +10,7 @@ from eth2spec.config import config_util from eth2spec.phase0 import spec as spec_phase0 from eth2spec.phase1 import spec as spec_phase1 from eth2spec.lightclient_patch import spec as spec_lightclient_patch -from eth2spec.test.context import PHASE0, PHASE1, LIGHTCLIENT_PATCH, TESTGEN_FORKS, MINIMAL, MAINNET +from eth2spec.test.context import PHASE1, LIGHTCLIENT_PATCH, TESTGEN_FORKS, MINIMAL, MAINNET from eth2spec.utils.ssz.ssz_typing import Container from eth2spec.utils.ssz.ssz_impl import ( hash_tree_root, From 7af50cc8273597123ec7d92ac5a3a00a568e4391 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 11 Dec 2020 14:46:16 -0700 Subject: [PATCH 20/56] add eth1 withdrawal credentials to spec --- specs/phase0/beacon-chain.md | 5 +++ specs/phase0/deposit-contract.md | 13 ++++-- specs/phase0/validator.md | 42 +++++++++++++++--- .../block_processing/test_process_deposit.py | 43 +++++++++++++++++++ 4 files changed, 93 insertions(+), 10 deletions(-) diff --git a/specs/phase0/beacon-chain.md b/specs/phase0/beacon-chain.md index fcd681115..1e9357610 100644 --- a/specs/phase0/beacon-chain.md +++ b/specs/phase0/beacon-chain.md @@ -14,6 +14,7 @@ - [Misc](#misc) - [Gwei values](#gwei-values) - [Initial values](#initial-values) + - [Validator withdrawal credential versions](#validator-withdrawal-credential-versions) - [Time parameters](#time-parameters) - [State list lengths](#state-list-lengths) - [Rewards and penalties](#rewards-and-penalties) @@ -210,7 +211,11 @@ The following values are (non-configurable) constants used throughout the specif | Name | Value | | - | - | | `GENESIS_FORK_VERSION` | `Version('0x00000000')` | + +### Validator withdrawal credential versions + | `BLS_WITHDRAWAL_PREFIX` | `Bytes1('0x00')` | +| `ETH1_ADDRESS_WITHDRAWAL_PREFIX` | `Bytes1('0x01')` | ### Time parameters diff --git a/specs/phase0/deposit-contract.md b/specs/phase0/deposit-contract.md index 8b3035629..429ebf238 100644 --- a/specs/phase0/deposit-contract.md +++ b/specs/phase0/deposit-contract.md @@ -59,12 +59,17 @@ The amount of ETH (rounded down to the closest Gwei) sent to the deposit contrac #### Withdrawal credentials -One of the `DepositData` fields is `withdrawal_credentials`. It is a commitment to credentials for withdrawing validator balance (e.g. to another validator, or to shards). The first byte of `withdrawal_credentials` is a version number. As of now, the only expected format is as follows: +One of the `DepositData` fields is `withdrawal_credentials`. -* `withdrawal_credentials[:1] == BLS_WITHDRAWAL_PREFIX` -* `withdrawal_credentials[1:] == hash(withdrawal_pubkey)[1:]` where `withdrawal_pubkey` is a BLS pubkey +This field is a commitment to credentials for withdrawing validator balance (e.g. to another validator, or to shards). +The first byte of `withdrawal_credentials` is a version number. The remaining +bytes are content specific to the version. -The private key corresponding to `withdrawal_pubkey` will be required to initiate a withdrawal. It can be stored separately until a withdrawal is required, e.g. in cold storage. +Currently, `BLS_WITHDRAWAL_PREFIX` and `ETH1_ADDRESS_WITHDRAWAL_PREFIX` +versioned withdrawal credentials are supported. Read more in the [validator guide](./validator.md). + +*Note*: The deposit contract does *not* validate withdrawal credentials. +Thus, new versions can be added without modifications of the deposit contract. #### `DepositEvent` log diff --git a/specs/phase0/validator.md b/specs/phase0/validator.md index c6a91dcfc..32a1d1010 100644 --- a/specs/phase0/validator.md +++ b/specs/phase0/validator.md @@ -16,7 +16,9 @@ This is an accompanying document to [Ethereum 2.0 Phase 0 -- The Beacon Chain](. - [Becoming a validator](#becoming-a-validator) - [Initialization](#initialization) - [BLS public key](#bls-public-key) - - [BLS withdrawal key](#bls-withdrawal-key) + - [Withdrawal credentials](#withdrawal-credentials) + - [BLS key credentials](#bls-key-credentials) + - [Eth1 address credentials](#eth1-address-credentials) - [Submit deposit](#submit-deposit) - [Process deposit](#process-deposit) - [Validator index](#validator-index) @@ -101,14 +103,42 @@ A validator must initialize many parameters locally before submitting a deposit Validator public keys are [G1 points](beacon-chain.md#bls-signatures) on the [BLS12-381 curve](https://z.cash/blog/new-snark-curve). A private key, `privkey`, must be securely generated along with the resultant `pubkey`. This `privkey` must be "hot", that is, constantly available to sign data throughout the lifetime of the validator. -#### BLS withdrawal key +#### Withdrawal credentials -A secondary withdrawal private key, `withdrawal_privkey`, must also be securely generated along with the resultant `withdrawal_pubkey`. This `withdrawal_privkey` does not have to be available for signing during the normal lifetime of a validator and can live in "cold storage". +The `withdrawal_credentials` ultimately control the deposited ETH once the +validator has exited and is withdrawable. The 0th byte of this 32-byte field, +called the "withdrawal prefix" defines the withdrawal credential version +while the remaining 31 bytes define the version-specific content. -The validator constructs their `withdrawal_credentials` via the following: +The following withdrawal credentials versions are currently supported. The +validator must choose and construct a version for the `withdrawal_credentials` field. -* Set `withdrawal_credentials[:1] == BLS_WITHDRAWAL_PREFIX`. -* Set `withdrawal_credentials[1:] == hash(withdrawal_pubkey)[1:]`. +##### BLS key credentials + +BLS withdrawal credentials are controlled by a secondary withdrawal BLS private key, `bls_withdrawal_privkey`. +This key is securely generated along with the resultant `bls_withdrawal_pubkey`. +This `withdrawal_privkey` does not have to be available for signing during +the normal lifetime of a validator and can live in "cold storage". + +The validator constructs `withdrawal_credentials` as the following: +* Set `withdrawal_credentials[:1] = BLS_WITHDRAWAL_PREFIX`. +* Set `withdrawal_credentials[1:] = hash(bls_withdrawal_pubkey)[1:]`. + +##### Eth1 address credentials + +Eth1 address credentials are controlled by an eth1 address. This can be an either an externally owned account or a contract. + +The withdrawal to the address specified will be a normal ETH transfer (with no payload other than the validator's ETH) +triggered by an eth1 transaction that will handle gas price/limit and payment of fees. + +As long as such a withdrawal account/contract can receive ETH transfers, +the future withdrawal protocol is agnostic to all other implementation details. + +The validator selects a 20-byte eth1 address, `eth1_withdrawal_address`, and constructs `withdrawal_credentials` as the following: +* Set `withdrawal_credentials[:1] = ETH1_ADDRESS_WITHDRAWAL_PREFIX`. +* Set `withdrawal_credentials[12:] = eth1_withdrawal_address`. + +*Note*: Bytes `withdrawal_credentials[1:12]` remain the default `0x00` value. ### Submit deposit diff --git a/tests/core/pyspec/eth2spec/test/phase0/block_processing/test_process_deposit.py b/tests/core/pyspec/eth2spec/test/phase0/block_processing/test_process_deposit.py index b7a0de6c8..36e76f46c 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/block_processing/test_process_deposit.py +++ b/tests/core/pyspec/eth2spec/test/phase0/block_processing/test_process_deposit.py @@ -94,6 +94,49 @@ def test_new_deposit_over_max(spec, state): yield from run_deposit_processing(spec, state, deposit, validator_index) +@with_all_phases +@spec_state_test +def test_new_deposit_eth1_withdrawal_credentials(spec, state): + # fresh deposit = next validator index = validator appended to registry + validator_index = len(state.validators) + withdrawal_credentials = ( + spec.ETH1_ADDRESS_WITHDRAWAL_PREFIX + + b'\x00' * 11 # specified 0s + + b'\x59' * 20 # a 20-byte eth1 address + ) + amount = spec.MAX_EFFECTIVE_BALANCE + deposit = prepare_state_and_deposit( + spec, state, + validator_index, + amount, + withdrawal_credentials=withdrawal_credentials, + signed=True, + ) + + yield from run_deposit_processing(spec, state, deposit, validator_index) + + +@with_all_phases +@spec_state_test +def test_new_deposit_non_versioned_withdrawal_credentials(spec, state): + # fresh deposit = next validator index = validator appended to registry + validator_index = len(state.validators) + withdrawal_credentials = ( + b'\xFF' # Non specified withdrawal credentials version + + b'\x02' * 31 # Garabage bytes + ) + amount = spec.MAX_EFFECTIVE_BALANCE + deposit = prepare_state_and_deposit( + spec, state, + validator_index, + amount, + withdrawal_credentials=withdrawal_credentials, + signed=True, + ) + + yield from run_deposit_processing(spec, state, deposit, validator_index) + + @with_all_phases @spec_state_test @always_bls From 128efdd34da71a146c4e366d4b0970a83fb01a09 Mon Sep 17 00:00:00 2001 From: Justin Date: Sat, 12 Dec 2020 20:38:40 +0000 Subject: [PATCH 21/56] Fix table for withdrawal credentials prefixes Minor cosmetic fixes (misformated table, section title). --- specs/phase0/beacon-chain.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/specs/phase0/beacon-chain.md b/specs/phase0/beacon-chain.md index 1e9357610..a51c503eb 100644 --- a/specs/phase0/beacon-chain.md +++ b/specs/phase0/beacon-chain.md @@ -14,7 +14,7 @@ - [Misc](#misc) - [Gwei values](#gwei-values) - [Initial values](#initial-values) - - [Validator withdrawal credential versions](#validator-withdrawal-credential-versions) + - [Withdrawal credentials prefixes](#withdrawal-credentials-prefixes) - [Time parameters](#time-parameters) - [State list lengths](#state-list-lengths) - [Rewards and penalties](#rewards-and-penalties) @@ -212,8 +212,10 @@ The following values are (non-configurable) constants used throughout the specif | - | - | | `GENESIS_FORK_VERSION` | `Version('0x00000000')` | -### Validator withdrawal credential versions +### Withdrawal credentials prefixes +| Name | Value | +| - | - | | `BLS_WITHDRAWAL_PREFIX` | `Bytes1('0x00')` | | `ETH1_ADDRESS_WITHDRAWAL_PREFIX` | `Bytes1('0x01')` | From 47ebf438b349175a68f26fca7e889643bae818d7 Mon Sep 17 00:00:00 2001 From: Justin Date: Sat, 12 Dec 2020 20:40:59 +0000 Subject: [PATCH 22/56] Cleaner section title "Withdrawal prefixes" matches `[BLS]/[ETH1_ADDRESS]_WITHDRAWAL_PREFIX` --- specs/phase0/beacon-chain.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/specs/phase0/beacon-chain.md b/specs/phase0/beacon-chain.md index a51c503eb..084107340 100644 --- a/specs/phase0/beacon-chain.md +++ b/specs/phase0/beacon-chain.md @@ -14,7 +14,7 @@ - [Misc](#misc) - [Gwei values](#gwei-values) - [Initial values](#initial-values) - - [Withdrawal credentials prefixes](#withdrawal-credentials-prefixes) + - [Withdrawal prefixes](#withdrawal-prefixes) - [Time parameters](#time-parameters) - [State list lengths](#state-list-lengths) - [Rewards and penalties](#rewards-and-penalties) @@ -212,7 +212,7 @@ The following values are (non-configurable) constants used throughout the specif | - | - | | `GENESIS_FORK_VERSION` | `Version('0x00000000')` | -### Withdrawal credentials prefixes +### Withdrawal prefixes | Name | Value | | - | - | From e93f1e1fa8c54bc0f9d7ede5200c92c4a68badf9 Mon Sep 17 00:00:00 2001 From: Justin Date: Sat, 12 Dec 2020 20:50:10 +0000 Subject: [PATCH 23/56] Copy-edit deposit-contract.md --- specs/phase0/deposit-contract.md | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/specs/phase0/deposit-contract.md b/specs/phase0/deposit-contract.md index 429ebf238..3633ac3ae 100644 --- a/specs/phase0/deposit-contract.md +++ b/specs/phase0/deposit-contract.md @@ -61,15 +61,12 @@ The amount of ETH (rounded down to the closest Gwei) sent to the deposit contrac One of the `DepositData` fields is `withdrawal_credentials`. -This field is a commitment to credentials for withdrawing validator balance (e.g. to another validator, or to shards). -The first byte of `withdrawal_credentials` is a version number. The remaining -bytes are content specific to the version. +This field is a commitment to credentials for withdrawing validator balance, e.g. to another validator, to an Ethereum 1.0 address, or to a shard. +The first byte of `withdrawal_credentials` is a withdrawal prefix which specifies the withdrawal type. The remaining 31 bytes are specific to the withdrawal prefix. -Currently, `BLS_WITHDRAWAL_PREFIX` and `ETH1_ADDRESS_WITHDRAWAL_PREFIX` -versioned withdrawal credentials are supported. Read more in the [validator guide](./validator.md). +The withdrawal prefixes currently supported are `BLS_WITHDRAWAL_PREFIX` and `ETH1_ADDRESS_WITHDRAWAL_PREFIX`. Read more in the [validator guide](./validator.md). -*Note*: The deposit contract does *not* validate withdrawal credentials. -Thus, new versions can be added without modifications of the deposit contract. +*Note*: The deposit contract does not validate withdrawal credentials. Support for new withdrawal types can be added without modifying the deposit contract. #### `DepositEvent` log From 0f94fa51b894de331a0e4370a692658294517d56 Mon Sep 17 00:00:00 2001 From: Justin Date: Sat, 12 Dec 2020 21:46:39 +0000 Subject: [PATCH 24/56] Update validator.md --- specs/phase0/validator.md | 38 +++++++++++++------------------------- 1 file changed, 13 insertions(+), 25 deletions(-) diff --git a/specs/phase0/validator.md b/specs/phase0/validator.md index 32a1d1010..e26f51819 100644 --- a/specs/phase0/validator.md +++ b/specs/phase0/validator.md @@ -105,40 +105,28 @@ Validator public keys are [G1 points](beacon-chain.md#bls-signatures) on the [BL #### Withdrawal credentials -The `withdrawal_credentials` ultimately control the deposited ETH once the -validator has exited and is withdrawable. The 0th byte of this 32-byte field, -called the "withdrawal prefix" defines the withdrawal credential version -while the remaining 31 bytes define the version-specific content. +The `withdrawal_credentials` field specifies how a validator's withdrawable balance may be withdrawn. The first byte of this 32-byte field is a withdrawal prefix which defines the semantics of the remaining 31 bytes. The following withdrawal prefixes are currently supported. -The following withdrawal credentials versions are currently supported. The -validator must choose and construct a version for the `withdrawal_credentials` field. +##### `BLS_WITHDRAWAL_PREFIX` -##### BLS key credentials +Withdrawal credentials with the BLS withdrawal prefix allow a BLS key pair `(bls_withdrawal_privkey, bls_withdrawal_pubkey)` to trigger withdrawals. The `withdrawal_credentials` field must be constructed such that: -BLS withdrawal credentials are controlled by a secondary withdrawal BLS private key, `bls_withdrawal_privkey`. -This key is securely generated along with the resultant `bls_withdrawal_pubkey`. -This `withdrawal_privkey` does not have to be available for signing during -the normal lifetime of a validator and can live in "cold storage". +* `withdrawal_credentials[:1] == BLS_WITHDRAWAL_PREFIX` +* `withdrawal_credentials[1:] == hash(bls_withdrawal_pubkey)[1:]` -The validator constructs `withdrawal_credentials` as the following: -* Set `withdrawal_credentials[:1] = BLS_WITHDRAWAL_PREFIX`. -* Set `withdrawal_credentials[1:] = hash(bls_withdrawal_pubkey)[1:]`. +*Note*: The `bls_withdrawal_pubkey` is not required for validating and can be kept in cold storage. -##### Eth1 address credentials +##### `ETH1_ADDRESS_WITHDRAWAL_PREFIX` -Eth1 address credentials are controlled by an eth1 address. This can be an either an externally owned account or a contract. +Withdrawal credentials with the Eth1 address withdrawal prefix specify a 20-byte Eth1 address `eth1_withdrawal_address` as the recipient for all withdrawals. The `eth1_withdrawal_address` can be the address of an externally owned account or of a contract. The `withdrawal_credentials` field must be constructed such that: -The withdrawal to the address specified will be a normal ETH transfer (with no payload other than the validator's ETH) -triggered by an eth1 transaction that will handle gas price/limit and payment of fees. +* `withdrawal_credentials[:1] = ETH1_ADDRESS_WITHDRAWAL_PREFIX` +* `withdrawal_credentials[1:12] == Bytes32()[1:12]` +* `withdrawal_credentials[12:] = eth1_withdrawal_address` -As long as such a withdrawal account/contract can receive ETH transfers, -the future withdrawal protocol is agnostic to all other implementation details. +Withdrawals to `eth1_withdrawal_address` will be normal ETH transfers (with no payload other than the validator's ETH) triggered by an Eth1 transaction that will handle gas price/limit and payment of fees. As long as the account or contract with address `eth1_withdrawal_address` can receive ETH transfers the future withdrawal protocol is agnostic to all other implementation details. -The validator selects a 20-byte eth1 address, `eth1_withdrawal_address`, and constructs `withdrawal_credentials` as the following: -* Set `withdrawal_credentials[:1] = ETH1_ADDRESS_WITHDRAWAL_PREFIX`. -* Set `withdrawal_credentials[12:] = eth1_withdrawal_address`. - -*Note*: Bytes `withdrawal_credentials[1:12]` remain the default `0x00` value. +**TODO**: Be explicit about the endianness of `eth1_withdrawal_address`. ### Submit deposit From 80613a99bda9fc87f20da98efc49984afad677ea Mon Sep 17 00:00:00 2001 From: Justin Date: Sat, 12 Dec 2020 21:51:21 +0000 Subject: [PATCH 25/56] Update validator.md --- specs/phase0/validator.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/specs/phase0/validator.md b/specs/phase0/validator.md index e26f51819..e2d8967e5 100644 --- a/specs/phase0/validator.md +++ b/specs/phase0/validator.md @@ -15,8 +15,8 @@ This is an accompanying document to [Ethereum 2.0 Phase 0 -- The Beacon Chain](. - [Misc](#misc) - [Becoming a validator](#becoming-a-validator) - [Initialization](#initialization) - - [BLS public key](#bls-public-key) - - [Withdrawal credentials](#withdrawal-credentials) + - [`BLS_WITHDRAWAL_PREFIX`](#bls_withdrawal_prefix) + - [`ETH1_ADDRESS_WITHDRAWAL_PREFIX`](#eth1_address_withdrawal_prefix) - [BLS key credentials](#bls-key-credentials) - [Eth1 address credentials](#eth1-address-credentials) - [Submit deposit](#submit-deposit) @@ -105,7 +105,7 @@ Validator public keys are [G1 points](beacon-chain.md#bls-signatures) on the [BL #### Withdrawal credentials -The `withdrawal_credentials` field specifies how a validator's withdrawable balance may be withdrawn. The first byte of this 32-byte field is a withdrawal prefix which defines the semantics of the remaining 31 bytes. The following withdrawal prefixes are currently supported. +The `withdrawal_credentials` field contrains how a validator's withdrawable balance may be withdrawn. The first byte of this 32-byte field is a withdrawal prefix which defines the semantics of the remaining 31 bytes. The following withdrawal prefixes are currently supported. ##### `BLS_WITHDRAWAL_PREFIX` @@ -114,7 +114,7 @@ Withdrawal credentials with the BLS withdrawal prefix allow a BLS key pair `(bls * `withdrawal_credentials[:1] == BLS_WITHDRAWAL_PREFIX` * `withdrawal_credentials[1:] == hash(bls_withdrawal_pubkey)[1:]` -*Note*: The `bls_withdrawal_pubkey` is not required for validating and can be kept in cold storage. +*Note*: The `bls_withdrawal_privkey` is not required for validating and can be kept in cold storage. ##### `ETH1_ADDRESS_WITHDRAWAL_PREFIX` @@ -124,7 +124,7 @@ Withdrawal credentials with the Eth1 address withdrawal prefix specify a 20-byte * `withdrawal_credentials[1:12] == Bytes32()[1:12]` * `withdrawal_credentials[12:] = eth1_withdrawal_address` -Withdrawals to `eth1_withdrawal_address` will be normal ETH transfers (with no payload other than the validator's ETH) triggered by an Eth1 transaction that will handle gas price/limit and payment of fees. As long as the account or contract with address `eth1_withdrawal_address` can receive ETH transfers the future withdrawal protocol is agnostic to all other implementation details. +Withdrawals to `eth1_withdrawal_address` will be normal ETH transfers (with no payload other than the validator's ETH) triggered by an Eth1 transaction that will handle the gas price and gas limit, as well the payment of fees. As long as the account or contract with address `eth1_withdrawal_address` can receive ETH transfers the future withdrawal protocol is agnostic to all other implementation details. **TODO**: Be explicit about the endianness of `eth1_withdrawal_address`. From 1f8ca7179fd82e18f6644fbdaec5f1f930827e93 Mon Sep 17 00:00:00 2001 From: Justin Date: Sat, 12 Dec 2020 21:56:30 +0000 Subject: [PATCH 26/56] Update validator.md --- specs/phase0/validator.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/specs/phase0/validator.md b/specs/phase0/validator.md index e2d8967e5..780f313c7 100644 --- a/specs/phase0/validator.md +++ b/specs/phase0/validator.md @@ -105,11 +105,11 @@ Validator public keys are [G1 points](beacon-chain.md#bls-signatures) on the [BL #### Withdrawal credentials -The `withdrawal_credentials` field contrains how a validator's withdrawable balance may be withdrawn. The first byte of this 32-byte field is a withdrawal prefix which defines the semantics of the remaining 31 bytes. The following withdrawal prefixes are currently supported. +The `withdrawal_credentials` field constrains validator withdrawals. The first byte of this 32-byte field is a withdrawal prefix which defines the semantics of the remaining 31 bytes. The following withdrawal prefixes are currently supported. ##### `BLS_WITHDRAWAL_PREFIX` -Withdrawal credentials with the BLS withdrawal prefix allow a BLS key pair `(bls_withdrawal_privkey, bls_withdrawal_pubkey)` to trigger withdrawals. The `withdrawal_credentials` field must be constructed such that: +Withdrawal credentials with the BLS withdrawal prefix allow a BLS key pair `(bls_withdrawal_privkey, bls_withdrawal_pubkey)` to trigger withdrawals. The `withdrawal_credentials` field must be such that: * `withdrawal_credentials[:1] == BLS_WITHDRAWAL_PREFIX` * `withdrawal_credentials[1:] == hash(bls_withdrawal_pubkey)[1:]` @@ -118,11 +118,11 @@ Withdrawal credentials with the BLS withdrawal prefix allow a BLS key pair `(bls ##### `ETH1_ADDRESS_WITHDRAWAL_PREFIX` -Withdrawal credentials with the Eth1 address withdrawal prefix specify a 20-byte Eth1 address `eth1_withdrawal_address` as the recipient for all withdrawals. The `eth1_withdrawal_address` can be the address of an externally owned account or of a contract. The `withdrawal_credentials` field must be constructed such that: +Withdrawal credentials with the Eth1 address withdrawal prefix specify a 20-byte Eth1 address `eth1_withdrawal_address` as the recipient for all withdrawals. The `eth1_withdrawal_address` can be the address of either an externally owned account or of a contract. The `withdrawal_credentials` field must be such that: -* `withdrawal_credentials[:1] = ETH1_ADDRESS_WITHDRAWAL_PREFIX` -* `withdrawal_credentials[1:12] == Bytes32()[1:12]` -* `withdrawal_credentials[12:] = eth1_withdrawal_address` +* `withdrawal_credentials[:1] == ETH1_ADDRESS_WITHDRAWAL_PREFIX` +* `withdrawal_credentials[1:12] == b'\x00' * 11` +* `withdrawal_credentials[12:] == eth1_withdrawal_address` Withdrawals to `eth1_withdrawal_address` will be normal ETH transfers (with no payload other than the validator's ETH) triggered by an Eth1 transaction that will handle the gas price and gas limit, as well the payment of fees. As long as the account or contract with address `eth1_withdrawal_address` can receive ETH transfers the future withdrawal protocol is agnostic to all other implementation details. From 809fc7afaffaad7d31c9b3761c0f35226098da59 Mon Sep 17 00:00:00 2001 From: Justin Date: Sat, 12 Dec 2020 21:57:58 +0000 Subject: [PATCH 27/56] Update validator.md --- specs/phase0/validator.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/specs/phase0/validator.md b/specs/phase0/validator.md index 780f313c7..0fd254321 100644 --- a/specs/phase0/validator.md +++ b/specs/phase0/validator.md @@ -15,10 +15,10 @@ This is an accompanying document to [Ethereum 2.0 Phase 0 -- The Beacon Chain](. - [Misc](#misc) - [Becoming a validator](#becoming-a-validator) - [Initialization](#initialization) - - [`BLS_WITHDRAWAL_PREFIX`](#bls_withdrawal_prefix) - - [`ETH1_ADDRESS_WITHDRAWAL_PREFIX`](#eth1_address_withdrawal_prefix) - - [BLS key credentials](#bls-key-credentials) - - [Eth1 address credentials](#eth1-address-credentials) + - [BLS public key](#bls-public-key) + - [Withdrawal credentials](#withdrawal-credentials) + - [`BLS_WITHDRAWAL_PREFIX`](#bls_withdrawal_prefix) + - [`ETH1_ADDRESS_WITHDRAWAL_PREFIX`](#eth1_address_withdrawal_prefix) - [Submit deposit](#submit-deposit) - [Process deposit](#process-deposit) - [Validator index](#validator-index) From 5992e8ff050855b532fa7d2248fc1b825ef65b2e Mon Sep 17 00:00:00 2001 From: Justin Date: Sat, 12 Dec 2020 22:02:56 +0000 Subject: [PATCH 28/56] Update deposit-contract.md --- specs/phase0/deposit-contract.md | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/specs/phase0/deposit-contract.md b/specs/phase0/deposit-contract.md index 3633ac3ae..a953b1781 100644 --- a/specs/phase0/deposit-contract.md +++ b/specs/phase0/deposit-contract.md @@ -59,14 +59,9 @@ The amount of ETH (rounded down to the closest Gwei) sent to the deposit contrac #### Withdrawal credentials -One of the `DepositData` fields is `withdrawal_credentials`. +One of the `DepositData` fields is `withdrawal_credentials` which constrains validator withdrawals. The first byte of this 32-byte field is a withdrawal prefix which defines the semantics of the remaining 31 bytes. The withdrawal prefixes currently supported are `BLS_WITHDRAWAL_PREFIX` and `ETH1_ADDRESS_WITHDRAWAL_PREFIX`. Read more in the [validator guide](./validator.md#withdrawal-credentials). -This field is a commitment to credentials for withdrawing validator balance, e.g. to another validator, to an Ethereum 1.0 address, or to a shard. -The first byte of `withdrawal_credentials` is a withdrawal prefix which specifies the withdrawal type. The remaining 31 bytes are specific to the withdrawal prefix. - -The withdrawal prefixes currently supported are `BLS_WITHDRAWAL_PREFIX` and `ETH1_ADDRESS_WITHDRAWAL_PREFIX`. Read more in the [validator guide](./validator.md). - -*Note*: The deposit contract does not validate withdrawal credentials. Support for new withdrawal types can be added without modifying the deposit contract. +*Note*: The deposit contract does not validate the `withdrawal_credentials` field. Support for new withdrawal prefixes can be added without modifying the deposit contract. #### `DepositEvent` log From a0ae04839550e84459da083b35a578558f78cf68 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Mon, 14 Dec 2020 13:09:25 -0700 Subject: [PATCH 29/56] copy edits --- specs/phase0/deposit-contract.md | 8 ++++++-- specs/phase0/validator.md | 21 +++++++++++++++------ 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/specs/phase0/deposit-contract.md b/specs/phase0/deposit-contract.md index a953b1781..4c340d688 100644 --- a/specs/phase0/deposit-contract.md +++ b/specs/phase0/deposit-contract.md @@ -59,9 +59,13 @@ The amount of ETH (rounded down to the closest Gwei) sent to the deposit contrac #### Withdrawal credentials -One of the `DepositData` fields is `withdrawal_credentials` which constrains validator withdrawals. The first byte of this 32-byte field is a withdrawal prefix which defines the semantics of the remaining 31 bytes. The withdrawal prefixes currently supported are `BLS_WITHDRAWAL_PREFIX` and `ETH1_ADDRESS_WITHDRAWAL_PREFIX`. Read more in the [validator guide](./validator.md#withdrawal-credentials). +One of the `DepositData` fields is `withdrawal_credentials` which constrains validator withdrawals. +The first byte of this 32-byte field is a withdrawal prefix which defines the semantics of the remaining 31 bytes. +The withdrawal prefixes currently supported are `BLS_WITHDRAWAL_PREFIX` and `ETH1_ADDRESS_WITHDRAWAL_PREFIX`. +Read more in the [validator guide](./validator.md#withdrawal-credentials). -*Note*: The deposit contract does not validate the `withdrawal_credentials` field. Support for new withdrawal prefixes can be added without modifying the deposit contract. +*Note*: The deposit contract does not validate the `withdrawal_credentials` field. +Support for new withdrawal prefixes can be added without modifying the deposit contract. #### `DepositEvent` log diff --git a/specs/phase0/validator.md b/specs/phase0/validator.md index 0fd254321..6f8d36b93 100644 --- a/specs/phase0/validator.md +++ b/specs/phase0/validator.md @@ -105,11 +105,16 @@ Validator public keys are [G1 points](beacon-chain.md#bls-signatures) on the [BL #### Withdrawal credentials -The `withdrawal_credentials` field constrains validator withdrawals. The first byte of this 32-byte field is a withdrawal prefix which defines the semantics of the remaining 31 bytes. The following withdrawal prefixes are currently supported. +The `withdrawal_credentials` field constrains validator withdrawals. +The first byte of this 32-byte field is a withdrawal prefix which defines the semantics of the remaining 31 bytes. + +The following withdrawal prefixes are currently supported. ##### `BLS_WITHDRAWAL_PREFIX` -Withdrawal credentials with the BLS withdrawal prefix allow a BLS key pair `(bls_withdrawal_privkey, bls_withdrawal_pubkey)` to trigger withdrawals. The `withdrawal_credentials` field must be such that: +Withdrawal credentials with the BLS withdrawal prefix allow a BLS key pair +`(bls_withdrawal_privkey, bls_withdrawal_pubkey)` to trigger withdrawals. +The `withdrawal_credentials` field must be such that: * `withdrawal_credentials[:1] == BLS_WITHDRAWAL_PREFIX` * `withdrawal_credentials[1:] == hash(bls_withdrawal_pubkey)[1:]` @@ -118,15 +123,19 @@ Withdrawal credentials with the BLS withdrawal prefix allow a BLS key pair `(bls ##### `ETH1_ADDRESS_WITHDRAWAL_PREFIX` -Withdrawal credentials with the Eth1 address withdrawal prefix specify a 20-byte Eth1 address `eth1_withdrawal_address` as the recipient for all withdrawals. The `eth1_withdrawal_address` can be the address of either an externally owned account or of a contract. The `withdrawal_credentials` field must be such that: +Withdrawal credentials with the Eth1 address withdrawal prefix specify +a 20-byte Eth1 address `eth1_withdrawal_address` as the recipient for all withdrawals. +The `eth1_withdrawal_address` can be the address of either an externally owned account or of a contract. +The `withdrawal_credentials` field must be such that: * `withdrawal_credentials[:1] == ETH1_ADDRESS_WITHDRAWAL_PREFIX` * `withdrawal_credentials[1:12] == b'\x00' * 11` * `withdrawal_credentials[12:] == eth1_withdrawal_address` -Withdrawals to `eth1_withdrawal_address` will be normal ETH transfers (with no payload other than the validator's ETH) triggered by an Eth1 transaction that will handle the gas price and gas limit, as well the payment of fees. As long as the account or contract with address `eth1_withdrawal_address` can receive ETH transfers the future withdrawal protocol is agnostic to all other implementation details. - -**TODO**: Be explicit about the endianness of `eth1_withdrawal_address`. +Withdrawals to `eth1_withdrawal_address` will be normal ETH transfers (with no payload other than the validator's ETH) +triggered by an Eth1 transaction that will handle the gas price and gas limit, as well the payment of fees. +As long as the account or contract with address `eth1_withdrawal_address` can receive ETH transfers +the future withdrawal protocol is agnostic to all other implementation details. ### Submit deposit From 1f7e9fabf24f02d5e178b90ab3f9c27e7c57029c Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Tue, 16 Feb 2021 11:55:01 -0700 Subject: [PATCH 30/56] minor 0x01 PR feedback --- specs/phase0/validator.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/specs/phase0/validator.md b/specs/phase0/validator.md index 6f8d36b93..15be3ee70 100644 --- a/specs/phase0/validator.md +++ b/specs/phase0/validator.md @@ -126,14 +126,16 @@ The `withdrawal_credentials` field must be such that: Withdrawal credentials with the Eth1 address withdrawal prefix specify a 20-byte Eth1 address `eth1_withdrawal_address` as the recipient for all withdrawals. The `eth1_withdrawal_address` can be the address of either an externally owned account or of a contract. + The `withdrawal_credentials` field must be such that: * `withdrawal_credentials[:1] == ETH1_ADDRESS_WITHDRAWAL_PREFIX` * `withdrawal_credentials[1:12] == b'\x00' * 11` * `withdrawal_credentials[12:] == eth1_withdrawal_address` -Withdrawals to `eth1_withdrawal_address` will be normal ETH transfers (with no payload other than the validator's ETH) -triggered by an Eth1 transaction that will handle the gas price and gas limit, as well the payment of fees. +After the merge of eth1 into eth2, +withdrawals to `eth1_withdrawal_address` will be normal ETH transfers (with no payload other than the validator's ETH) +triggered by a user transaction that will set the gas price and gas limit as well pay fees. As long as the account or contract with address `eth1_withdrawal_address` can receive ETH transfers the future withdrawal protocol is agnostic to all other implementation details. From 192696a6c55c1dc437b90601eb398ed64695c9eb Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Mon, 7 Dec 2020 10:49:12 +0800 Subject: [PATCH 31/56] Set codespell<3.0.0,>=2.0.0 version and add `ether` to whitelist --- .circleci/config.yml | 2 +- .codespell-whitelist | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 2767bec70..b57e15458 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -120,7 +120,7 @@ jobs: - checkout - run: name: Check codespell - command: pip install codespell --user && make codespell + command: pip install 'codespell<3.0.0,>=2.0.0' --user && make codespell lint: docker: - image: circleci/python:3.8 diff --git a/.codespell-whitelist b/.codespell-whitelist index ff694e380..6b8bab36f 100644 --- a/.codespell-whitelist +++ b/.codespell-whitelist @@ -1,2 +1,3 @@ uint -byteorder \ No newline at end of file +byteorder +ether From d1401a7f60dafa7b5c8dd5a7a913de6d45457544 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Mon, 7 Dec 2020 10:59:05 +0800 Subject: [PATCH 32/56] Fix doctoc@2 version --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index b57e15458..e00463cc5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -111,7 +111,7 @@ jobs: - checkout - run: name: Check table of contents - command: sudo npm install -g doctoc && make check_toc + command: sudo npm install -g doctoc@2 && make check_toc codespell: docker: - image: circleci/python:3.8 From b789b10397f9a10c45066d5ee4c4f62d6c138cc3 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Mon, 7 Dec 2020 11:00:29 +0800 Subject: [PATCH 33/56] Minor update ToC --- specs/phase0/beacon-chain.md | 1 - specs/phase0/deposit-contract.md | 1 - specs/phase0/fork-choice.md | 1 - specs/phase0/p2p-interface.md | 1 - specs/phase0/validator.md | 1 - specs/phase0/weak-subjectivity.md | 1 - specs/phase1/beacon-chain.md | 1 - specs/phase1/custody-game.md | 1 - specs/phase1/fork-choice.md | 1 - specs/phase1/light-client-sync.md | 1 - specs/phase1/phase1-fork.md | 1 - specs/phase1/shard-fork-choice.md | 1 - specs/phase1/shard-transition.md | 1 - specs/phase1/validator.md | 1 - ssz/merkle-proofs.md | 1 - ssz/simple-serialize.md | 1 - 16 files changed, 16 deletions(-) diff --git a/specs/phase0/beacon-chain.md b/specs/phase0/beacon-chain.md index 084107340..682131546 100644 --- a/specs/phase0/beacon-chain.md +++ b/specs/phase0/beacon-chain.md @@ -5,7 +5,6 @@ - - [Introduction](#introduction) - [Notation](#notation) - [Custom types](#custom-types) diff --git a/specs/phase0/deposit-contract.md b/specs/phase0/deposit-contract.md index 4c340d688..02e762dae 100644 --- a/specs/phase0/deposit-contract.md +++ b/specs/phase0/deposit-contract.md @@ -5,7 +5,6 @@ - - [Introduction](#introduction) - [Constants](#constants) - [Configuration](#configuration) diff --git a/specs/phase0/fork-choice.md b/specs/phase0/fork-choice.md index 8bc108caa..b5689ecd2 100644 --- a/specs/phase0/fork-choice.md +++ b/specs/phase0/fork-choice.md @@ -5,7 +5,6 @@ - - [Introduction](#introduction) - [Fork choice](#fork-choice) - [Configuration](#configuration) diff --git a/specs/phase0/p2p-interface.md b/specs/phase0/p2p-interface.md index 43a097f7e..5dc892991 100644 --- a/specs/phase0/p2p-interface.md +++ b/specs/phase0/p2p-interface.md @@ -14,7 +14,6 @@ It consists of four main sections: - - [Network fundamentals](#network-fundamentals) - [Transport](#transport) - [Encryption and identification](#encryption-and-identification) diff --git a/specs/phase0/validator.md b/specs/phase0/validator.md index 15be3ee70..9e2ee7b1f 100644 --- a/specs/phase0/validator.md +++ b/specs/phase0/validator.md @@ -8,7 +8,6 @@ This is an accompanying document to [Ethereum 2.0 Phase 0 -- The Beacon Chain](. - - [Introduction](#introduction) - [Prerequisites](#prerequisites) - [Constants](#constants) diff --git a/specs/phase0/weak-subjectivity.md b/specs/phase0/weak-subjectivity.md index 9d433de8e..b4d78cb12 100644 --- a/specs/phase0/weak-subjectivity.md +++ b/specs/phase0/weak-subjectivity.md @@ -6,7 +6,6 @@ - - [Introduction](#introduction) - [Prerequisites](#prerequisites) - [Constants](#constants) diff --git a/specs/phase1/beacon-chain.md b/specs/phase1/beacon-chain.md index 23ce88aa9..c8f93cc7f 100644 --- a/specs/phase1/beacon-chain.md +++ b/specs/phase1/beacon-chain.md @@ -7,7 +7,6 @@ - - [Introduction](#introduction) - [Custom types](#custom-types) - [Configuration](#configuration) diff --git a/specs/phase1/custody-game.md b/specs/phase1/custody-game.md index 82eb35d86..33c2a0397 100644 --- a/specs/phase1/custody-game.md +++ b/specs/phase1/custody-game.md @@ -7,7 +7,6 @@ - - [Introduction](#introduction) - [Constants](#constants) - [Misc](#misc) diff --git a/specs/phase1/fork-choice.md b/specs/phase1/fork-choice.md index 3845b2b74..d2e1bfefe 100644 --- a/specs/phase1/fork-choice.md +++ b/specs/phase1/fork-choice.md @@ -7,7 +7,6 @@ - - [Introduction](#introduction) - [Updated data structures](#updated-data-structures) - [Extended `Store`](#extended-store) diff --git a/specs/phase1/light-client-sync.md b/specs/phase1/light-client-sync.md index 4d14485dd..107baa0c6 100644 --- a/specs/phase1/light-client-sync.md +++ b/specs/phase1/light-client-sync.md @@ -8,7 +8,6 @@ - - [Introduction](#introduction) - [Custom types](#custom-types) - [Constants](#constants) diff --git a/specs/phase1/phase1-fork.md b/specs/phase1/phase1-fork.md index b4ace1066..d81ca64b3 100644 --- a/specs/phase1/phase1-fork.md +++ b/specs/phase1/phase1-fork.md @@ -7,7 +7,6 @@ - - [Introduction](#introduction) - [Configuration](#configuration) - [Fork to Phase 1](#fork-to-phase-1) diff --git a/specs/phase1/shard-fork-choice.md b/specs/phase1/shard-fork-choice.md index 380269d13..177c9c18c 100644 --- a/specs/phase1/shard-fork-choice.md +++ b/specs/phase1/shard-fork-choice.md @@ -7,7 +7,6 @@ - - [Introduction](#introduction) - [Fork choice](#fork-choice) - [Helpers](#helpers) diff --git a/specs/phase1/shard-transition.md b/specs/phase1/shard-transition.md index f3a1f83ce..35d421cdd 100644 --- a/specs/phase1/shard-transition.md +++ b/specs/phase1/shard-transition.md @@ -7,7 +7,6 @@ - - [Introduction](#introduction) - [Helper functions](#helper-functions) - [Shard block verification functions](#shard-block-verification-functions) diff --git a/specs/phase1/validator.md b/specs/phase1/validator.md index 2bfea017e..c5893fbc6 100644 --- a/specs/phase1/validator.md +++ b/specs/phase1/validator.md @@ -8,7 +8,6 @@ - - [Introduction](#introduction) - [Prerequisites](#prerequisites) - [Constants](#constants) diff --git a/ssz/merkle-proofs.md b/ssz/merkle-proofs.md index 2f32e43eb..6772026fe 100644 --- a/ssz/merkle-proofs.md +++ b/ssz/merkle-proofs.md @@ -7,7 +7,6 @@ - - [Helper functions](#helper-functions) - [Generalized Merkle tree index](#generalized-merkle-tree-index) - [SSZ object to index](#ssz-object-to-index) diff --git a/ssz/simple-serialize.md b/ssz/simple-serialize.md index b0e7ec1e0..078da9eae 100644 --- a/ssz/simple-serialize.md +++ b/ssz/simple-serialize.md @@ -5,7 +5,6 @@ - - [Constants](#constants) - [Typing](#typing) - [Basic types](#basic-types) From fb974ed37f8a1b91cea92778a3003a94af6d6040 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Tue, 23 Feb 2021 16:35:01 -0700 Subject: [PATCH 34/56] bump version to 1.0.1 --- tests/core/pyspec/eth2spec/VERSION.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core/pyspec/eth2spec/VERSION.txt b/tests/core/pyspec/eth2spec/VERSION.txt index afaf360d3..7f207341d 100644 --- a/tests/core/pyspec/eth2spec/VERSION.txt +++ b/tests/core/pyspec/eth2spec/VERSION.txt @@ -1 +1 @@ -1.0.0 \ No newline at end of file +1.0.1 \ No newline at end of file From 396d399129090d6c8973acfa47edc50077b69d0a Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Wed, 24 Feb 2021 08:53:54 -0600 Subject: [PATCH 35/56] Apply suggestions from code review form @hwwhww Co-authored-by: Hsiao-Wei Wang --- specs/phase0/validator.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/specs/phase0/validator.md b/specs/phase0/validator.md index 9e2ee7b1f..8a6f221a7 100644 --- a/specs/phase0/validator.md +++ b/specs/phase0/validator.md @@ -132,10 +132,10 @@ The `withdrawal_credentials` field must be such that: * `withdrawal_credentials[1:12] == b'\x00' * 11` * `withdrawal_credentials[12:] == eth1_withdrawal_address` -After the merge of eth1 into eth2, +After the merge of the current Ethereum application layer (Eth1) into the Beacon Chain (Eth2), withdrawals to `eth1_withdrawal_address` will be normal ETH transfers (with no payload other than the validator's ETH) triggered by a user transaction that will set the gas price and gas limit as well pay fees. -As long as the account or contract with address `eth1_withdrawal_address` can receive ETH transfers +As long as the account or contract with address `eth1_withdrawal_address` can receive ETH transfers, the future withdrawal protocol is agnostic to all other implementation details. ### Submit deposit From deace8768e87ccd3cdc64d759c1752f764fdc3b8 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Mon, 1 Mar 2021 18:19:12 -0700 Subject: [PATCH 36/56] port @justindrake's general cleanups from #2212 --- configs/mainnet/lightclient_patch.yaml | 2 +- configs/minimal/lightclient_patch.yaml | 2 +- specs/lightclient/beacon-chain.md | 227 +++++++++--------- specs/lightclient/lightclient-fork.md | 6 +- .../pyspec/eth2spec/test/helpers/rewards.py | 47 ++-- ..._process_justification_and_finalization.py | 6 +- .../test/phase0/sanity/test_blocks.py | 2 +- 7 files changed, 150 insertions(+), 142 deletions(-) diff --git a/configs/mainnet/lightclient_patch.yaml b/configs/mainnet/lightclient_patch.yaml index 6c5b16edf..a9ddc16f6 100644 --- a/configs/mainnet/lightclient_patch.yaml +++ b/configs/mainnet/lightclient_patch.yaml @@ -17,7 +17,7 @@ HF1_PROPORTIONAL_SLASHING_MULTIPLIER: 2 # 2**10 (=1,024) SYNC_COMMITTEE_SIZE: 1024 # 2**6 (=64) -SYNC_COMMITTEE_PUBKEY_AGGREGATES_SIZE: 64 +SYNC_SUBCOMMITTEE_SIZE: 64 # Time parameters diff --git a/configs/minimal/lightclient_patch.yaml b/configs/minimal/lightclient_patch.yaml index 7ab5f34ba..56ce34591 100644 --- a/configs/minimal/lightclient_patch.yaml +++ b/configs/minimal/lightclient_patch.yaml @@ -17,7 +17,7 @@ HF1_PROPORTIONAL_SLASHING_MULTIPLIER: 2 # [customized] SYNC_COMMITTEE_SIZE: 32 # [customized] -SYNC_COMMITTEE_PUBKEY_AGGREGATES_SIZE: 16 +SYNC_SUBCOMMITTEE_SIZE: 16 # Time parameters diff --git a/specs/lightclient/beacon-chain.md b/specs/lightclient/beacon-chain.md index bf9b6a092..de0fdf8c5 100644 --- a/specs/lightclient/beacon-chain.md +++ b/specs/lightclient/beacon-chain.md @@ -9,8 +9,8 @@ - [Introduction](#introduction) - [Custom types](#custom-types) - [Constants](#constants) - - [Validator action flags](#validator-action-flags) - - [Participation rewards](#participation-rewards) + - [Participation flag indices](#participation-flag-indices) + - [Participation flag fractions](#participation-flag-fractions) - [Misc](#misc) - [Configuration](#configuration) - [Updated penalty values](#updated-penalty-values) @@ -27,7 +27,9 @@ - [`Predicates`](#predicates) - [`eth2_fast_aggregate_verify`](#eth2_fast_aggregate_verify) - [Misc](#misc-2) - - [`flags_and_numerators`](#flags_and_numerators) + - [`get_flag_indices_and_numerators`](#get_flag_indices_and_numerators) + - [`add_flag`](#add_flag) + - [`has_flag`](#has_flag) - [Beacon state accessors](#beacon-state-accessors) - [`get_sync_committee_indices`](#get_sync_committee_indices) - [`get_sync_committee`](#get_sync_committee) @@ -38,15 +40,15 @@ - [Beacon state mutators](#beacon-state-mutators) - [New `slash_validator`](#new-slash_validator) - [Block processing](#block-processing) - - [New `process_attestation`](#new-process_attestation) + - [Modified `process_attestation`](#modified-process_attestation) - [New `process_deposit`](#new-process_deposit) - [Sync committee processing](#sync-committee-processing) - [Epoch processing](#epoch-processing) - - [New `process_justification_and_finalization`](#new-process_justification_and_finalization) - - [New `process_rewards_and_penalties`](#new-process_rewards_and_penalties) - - [New `process_slashings`](#new-process_slashings) - - [Sync committee updates](#sync-committee-updates) + - [Justification and finalization](#justification-and-finalization) + - [Rewards and penalties](#rewards-and-penalties) + - [Slashings](#slashings) - [Participation flags updates](#participation-flags-updates) + - [Sync committee updates](#sync-committee-updates) @@ -66,34 +68,29 @@ It has four main features: | Name | SSZ equivalent | Description | | - | - | - | -| `ValidatorFlag` | `uint8` | Bitflags to track validator actions with | +| `ParticipationFlags` | `uint8` | A succinct representation of 8 boolean participation flags | ## Constants -### Validator action flags - -This is formatted as an enum, with values `2**i` that can be combined as bit-flags. -The `0` value is reserved as default. Remaining bits in `ValidatorFlag` may be used in future hardforks. - -**Note**: Unlike Phase0, a `TIMELY_TARGET_FLAG` does not necessarily imply a `TIMELY_SOURCE_FLAG` -due to the varying slot delay requirements of each. +### Participation flag indices | Name | Value | | - | - | -| `TIMELY_HEAD_FLAG` | `ValidatorFlag(2**0)` (= 1) | -| `TIMELY_SOURCE_FLAG` | `ValidatorFlag(2**1)` (= 2) | -| `TIMELY_TARGET_FLAG` | `ValidatorFlag(2**2)` (= 4) | +| `TIMELY_HEAD_FLAG_INDEX` | `0` | +| `TIMELY_SOURCE_FLAG_INDEX` | `1` | +| `TIMELY_TARGET_FLAG_INDEX` | `2` | -### Participation rewards +### Participation flag fractions | Name | Value | | - | - | -| `TIMELY_HEAD_NUMERATOR` | `12` | -| `TIMELY_SOURCE_NUMERATOR` | `12` | -| `TIMELY_TARGET_NUMERATOR` | `32` | -| `REWARD_DENOMINATOR` | `64` | +| `TIMELY_HEAD_FLAG_NUMERATOR` | `12` | +| `TIMELY_SOURCE_FLAG_NUMERATOR` | `12` | +| `TIMELY_TARGET_FLAG_NUMERATOR` | `32` | +| `FLAG_DENOMINATOR` | `64` | -The reward fractions add up to 7/8, leaving the remaining 1/8 for proposer rewards and other future micro-rewards. +**Note**: The participatition flag fractions add up to 7/8. +The remaining 1/8 is for proposer incentives and other future micro-incentives. ### Misc @@ -119,8 +116,8 @@ This patch updates a few configuration values to move penalty constants toward t | Name | Value | | - | - | -| `SYNC_COMMITTEE_SIZE` | `uint64(2**10)` (= 1024) | -| `SYNC_COMMITTEE_PUBKEY_AGGREGATES_SIZE` | `uint64(2**6)` (= 64) | +| `SYNC_COMMITTEE_SIZE` | `uint64(2**10)` (= 1,024) | +| `SYNC_SUBCOMMITTEE_SIZE` | `uint64(2**6)` (= 64) | ### Time parameters @@ -144,10 +141,19 @@ order and append any additional fields to the end. #### `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] # Sync committee aggregate signature - sync_committee_bits: Bitvector[SYNC_COMMITTEE_SIZE] - sync_committee_signature: BLSSignature + sync_committee_bits: Bitvector[SYNC_COMMITTEE_SIZE] # [New in HF1] + sync_committee_signature: BLSSignature # [New in HF1] ``` #### `BeaconState` @@ -176,8 +182,8 @@ class BeaconState(Container): # Slashings slashings: Vector[Gwei, EPOCHS_PER_SLASHINGS_VECTOR] # Per-epoch sums of slashed effective balances # Participation - previous_epoch_participation: List[ValidatorFlag, VALIDATOR_REGISTRY_LIMIT] - current_epoch_participation: List[ValidatorFlag, VALIDATOR_REGISTRY_LIMIT] + previous_epoch_participation: List[ParticipationFlags, VALIDATOR_REGISTRY_LIMIT] + current_epoch_participation: List[ParticipationFlags, VALIDATOR_REGISTRY_LIMIT] # Finality justification_bits: Bitvector[JUSTIFICATION_BITS_LENGTH] # Bit set for every recent justified epoch previous_justified_checkpoint: Checkpoint @@ -195,7 +201,7 @@ class BeaconState(Container): ```python class SyncCommittee(Container): pubkeys: Vector[BLSPubkey, SYNC_COMMITTEE_SIZE] - pubkey_aggregates: Vector[BLSPubkey, SYNC_COMMITTEE_SIZE // SYNC_COMMITTEE_PUBKEY_AGGREGATES_SIZE] + pubkey_aggregates: Vector[BLSPubkey, SYNC_COMMITTEE_SIZE // SYNC_SUBCOMMITTEE_SIZE] ``` ## Helper functions @@ -216,25 +222,31 @@ def eth2_fast_aggregate_verify(pubkeys: Sequence[BLSPubkey], message: Bytes32, s ### Misc -#### `flags_and_numerators` +#### `get_flag_indices_and_numerators` ```python -def get_flags_and_numerators() -> Sequence[Tuple[ValidatorFlag, int]]: +def get_flag_indices_and_numerators() -> Sequence[Tuple[int, int]]: return ( - (TIMELY_HEAD_FLAG, TIMELY_HEAD_NUMERATOR), - (TIMELY_SOURCE_FLAG, TIMELY_SOURCE_NUMERATOR), - (TIMELY_TARGET_FLAG, TIMELY_TARGET_NUMERATOR) + (TIMELY_HEAD_FLAG_INDEX, TIMELY_HEAD_FLAG_NUMERATOR), + (TIMELY_SOURCE_FLAG_INDEX, TIMELY_SOURCE_FLAG_NUMERATOR), + (TIMELY_TARGET_FLAG_INDEX, TIMELY_TARGET_FLAG_NUMERATOR), ) ``` -```python -def add_validator_flags(flags: ValidatorFlag, add: ValidatorFlag) -> ValidatorFlag: - return flags | add -``` +#### `add_flag` ```python -def has_validator_flags(flags: ValidatorFlag, has: ValidatorFlag) -> bool: - return flags & has == has +def add_flag(flags: ParticipationFlags, flag_index: int) -> ParticipationFlags: + flag = ParticipationFlags(2**flag_index) + return flags | flag +``` + +#### `has_flag` + +```python +def has_flag(flags: ParticipationFlags, flag_index: int) -> bool: + flag = ParticipationFlags(2**flag_index) + return flags & flag == flag ``` ### Beacon state accessors @@ -275,8 +287,8 @@ def get_sync_committee(state: BeaconState, epoch: Epoch) -> SyncCommittee: validators = [state.validators[index] for index in indices] pubkeys = [validator.pubkey for validator in validators] aggregates = [ - bls.AggregatePKs(pubkeys[i:i + SYNC_COMMITTEE_PUBKEY_AGGREGATES_SIZE]) - for i in range(0, len(pubkeys), SYNC_COMMITTEE_PUBKEY_AGGREGATES_SIZE) + bls.AggregatePKs(pubkeys[i:i + SYNC_SUBCOMMITTEE_SIZE]) + for i in range(0, len(pubkeys), SYNC_SUBCOMMITTEE_SIZE) ] return SyncCommittee(pubkeys=pubkeys, pubkey_aggregates=aggregates) ``` @@ -295,19 +307,17 @@ def get_base_reward(state: BeaconState, index: ValidatorIndex) -> Gwei: #### `get_unslashed_participating_indices` ```python -def get_unslashed_participating_indices(state: BeaconState, flags: ValidatorFlag, epoch: Epoch) -> Set[ValidatorIndex]: +def get_unslashed_participating_indices(state: BeaconState, flag_index: int, epoch: Epoch) -> Set[ValidatorIndex]: """ - Retrieve the active validator indices of the given epoch, which are not slashed, and have all of the given flags. + Retrieve the active and unslashed validator indices for the given epoch and flag index. """ assert epoch in (get_previous_epoch(state), get_current_epoch(state)) if epoch == get_current_epoch(state): epoch_participation = state.current_epoch_participation else: epoch_participation = state.previous_epoch_participation - participating_indices = [ - index for index in get_active_validator_indices(state, epoch) - if has_validator_flags(epoch_participation[index], flags) - ] + active_validator_indices = get_active_validator_indices(state, epoch) + participating_indices = [i for i in active_validator_indices if has_flag(epoch_participation[i], flag_index)] return set(filter(lambda index: not state.validators[index].slashed, participating_indices)) ``` @@ -315,7 +325,7 @@ def get_unslashed_participating_indices(state: BeaconState, flags: ValidatorFlag ```python def get_flag_deltas(state: BeaconState, - flag: ValidatorFlag, + flag_index: int, numerator: uint64) -> Tuple[Sequence[Gwei], Sequence[Gwei]]: """ Compute the rewards and penalties associated with a particular duty, by scanning through the participation @@ -324,7 +334,7 @@ def get_flag_deltas(state: BeaconState, rewards = [Gwei(0)] * len(state.validators) penalties = [Gwei(0)] * len(state.validators) - unslashed_participating_indices = get_unslashed_participating_indices(state, flag, get_previous_epoch(state)) + unslashed_participating_indices = get_unslashed_participating_indices(state, flag_index, get_previous_epoch(state)) increment = EFFECTIVE_BALANCE_INCREMENT # Factored out from balances to avoid uint64 overflow unslashed_participating_increments = get_total_balance(state, unslashed_participating_indices) // increment active_increments = get_total_active_balance(state) // increment @@ -333,14 +343,14 @@ def get_flag_deltas(state: BeaconState, if index in unslashed_participating_indices: if is_in_inactivity_leak(state): # Optimal participation is fully rewarded to cancel the inactivity penalty - rewards[index] = base_reward * numerator // REWARD_DENOMINATOR + rewards[index] = base_reward * numerator // FLAG_DENOMINATOR else: rewards[index] = ( (base_reward * numerator * unslashed_participating_increments) - // (active_increments * REWARD_DENOMINATOR) + // (active_increments * FLAG_DENOMINATOR) ) else: - penalties[index] = base_reward * numerator // REWARD_DENOMINATOR + penalties[index] = base_reward * numerator // FLAG_DENOMINATOR return rewards, penalties ``` @@ -358,13 +368,13 @@ def get_inactivity_penalty_deltas(state: BeaconState) -> Tuple[Sequence[Gwei], S """ penalties = [Gwei(0) for _ in range(len(state.validators))] if is_in_inactivity_leak(state): - reward_numerator_sum = sum(numerator for (_, numerator) in get_flags_and_numerators()) + reward_numerator_sum = sum(numerator for (_, numerator) in get_flag_indices_and_numerators()) matching_target_attesting_indices = get_unslashed_participating_indices( - state, TIMELY_TARGET_FLAG, get_previous_epoch(state) + state, TIMELY_TARGET_FLAG_INDEX, get_previous_epoch(state) ) for index in get_eligible_validator_indices(state): # If validator is performing optimally this cancels all attestation rewards for a neutral balance - penalties[index] += Gwei(get_base_reward(state, index) * reward_numerator_sum // REWARD_DENOMINATOR) + penalties[index] += Gwei(get_base_reward(state, index) * reward_numerator_sum // FLAG_DENOMINATOR) if index not in matching_target_attesting_indices: effective_balance = state.validators[index].effective_balance penalties[index] += Gwei( @@ -415,12 +425,11 @@ def process_block(state: BeaconState, block: BeaconBlock) -> None: process_block_header(state, block) process_randao(state, block.body) process_eth1_data(state, block.body) - process_operations(state, block.body) - # Light client support - process_sync_committee(state, block.body) + process_operations(state, block.body) # [Modified in HF1] + process_sync_committee(state, block.body) # [New in HF1] ``` -#### New `process_attestation` +#### Modified `process_attestation` *Note*: The function `process_attestation` is modified to do incentive accounting with epoch participation flags. @@ -451,25 +460,25 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None: # Verify signature assert is_valid_indexed_attestation(state, get_indexed_attestation(state, attestation)) - # Participation flags - participation_flags = [] + # Participation flag indices + participation_flag_indices = [] if is_matching_head and is_matching_target and state.slot <= data.slot + MIN_ATTESTATION_INCLUSION_DELAY: - participation_flags.append(TIMELY_HEAD_FLAG) + participation_flag_indices.append(TIMELY_HEAD_FLAG_INDEX) if is_matching_source and state.slot <= data.slot + integer_squareroot(SLOTS_PER_EPOCH): - participation_flags.append(TIMELY_SOURCE_FLAG) + participation_flag_indices.append(TIMELY_SOURCE_FLAG_INDEX) if is_matching_target and state.slot <= data.slot + SLOTS_PER_EPOCH: - participation_flags.append(TIMELY_TARGET_FLAG) + participation_flag_indices.append(TIMELY_TARGET_FLAG_INDEX) # Update epoch participation flags proposer_reward_numerator = 0 for index in get_attesting_indices(state, data, attestation.aggregation_bits): - for flag, numerator in get_flags_and_numerators(): - if flag in participation_flags and not has_validator_flags(epoch_participation[index], flag): - epoch_participation[index] = add_validator_flags(epoch_participation[index], flag) - proposer_reward_numerator += get_base_reward(state, index) * numerator + for flag_index, flag_numerator in get_flag_indices_and_numerators(): + if flag_index in participation_flag_indices and not has_flag(epoch_participation[index], flag_index): + epoch_participation[index] = add_flag(epoch_participation[index], flag_index) + proposer_reward_numerator += get_base_reward(state, index) * flag_numerator # Reward proposer - proposer_reward = Gwei(proposer_reward_numerator // (REWARD_DENOMINATOR * PROPOSER_REWARD_QUOTIENT)) + proposer_reward = Gwei(proposer_reward_numerator // (FLAG_DENOMINATOR * PROPOSER_REWARD_QUOTIENT)) increase_balance(state, get_beacon_proposer_index(state), proposer_reward) ``` @@ -511,8 +520,8 @@ def process_deposit(state: BeaconState, deposit: Deposit) -> None: state.validators.append(get_validator_from_deposit(state, deposit)) state.balances.append(amount) # [Added in hf-1] Initialize empty participation flags for new validator - state.previous_epoch_participation.append(ValidatorFlag(0)) - state.current_epoch_participation.append(ValidatorFlag(0)) + state.previous_epoch_participation.append(ParticipationFlags(0b0000_0000)) + state.current_epoch_participation.append(ParticipationFlags(0b0000_0000)) else: # Increase balance by deposit amount index = ValidatorIndex(validator_pubkeys.index(pubkey)) @@ -534,26 +543,26 @@ def process_sync_committee(state: BeaconState, body: BeaconBlockBody) -> None: assert eth2_fast_aggregate_verify(participant_pubkeys, signing_root, body.sync_committee_signature) # Reward sync committee participants - total_proposer_reward = Gwei(0) + proposer_rewards = Gwei(0) active_validator_count = uint64(len(get_active_validator_indices(state, get_current_epoch(state)))) for participant_index in participant_indices: - base_reward = get_base_reward(state, participant_index) proposer_reward = get_proposer_reward(state, participant_index) + proposer_rewards += proposer_reward + base_reward = get_base_reward(state, participant_index) max_participant_reward = base_reward - proposer_reward - reward = Gwei(max_participant_reward * active_validator_count // len(committee_indices) // SLOTS_PER_EPOCH) + reward = Gwei(max_participant_reward * active_validator_count // (len(committee_indices) * SLOTS_PER_EPOCH)) increase_balance(state, participant_index, reward) - total_proposer_reward += proposer_reward # Reward beacon proposer - increase_balance(state, get_beacon_proposer_index(state), total_proposer_reward) + increase_balance(state, get_beacon_proposer_index(state), proposer_rewards) ``` ### Epoch processing ```python def process_epoch(state: BeaconState) -> None: - process_justification_and_finalization(state) # [Updated in HF1] - process_rewards_and_penalties(state) # [Updated in HF1] + process_justification_and_finalization(state) # [Modified in HF1] + process_rewards_and_penalties(state) # [Modified in HF1] process_registry_updates(state) process_slashings(state) process_eth1_data_reset(state) @@ -561,13 +570,11 @@ def process_epoch(state: BeaconState) -> None: process_slashings_reset(state) process_randao_mixes_reset(state) process_historical_roots_update(state) - # [Removed in HF1] -- process_participation_record_updates(state) - # [Added in HF1] - process_participation_flag_updates(state) - process_sync_committee_updates(state) + process_participation_flag_updates(state) # [New in HF1] + process_sync_committee_updates(state) # [New in HF1] ``` -#### New `process_justification_and_finalization` +#### Justification and finalization *Note*: The function `process_justification_and_finalization` is modified with `matching_target_attestations` replaced by `matching_target_indices`. @@ -586,12 +593,12 @@ def process_justification_and_finalization(state: BeaconState) -> None: state.previous_justified_checkpoint = state.current_justified_checkpoint state.justification_bits[1:] = state.justification_bits[:JUSTIFICATION_BITS_LENGTH - 1] state.justification_bits[0] = 0b0 - matching_target_indices = get_unslashed_participating_indices(state, TIMELY_TARGET_FLAG, previous_epoch) + matching_target_indices = get_unslashed_participating_indices(state, TIMELY_TARGET_FLAG_INDEX, previous_epoch) if get_total_balance(state, matching_target_indices) * 3 >= get_total_active_balance(state) * 2: state.current_justified_checkpoint = Checkpoint(epoch=previous_epoch, root=get_block_root(state, previous_epoch)) state.justification_bits[1] = 0b1 - matching_target_indices = get_unslashed_participating_indices(state, TIMELY_TARGET_FLAG, current_epoch) + matching_target_indices = get_unslashed_participating_indices(state, TIMELY_TARGET_FLAG_INDEX, current_epoch) if get_total_balance(state, matching_target_indices) * 3 >= get_total_active_balance(state) * 2: state.current_justified_checkpoint = Checkpoint(epoch=current_epoch, root=get_block_root(state, current_epoch)) @@ -613,16 +620,19 @@ def process_justification_and_finalization(state: BeaconState) -> None: state.finalized_checkpoint = old_current_justified_checkpoint ``` -#### New `process_rewards_and_penalties` +#### Rewards and penalties -*Note*: The function `process_rewards_and_penalties` is modified to use participation flag deltas. +*Note*: The function `process_rewards_and_penalties` is modified to support the incentive reforms. ```python def process_rewards_and_penalties(state: BeaconState) -> None: # No rewards are applied at the end of `GENESIS_EPOCH` because rewards are for work done in the previous epoch if get_current_epoch(state) == GENESIS_EPOCH: return - flag_deltas = [get_flag_deltas(state, flag, numerator) for (flag, numerator) in get_flags_and_numerators()] + flag_deltas = [ + get_flag_deltas(state, flag_index, flag_numerator) + for (flag_index, flag_numerator) in get_flag_indices_and_numerators() + ] deltas = flag_deltas + [get_inactivity_penalty_deltas(state)] for (rewards, penalties) in deltas: for index in range(len(state.validators)): @@ -630,10 +640,9 @@ def process_rewards_and_penalties(state: BeaconState) -> None: decrease_balance(state, ValidatorIndex(index), penalties[index]) ``` -#### New `process_slashings` +#### Slashings -*Note*: The function `process_slashings` is modified -with the substitution of `PROPORTIONAL_SLASHING_MULTIPLIER` with `HF1_PROPORTIONAL_SLASHING_MULTIPLIER`. +*Note*: The function `process_slashings` is modified to use `HF1_PROPORTIONAL_SLASHING_MULTIPLIER`. ```python def process_slashings(state: BeaconState) -> None: @@ -648,26 +657,24 @@ def process_slashings(state: BeaconState) -> None: decrease_balance(state, ValidatorIndex(index), penalty) ``` +#### Participation flags updates + +*Note*: The function `process_participation_flag_updates` is new. + +```python +def process_participation_flag_updates(state: BeaconState) -> None: + state.previous_epoch_participation = state.current_epoch_participation + state.current_epoch_participation = [ParticipationFlags(0b0000_0000) for _ in range(len(state.validators))] +``` + #### Sync committee updates +*Note*: The function `process_sync_committee_updates` is new. + ```python def process_sync_committee_updates(state: BeaconState) -> None: - """ - Call to ``proces_sync_committee_updates`` added to ``process_epoch`` in HF1 - """ next_epoch = get_current_epoch(state) + Epoch(1) if next_epoch % EPOCHS_PER_SYNC_COMMITTEE_PERIOD == 0: state.current_sync_committee = state.next_sync_committee state.next_sync_committee = get_sync_committee(state, next_epoch + EPOCHS_PER_SYNC_COMMITTEE_PERIOD) ``` - -#### Participation flags updates - -```python -def process_participation_flag_updates(state: BeaconState) -> None: - """ - Call to ``process_participation_flag_updates`` added to ``process_epoch`` in HF1 - """ - state.previous_epoch_participation = state.current_epoch_participation - state.current_epoch_participation = [ValidatorFlag(0) for _ in range(len(state.validators))] -``` diff --git a/specs/lightclient/lightclient-fork.md b/specs/lightclient/lightclient-fork.md index aa0171b86..157e67dc9 100644 --- a/specs/lightclient/lightclient-fork.md +++ b/specs/lightclient/lightclient-fork.md @@ -66,9 +66,9 @@ def upgrade_to_lightclient_patch(pre: phase0.BeaconState) -> BeaconState: randao_mixes=pre.randao_mixes, # Slashings slashings=pre.slashings, - # Attestations - previous_epoch_participation=[ValidatorFlag(0) for _ in range(len(pre.validators))], - current_epoch_participation=[ValidatorFlag(0) for _ in range(len(pre.validators))], + # Participation + previous_epoch_participation=[ParticipationFlags(0) for _ in range(len(pre.validators))], + current_epoch_participation=[ParticipationFlags(0) for _ in range(len(pre.validators))], # Finality justification_bits=pre.justification_bits, previous_justified_checkpoint=pre.previous_justified_checkpoint, diff --git a/tests/core/pyspec/eth2spec/test/helpers/rewards.py b/tests/core/pyspec/eth2spec/test/helpers/rewards.py index 2499bcffe..19ed3f691 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/rewards.py +++ b/tests/core/pyspec/eth2spec/test/helpers/rewards.py @@ -41,13 +41,13 @@ def run_deltas(spec, state): if is_post_lightclient_patch(spec): def get_source_deltas(state): - return spec.get_flag_deltas(state, spec.TIMELY_SOURCE_FLAG, spec.TIMELY_SOURCE_NUMERATOR) + return spec.get_flag_deltas(state, spec.TIMELY_SOURCE_FLAG_INDEX, spec.TIMELY_SOURCE_FLAG_NUMERATOR) def get_head_deltas(state): - return spec.get_flag_deltas(state, spec.TIMELY_HEAD_FLAG, spec.TIMELY_HEAD_NUMERATOR) + return spec.get_flag_deltas(state, spec.TIMELY_HEAD_FLAG_INDEX, spec.TIMELY_HEAD_FLAG_NUMERATOR) def get_target_deltas(state): - return spec.get_flag_deltas(state, spec.TIMELY_TARGET_FLAG, spec.TIMELY_TARGET_NUMERATOR) + return spec.get_flag_deltas(state, spec.TIMELY_TARGET_FLAG_INDEX, spec.TIMELY_TARGET_FLAG_NUMERATOR) yield from run_attestation_component_deltas( spec, @@ -74,13 +74,13 @@ def run_deltas(spec, state): yield from run_get_inactivity_penalty_deltas(spec, state) -def deltas_name_to_flag(spec, deltas_name): +def deltas_name_to_flag_index(spec, deltas_name): if 'source' in deltas_name: - return spec.TIMELY_SOURCE_FLAG + return spec.TIMELY_SOURCE_FLAG_INDEX elif 'head' in deltas_name: - return spec.TIMELY_HEAD_FLAG + return spec.TIMELY_HEAD_FLAG_INDEX elif 'target' in deltas_name: - return spec.TIMELY_TARGET_FLAG + return spec.TIMELY_TARGET_FLAG_INDEX raise ValueError("Wrong deltas_name %s" % deltas_name) @@ -98,7 +98,7 @@ def run_attestation_component_deltas(spec, state, component_delta_fn, matching_a matching_indices = spec.get_unslashed_attesting_indices(state, matching_attestations) else: matching_indices = spec.get_unslashed_participating_indices( - state, deltas_name_to_flag(spec, deltas_name), spec.get_previous_epoch(state) + state, deltas_name_to_flag_index(spec, deltas_name), spec.get_previous_epoch(state) ) eligible_indices = spec.get_eligible_validator_indices(state) @@ -187,9 +187,9 @@ def run_get_inactivity_penalty_deltas(spec, state): matching_attesting_indices = spec.get_unslashed_attesting_indices(state, matching_attestations) else: matching_attesting_indices = spec.get_unslashed_participating_indices( - state, spec.TIMELY_TARGET_FLAG, spec.get_previous_epoch(state) + state, spec.TIMELY_TARGET_FLAG_INDEX, spec.get_previous_epoch(state) ) - reward_numerator_sum = sum(numerator for (_, numerator) in spec.get_flags_and_numerators()) + reward_numerator_sum = sum(numerator for (_, numerator) in spec.get_flag_indices_and_numerators()) eligible_indices = spec.get_eligible_validator_indices(state) for index in range(len(state.validators)): @@ -205,7 +205,7 @@ def run_get_inactivity_penalty_deltas(spec, state): base_reward = spec.get_base_reward(state, index) base_penalty = cancel_base_rewards_per_epoch * base_reward - spec.get_proposer_reward(state, index) else: - base_penalty = spec.get_base_reward(state, index) * reward_numerator_sum // spec.REWARD_DENOMINATOR + base_penalty = spec.get_base_reward(state, index) * reward_numerator_sum // spec.FLAG_DENOMINATOR if not has_enough_for_reward(spec, state, index): assert penalties[index] == 0 @@ -314,7 +314,7 @@ def run_test_full_but_partial_participation(spec, state, rng=Random(5522)): else: for index in range(len(state.validators)): if rng.choice([True, False]): - state.previous_epoch_participation[index] = spec.ValidatorFlag(0) + state.previous_epoch_participation[index] = spec.ParticipationFlags(0b0000_0000) yield from run_deltas(spec, state) @@ -328,7 +328,7 @@ def run_test_partial(spec, state, fraction_filled): state.previous_epoch_attestations = state.previous_epoch_attestations[:num_attestations] else: for index in range(int(len(state.validators) * fraction_filled)): - state.previous_epoch_participation[index] = spec.ValidatorFlag(0) + state.previous_epoch_participation[index] = spec.ParticipationFlags(0b0000_0000) yield from run_deltas(spec, state) @@ -394,7 +394,7 @@ def run_test_some_very_low_effective_balances_that_did_not_attest(spec, state): else: index = 0 state.validators[index].effective_balance = 1 - state.previous_epoch_participation[index] = spec.ValidatorFlag(0) + state.previous_epoch_participation[index] = spec.ParticipationFlags(0b0000_0000) yield from run_deltas(spec, state) @@ -521,23 +521,24 @@ def run_test_full_random(spec, state, rng=Random(8020)): is_timely_correct_head = rng.randint(0, 2) != 0 flags = state.previous_epoch_participation[index] - def set_flag(f, v): + def set_flag(index, value): nonlocal flags - if v: - flags |= f + flag = spec.ParticipationFlags(2**index) + if value: + flags |= flag else: - flags &= 0xff ^ f + flags &= 0xff ^ flag - set_flag(spec.TIMELY_HEAD_FLAG, is_timely_correct_head) + set_flag(spec.TIMELY_HEAD_FLAG_INDEX, is_timely_correct_head) if is_timely_correct_head: # If timely head, then must be timely target - set_flag(spec.TIMELY_TARGET_FLAG, True) + set_flag(spec.TIMELY_TARGET_FLAG_INDEX, True) # If timely head, then must be timely source - set_flag(spec.TIMELY_SOURCE_FLAG, True) + set_flag(spec.TIMELY_SOURCE_FLAG_INDEX, True) else: # ~50% of remaining have bad target or not timely enough - set_flag(spec.TIMELY_TARGET_FLAG, rng.choice([True, False])) + set_flag(spec.TIMELY_TARGET_FLAG_INDEX, rng.choice([True, False])) # ~50% of remaining have bad source or not timely enough - set_flag(spec.TIMELY_SOURCE_FLAG, rng.choice([True, False])) + set_flag(spec.TIMELY_SOURCE_FLAG_INDEX, rng.choice([True, False])) state.previous_epoch_participation[index] = flags yield from run_deltas(spec, state) diff --git a/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_justification_and_finalization.py b/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_justification_and_finalization.py index 89783f987..274d67134 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_justification_and_finalization.py +++ b/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_justification_and_finalization.py @@ -78,10 +78,10 @@ def add_mock_attestations(spec, state, epoch, source, target, sufficient_support else: for i, index in enumerate(committee): if aggregation_bits[i]: - epoch_participation[index] |= spec.TIMELY_HEAD_FLAG - epoch_participation[index] |= spec.TIMELY_SOURCE_FLAG + epoch_participation[index] |= spec.ParticipationFlags(2**spec.TIMELY_HEAD_FLAG_INDEX) + epoch_participation[index] |= spec.ParticipationFlags(2**spec.TIMELY_SOURCE_FLAG_INDEX) if not messed_up_target: - epoch_participation[index] |= spec.TIMELY_TARGET_FLAG + epoch_participation[index] |= spec.ParticipationFlags(2**spec.TIMELY_TARGET_FLAG_INDEX) def get_checkpoints(spec, epoch): diff --git a/tests/core/pyspec/eth2spec/test/phase0/sanity/test_blocks.py b/tests/core/pyspec/eth2spec/test/phase0/sanity/test_blocks.py index 1834b290f..98ffbd590 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/sanity/test_blocks.py +++ b/tests/core/pyspec/eth2spec/test/phase0/sanity/test_blocks.py @@ -806,7 +806,7 @@ def test_attestation(spec, state): assert spec.hash_tree_root(state.previous_epoch_attestations) == pre_current_attestations_root else: for index in range(len(state.validators)): - assert state.current_epoch_participation[index] == 0 + assert state.current_epoch_participation[index] == spec.ParticipationFlags(0b0000_0000) assert spec.hash_tree_root(state.previous_epoch_participation) == pre_current_epoch_participation_root From 8ea5e37608bd6734e2764665d35a0433579b5ad0 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Tue, 2 Mar 2021 07:56:30 -0600 Subject: [PATCH 37/56] add another 'modified' tag Co-authored-by: Hsiao-Wei Wang --- specs/lightclient/beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/lightclient/beacon-chain.md b/specs/lightclient/beacon-chain.md index de0fdf8c5..bc070908a 100644 --- a/specs/lightclient/beacon-chain.md +++ b/specs/lightclient/beacon-chain.md @@ -564,7 +564,7 @@ def process_epoch(state: BeaconState) -> None: process_justification_and_finalization(state) # [Modified in HF1] process_rewards_and_penalties(state) # [Modified in HF1] process_registry_updates(state) - process_slashings(state) + process_slashings(state) # [Modified in HF1] process_eth1_data_reset(state) process_effective_balance_updates(state) process_slashings_reset(state) From e1023f55d1ab36c0c148da991df62f043b3c6188 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Fri, 5 Mar 2021 18:05:15 -0800 Subject: [PATCH 38/56] Fix a small typo --- specs/phase0/p2p-interface.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/phase0/p2p-interface.md b/specs/phase0/p2p-interface.md index 249d08799..02a578fb8 100644 --- a/specs/phase0/p2p-interface.md +++ b/specs/phase0/p2p-interface.md @@ -292,7 +292,7 @@ If one or more validations fail while processing the items in order, return eith There are two primary global topics used to propagate beacon blocks (`beacon_block`) and aggregate attestations (`beacon_aggregate_and_proof`) to all nodes on the network. -There are three additional global topics are used to propagate lower frequency validator messages +There are three additional global topics that are used to propagate lower frequency validator messages (`voluntary_exit`, `proposer_slashing`, and `attester_slashing`). ##### `beacon_block` From 6bd1efc73bf45ae5658e115a8b2956144d4f4559 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Mon, 8 Mar 2021 17:16:13 -0700 Subject: [PATCH 39/56] rename fork files --- setup.py | 4 ++-- specs/lightclient/{lightclient-fork.md => fork.md} | 0 specs/phase1/{phase1-fork.md => fork.md} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename specs/lightclient/{lightclient-fork.md => fork.md} (100%) rename specs/phase1/{phase1-fork.md => fork.md} (100%) diff --git a/setup.py b/setup.py index 6cfa0910a..ca85a83ac 100644 --- a/setup.py +++ b/setup.py @@ -449,7 +449,7 @@ class PySpecCommand(Command): specs/phase1/beacon-chain.md specs/phase1/shard-transition.md specs/phase1/fork-choice.md - specs/phase1/phase1-fork.md + specs/phase1/fork.md specs/phase1/shard-fork-choice.md specs/phase1/validator.md """ @@ -460,7 +460,7 @@ class PySpecCommand(Command): specs/phase0/validator.md specs/phase0/weak-subjectivity.md specs/lightclient/beacon-chain.md - specs/lightclient/lightclient-fork.md + specs/lightclient/fork.md """ # TODO: add specs/lightclient/sync-protocol.md back when the GeneralizedIndex helpers are included. else: diff --git a/specs/lightclient/lightclient-fork.md b/specs/lightclient/fork.md similarity index 100% rename from specs/lightclient/lightclient-fork.md rename to specs/lightclient/fork.md diff --git a/specs/phase1/phase1-fork.md b/specs/phase1/fork.md similarity index 100% rename from specs/phase1/phase1-fork.md rename to specs/phase1/fork.md From d6961f636de17b31ecb3350b0a5710a1d102d669 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Mon, 8 Mar 2021 17:16:29 -0700 Subject: [PATCH 40/56] add base hf1 fork function tests --- tests/core/pyspec/eth2spec/test/context.py | 10 +- .../test/lightclient_patch/fork/test_fork.py | 104 ++++++++++++++++++ 2 files changed, 108 insertions(+), 6 deletions(-) create mode 100644 tests/core/pyspec/eth2spec/test/lightclient_patch/fork/test_fork.py diff --git a/tests/core/pyspec/eth2spec/test/context.py b/tests/core/pyspec/eth2spec/test/context.py index 5c2a3bf4d..3f247b400 100644 --- a/tests/core/pyspec/eth2spec/test/context.py +++ b/tests/core/pyspec/eth2spec/test/context.py @@ -346,13 +346,11 @@ def with_phases(phases, other_phases=None): # A new state-creation helper for phase 1 may be in place, and then phase1+ tests can run without phase0 available_phases.add(PHASE0) + # Populate all phases for multi-phase tests phase_dir = {} - if PHASE0 in available_phases: - phase_dir[PHASE0] = spec_phase0 - if PHASE1 in available_phases: - phase_dir[PHASE1] = spec_phase1 - if LIGHTCLIENT_PATCH in available_phases: - phase_dir[LIGHTCLIENT_PATCH] = spec_lightclient_patch + phase_dir[PHASE0] = spec_phase0 + phase_dir[PHASE1] = spec_phase1 + phase_dir[LIGHTCLIENT_PATCH] = spec_lightclient_patch # return is ignored whenever multiple phases are ran. If if PHASE0 in run_phases: diff --git a/tests/core/pyspec/eth2spec/test/lightclient_patch/fork/test_fork.py b/tests/core/pyspec/eth2spec/test/lightclient_patch/fork/test_fork.py new file mode 100644 index 000000000..08c6e6d29 --- /dev/null +++ b/tests/core/pyspec/eth2spec/test/lightclient_patch/fork/test_fork.py @@ -0,0 +1,104 @@ +from operator import attrgetter + +from eth2spec.test.context import ( + PHASE0, LIGHTCLIENT_PATCH, + spec_state_test, with_phases, + with_custom_state, + spec_test, with_state, + low_balances, misc_balances, large_validator_set, +) +from eth2spec.test.helpers.state import ( + next_slots, + next_epoch, + next_epoch_via_block, + transition_to_slot_via_block, +) + + +def run_fork_test(spec, pre_state): + yield 'pre', pre_state + + post_state = spec.upgrade_to_lightclient_patch(pre_state) + + # Stable fields + stable_fields = [ + 'genesis_time', 'genesis_validators_root', 'slot', + # History + 'latest_block_header', 'block_roots', 'state_roots', 'historical_roots', + # Eth1 + 'eth1_data', 'eth1_data_votes', 'eth1_deposit_index', + # Registry + 'validators', 'balances', + # Randomness + 'randao_mixes', + # Slashings + 'slashings', + # Finality + 'justification_bits', 'previous_justified_checkpoint', 'current_justified_checkpoint', 'finalized_checkpoint', + ] + for field in stable_fields: + assert getattr(pre_state, field) == getattr(post_state, field) + + # Modified fields + modified_fields = ['fork'] + for field in modified_fields: + assert getattr(pre_state, field) != getattr(post_state, field) + + assert pre_state.fork.current_version == post_state.fork.previous_version + assert post_state.fork.current_version == spec.LIGHTCLIENT_PATCH_FORK_VERSION + assert post_state.fork.epoch == spec.get_current_epoch(post_state) + + yield 'post', post_state + + +@with_phases(([PHASE0])) +@with_state +@spec_test +def test_fork_base_state(spec, phases, state): + yield from run_fork_test(phases[LIGHTCLIENT_PATCH], state) + + +@with_phases(([PHASE0])) +@with_state +@spec_test +def test_fork_next_epoch(spec, phases, state): + next_epoch(spec, state) + yield from run_fork_test(phases[LIGHTCLIENT_PATCH], state) + + +@with_phases(([PHASE0])) +@with_state +@spec_test +def test_fork_next_epoch_with_block(spec, phases, state): + next_epoch_via_block(spec, state) + yield from run_fork_test(phases[LIGHTCLIENT_PATCH], state) + + +@with_phases(([PHASE0])) +@with_state +@spec_test +def test_fork_many_next_epoch(spec, phases, state): + for _ in range(3): + next_epoch(spec, state) + yield from run_fork_test(phases[LIGHTCLIENT_PATCH], state) + + +@with_phases(([PHASE0])) +@with_custom_state(balances_fn=low_balances, threshold_fn=lambda spec: spec.EJECTION_BALANCE) +@spec_test +def test_fork_random_low_balances(spec, phases, state): + yield from run_fork_test(phases[LIGHTCLIENT_PATCH], state) + + +@with_phases(([PHASE0])) +@with_custom_state(balances_fn=misc_balances, threshold_fn=lambda spec: spec.EJECTION_BALANCE) +@spec_test +def test_fork_random_misc_balances(spec, phases, state): + yield from run_fork_test(phases[LIGHTCLIENT_PATCH], state) + + +@with_phases(([PHASE0])) +@with_custom_state(balances_fn=large_validator_set, threshold_fn=lambda spec: spec.EJECTION_BALANCE) +@spec_test +def test_fork_random_large_validator_set(spec, phases, state): + yield from run_fork_test(phases[LIGHTCLIENT_PATCH], state) From 6c406753f150563cac1253cfef8d99d9111bd906 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Mon, 8 Mar 2021 19:11:31 -0700 Subject: [PATCH 41/56] working through test gens --- tests/core/pyspec/eth2spec/test/context.py | 18 +++++-- .../test/lightclient_patch/fork/__init__.py | 0 .../test/lightclient_patch/fork/test_fork.py | 44 +++++++++++------ tests/formats/forks/README.md | 47 +++++++++++++++++++ tests/generators/forks/main.py | 40 ++++++++++++++++ tests/generators/forks/requirements.txt | 2 + 6 files changed, 133 insertions(+), 18 deletions(-) create mode 100644 tests/core/pyspec/eth2spec/test/lightclient_patch/fork/__init__.py create mode 100644 tests/formats/forks/README.md create mode 100644 tests/generators/forks/main.py create mode 100644 tests/generators/forks/requirements.txt diff --git a/tests/core/pyspec/eth2spec/test/context.py b/tests/core/pyspec/eth2spec/test/context.py index 3f247b400..9c45049a2 100644 --- a/tests/core/pyspec/eth2spec/test/context.py +++ b/tests/core/pyspec/eth2spec/test/context.py @@ -70,7 +70,7 @@ class SpecForks(TypedDict, total=False): def _prepare_state(balances_fn: Callable[[Any], Sequence[int]], threshold_fn: Callable[[Any], int], - spec: Spec, phases: SpecForks): + spec: Spec, phases: SpecForks, is_fork_test: bool): p0 = phases[PHASE0] balances = balances_fn(p0) @@ -82,7 +82,7 @@ def _prepare_state(balances_fn: Callable[[Any], Sequence[int]], threshold_fn: Ca # TODO: instead of upgrading a test phase0 genesis state we can also write a phase1 state helper. # Decide based on performance/consistency results later. state = phases[PHASE1].upgrade_to_phase1(state) - elif spec.fork == LIGHTCLIENT_PATCH: # not generalizing this just yet, unclear final spec fork/patch order. + elif spec.fork == LIGHTCLIENT_PATCH and not fork_test: # do not upgrade if spec ttttest state = phases[LIGHTCLIENT_PATCH].upgrade_to_lightclient_patch(state) return state @@ -98,10 +98,11 @@ def with_custom_state(balances_fn: Callable[[Any], Sequence[int]], def entry(*args, spec: Spec, phases: SpecForks, **kw): # make a key for the state # genesis fork version separates configs during test-generation runtime. - key = (spec.fork, spec.GENESIS_FORK_VERSION, spec.__file__, balances_fn, threshold_fn) + is_fork_test = kw.pop('fork_test') if 'fork_test' in kw else False + key = (spec.fork, spec.GENESIS_FORK_VERSION, spec.__file__, balances_fn, threshold_fn, is_fork_test) global _custom_state_cache_dict if key not in _custom_state_cache_dict: - state = _prepare_state(balances_fn, threshold_fn, spec, phases) + state = _prepare_state(balances_fn, threshold_fn, spec, phases, is_fork_test) _custom_state_cache_dict[key] = state.get_backing() # Take an entry out of the LRU. @@ -287,6 +288,15 @@ def bls_switch(fn): return entry +def fork_test(fn): + """ + """ + def entry(*args, **kw): + # override fork test setting + kw['fork_test'] = True + return entry + + def disable_process_reveal_deadlines(fn): """ Decorator to make a function execute with `process_reveal_deadlines` OFF. diff --git a/tests/core/pyspec/eth2spec/test/lightclient_patch/fork/__init__.py b/tests/core/pyspec/eth2spec/test/lightclient_patch/fork/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/core/pyspec/eth2spec/test/lightclient_patch/fork/test_fork.py b/tests/core/pyspec/eth2spec/test/lightclient_patch/fork/test_fork.py index 08c6e6d29..527ad746c 100644 --- a/tests/core/pyspec/eth2spec/test/lightclient_patch/fork/test_fork.py +++ b/tests/core/pyspec/eth2spec/test/lightclient_patch/fork/test_fork.py @@ -1,20 +1,22 @@ -from operator import attrgetter - from eth2spec.test.context import ( - PHASE0, LIGHTCLIENT_PATCH, - spec_state_test, with_phases, - with_custom_state, + LIGHTCLIENT_PATCH, + with_phases, + with_custom_state, fork_test, spec_test, with_state, low_balances, misc_balances, large_validator_set, ) +from eth2spec.test.utils import with_meta_tags from eth2spec.test.helpers.state import ( - next_slots, next_epoch, next_epoch_via_block, - transition_to_slot_via_block, ) +HF1_FORK_TEST_META_TAGS = { + 'fork': 'altair', +} + + def run_fork_test(spec, pre_state): yield 'pre', pre_state @@ -51,54 +53,68 @@ def run_fork_test(spec, pre_state): yield 'post', post_state -@with_phases(([PHASE0])) +@with_phases(([LIGHTCLIENT_PATCH])) @with_state @spec_test +@fork_test +@with_meta_tags(HF1_FORK_TEST_META_TAGS) def test_fork_base_state(spec, phases, state): yield from run_fork_test(phases[LIGHTCLIENT_PATCH], state) -@with_phases(([PHASE0])) +@with_phases(([LIGHTCLIENT_PATCH])) @with_state @spec_test +@fork_test +@with_meta_tags(HF1_FORK_TEST_META_TAGS) def test_fork_next_epoch(spec, phases, state): next_epoch(spec, state) yield from run_fork_test(phases[LIGHTCLIENT_PATCH], state) -@with_phases(([PHASE0])) +@with_phases(([LIGHTCLIENT_PATCH])) @with_state @spec_test +@fork_test +@with_meta_tags(HF1_FORK_TEST_META_TAGS) def test_fork_next_epoch_with_block(spec, phases, state): next_epoch_via_block(spec, state) yield from run_fork_test(phases[LIGHTCLIENT_PATCH], state) -@with_phases(([PHASE0])) +@with_phases(([LIGHTCLIENT_PATCH])) @with_state @spec_test +@fork_test +@with_meta_tags(HF1_FORK_TEST_META_TAGS) def test_fork_many_next_epoch(spec, phases, state): for _ in range(3): next_epoch(spec, state) yield from run_fork_test(phases[LIGHTCLIENT_PATCH], state) -@with_phases(([PHASE0])) +@with_phases(([LIGHTCLIENT_PATCH])) @with_custom_state(balances_fn=low_balances, threshold_fn=lambda spec: spec.EJECTION_BALANCE) @spec_test +@fork_test +@with_meta_tags(HF1_FORK_TEST_META_TAGS) def test_fork_random_low_balances(spec, phases, state): yield from run_fork_test(phases[LIGHTCLIENT_PATCH], state) -@with_phases(([PHASE0])) +@with_phases(([LIGHTCLIENT_PATCH])) @with_custom_state(balances_fn=misc_balances, threshold_fn=lambda spec: spec.EJECTION_BALANCE) @spec_test +@fork_test +@with_meta_tags(HF1_FORK_TEST_META_TAGS) def test_fork_random_misc_balances(spec, phases, state): yield from run_fork_test(phases[LIGHTCLIENT_PATCH], state) -@with_phases(([PHASE0])) +@with_phases(([LIGHTCLIENT_PATCH])) @with_custom_state(balances_fn=large_validator_set, threshold_fn=lambda spec: spec.EJECTION_BALANCE) @spec_test +@fork_test +@with_meta_tags(HF1_FORK_TEST_META_TAGS) def test_fork_random_large_validator_set(spec, phases, state): yield from run_fork_test(phases[LIGHTCLIENT_PATCH], state) diff --git a/tests/formats/forks/README.md b/tests/formats/forks/README.md new file mode 100644 index 000000000..1a7ee64ad --- /dev/null +++ b/tests/formats/forks/README.md @@ -0,0 +1,47 @@ +# Forks + +The aim of the fork tests is to ensure that a pre-fork state can be transformed + into a valid post-fork state, utilizing the `upgrade` function found in the relevant `fork.md` spec. + +There is only one handler: `core`. Each fork (after genesis) is handled with the same format, + and the particular fork boundary being tested is noted in `meta.yaml`. + +## Test case format + +### `meta.yaml` + +A yaml file to signify which fork boundary is being tested. + +```yaml +fork: str -- Fork being transitioned to +``` + +#### Fork strings + +Key of valid `fork` strings that might be found in `meta.yaml` + +| String ID | Pre-fork | Post-fork | Function | +| - | - | - | - | +| `altair` | Phase 0 | Altair | `upgrade_to_lightclient_patch` | + +### `pre.yaml` + +A YAML-encoded `BeaconState`, the state before running the fork transition. + +Also available as `pre.ssz`. + +### `post.yaml` + +A YAML-encoded `BeaconState`, the state after applying the fork transition. + +Also available as `post.ssz`. + +*Note*: This type is the `BeaconState` after the fork and is *not* the same type as `pre`. + +## Processing + +To process this test, pass `pre` into the upgrade function defined by the `fork` in `meta.yaml`. + +## Condition + +The resulting state should match the expected `post`. diff --git a/tests/generators/forks/main.py b/tests/generators/forks/main.py new file mode 100644 index 000000000..a32ece712 --- /dev/null +++ b/tests/generators/forks/main.py @@ -0,0 +1,40 @@ +from importlib import reload +from typing import Iterable + +from eth2spec.test.context import LIGHTCLIENT_PATCH +from eth2spec.config import config_util +from eth2spec.test.lightclient_patch.fork import test_fork as test_altair_forks +from eth2spec.phase0 import spec as spec_phase0 + +from eth2spec.gen_helpers.gen_base import gen_runner, gen_typing +from eth2spec.gen_helpers.gen_from_tests.gen import generate_from_tests + + +pre_specs = { + LIGHTCLIENT_PATCH: spec_phase0, +} + + +def create_provider(fork_name: str, tests_src, config_name: str) -> gen_typing.TestProvider: + + def prepare_fn(configs_path: str) -> str: + config_util.prepare_config(configs_path, config_name) + reload(pre_specs[fork_name]) + return config_name + + def cases_fn() -> Iterable[gen_typing.TestCase]: + return generate_from_tests( + runner_name='forks', + handler_name='core', + src=tests_src, + fork_name=fork_name, + ) + + return gen_typing.TestProvider(prepare=prepare_fn, make_cases=cases_fn) + + +if __name__ == "__main__": + gen_runner.run_generator("forks", [ + create_provider(LIGHTCLIENT_PATCH, test_altair_forks, 'minimal'), + create_provider(LIGHTCLIENT_PATCH, test_altair_forks, 'minimal'), + ]) diff --git a/tests/generators/forks/requirements.txt b/tests/generators/forks/requirements.txt new file mode 100644 index 000000000..816df6e63 --- /dev/null +++ b/tests/generators/forks/requirements.txt @@ -0,0 +1,2 @@ +pytest>=4.4 +../../../ \ No newline at end of file From 50fb3da0729429179e6a24abaf1150b6c023a94b Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Tue, 9 Mar 2021 20:31:06 +0800 Subject: [PATCH 42/56] Make test_fork.py truly pass --- tests/core/pyspec/eth2spec/test/context.py | 3 +- .../test/lightclient_patch/fork/test_fork.py | 45 ++++++++++--------- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/context.py b/tests/core/pyspec/eth2spec/test/context.py index 9c45049a2..f3d8e2a8f 100644 --- a/tests/core/pyspec/eth2spec/test/context.py +++ b/tests/core/pyspec/eth2spec/test/context.py @@ -82,7 +82,7 @@ def _prepare_state(balances_fn: Callable[[Any], Sequence[int]], threshold_fn: Ca # TODO: instead of upgrading a test phase0 genesis state we can also write a phase1 state helper. # Decide based on performance/consistency results later. state = phases[PHASE1].upgrade_to_phase1(state) - elif spec.fork == LIGHTCLIENT_PATCH and not fork_test: # do not upgrade if spec ttttest + elif spec.fork == LIGHTCLIENT_PATCH and not is_fork_test: # do not upgrade if spec ttttest state = phases[LIGHTCLIENT_PATCH].upgrade_to_lightclient_patch(state) return state @@ -294,6 +294,7 @@ def fork_test(fn): def entry(*args, **kw): # override fork test setting kw['fork_test'] = True + return fn(*args, **kw) return entry diff --git a/tests/core/pyspec/eth2spec/test/lightclient_patch/fork/test_fork.py b/tests/core/pyspec/eth2spec/test/lightclient_patch/fork/test_fork.py index 527ad746c..88ff68a06 100644 --- a/tests/core/pyspec/eth2spec/test/lightclient_patch/fork/test_fork.py +++ b/tests/core/pyspec/eth2spec/test/lightclient_patch/fork/test_fork.py @@ -1,5 +1,5 @@ from eth2spec.test.context import ( - LIGHTCLIENT_PATCH, + PHASE0, LIGHTCLIENT_PATCH, with_phases, with_custom_state, fork_test, spec_test, with_state, @@ -53,39 +53,39 @@ def run_fork_test(spec, pre_state): yield 'post', post_state -@with_phases(([LIGHTCLIENT_PATCH])) -@with_state -@spec_test @fork_test +@with_phases(([PHASE0])) +@spec_test +@with_state @with_meta_tags(HF1_FORK_TEST_META_TAGS) def test_fork_base_state(spec, phases, state): yield from run_fork_test(phases[LIGHTCLIENT_PATCH], state) -@with_phases(([LIGHTCLIENT_PATCH])) -@with_state -@spec_test @fork_test +@with_phases(([PHASE0])) +@spec_test +@with_state @with_meta_tags(HF1_FORK_TEST_META_TAGS) def test_fork_next_epoch(spec, phases, state): next_epoch(spec, state) yield from run_fork_test(phases[LIGHTCLIENT_PATCH], state) -@with_phases(([LIGHTCLIENT_PATCH])) -@with_state -@spec_test @fork_test +@with_phases(([PHASE0])) +@spec_test +@with_state @with_meta_tags(HF1_FORK_TEST_META_TAGS) def test_fork_next_epoch_with_block(spec, phases, state): next_epoch_via_block(spec, state) yield from run_fork_test(phases[LIGHTCLIENT_PATCH], state) -@with_phases(([LIGHTCLIENT_PATCH])) -@with_state -@spec_test @fork_test +@with_phases(([PHASE0])) +@spec_test +@with_state @with_meta_tags(HF1_FORK_TEST_META_TAGS) def test_fork_many_next_epoch(spec, phases, state): for _ in range(3): @@ -93,28 +93,29 @@ def test_fork_many_next_epoch(spec, phases, state): yield from run_fork_test(phases[LIGHTCLIENT_PATCH], state) -@with_phases(([LIGHTCLIENT_PATCH])) -@with_custom_state(balances_fn=low_balances, threshold_fn=lambda spec: spec.EJECTION_BALANCE) -@spec_test @fork_test +@with_phases(([PHASE0])) +@spec_test +@with_custom_state(balances_fn=low_balances, threshold_fn=lambda spec: spec.EJECTION_BALANCE) +@with_state @with_meta_tags(HF1_FORK_TEST_META_TAGS) def test_fork_random_low_balances(spec, phases, state): yield from run_fork_test(phases[LIGHTCLIENT_PATCH], state) -@with_phases(([LIGHTCLIENT_PATCH])) -@with_custom_state(balances_fn=misc_balances, threshold_fn=lambda spec: spec.EJECTION_BALANCE) -@spec_test @fork_test +@with_phases(([PHASE0])) +@with_custom_state(balances_fn=misc_balances, threshold_fn=lambda spec: spec.EJECTION_BALANCE) +@with_state @with_meta_tags(HF1_FORK_TEST_META_TAGS) def test_fork_random_misc_balances(spec, phases, state): yield from run_fork_test(phases[LIGHTCLIENT_PATCH], state) -@with_phases(([LIGHTCLIENT_PATCH])) -@with_custom_state(balances_fn=large_validator_set, threshold_fn=lambda spec: spec.EJECTION_BALANCE) -@spec_test @fork_test +@with_phases(([PHASE0])) +@with_custom_state(balances_fn=large_validator_set, threshold_fn=lambda spec: spec.EJECTION_BALANCE) +@with_state @with_meta_tags(HF1_FORK_TEST_META_TAGS) def test_fork_random_large_validator_set(spec, phases, state): yield from run_fork_test(phases[LIGHTCLIENT_PATCH], state) From f97ea9e172e88a7527e7c7fa97e104a90df99a69 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Tue, 9 Mar 2021 20:55:39 +0800 Subject: [PATCH 43/56] Generate basic tests. Still having problem with generating `with_custom_state` tests --- .../gen_helpers/gen_from_tests/gen.py | 11 +++++++--- tests/generators/forks/main.py | 21 +++++++------------ 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/tests/core/pyspec/eth2spec/gen_helpers/gen_from_tests/gen.py b/tests/core/pyspec/eth2spec/gen_helpers/gen_from_tests/gen.py index 67d29b194..f04bf46a7 100644 --- a/tests/core/pyspec/eth2spec/gen_helpers/gen_from_tests/gen.py +++ b/tests/core/pyspec/eth2spec/gen_helpers/gen_from_tests/gen.py @@ -1,6 +1,6 @@ from importlib import reload, import_module from inspect import getmembers, isfunction -from typing import Any, Callable, Dict, Iterable +from typing import Any, Callable, Dict, Iterable, Optional from eth2spec.config import config_util from eth2spec.utils import bls @@ -11,7 +11,7 @@ from eth2spec.gen_helpers.gen_base.gen_typing import TestCase, TestProvider def generate_from_tests(runner_name: str, handler_name: str, src: Any, - fork_name: SpecForkName, bls_active: bool = True) -> Iterable[TestCase]: + fork_name: SpecForkName, bls_active: bool = True, phase: Optional[str]=None) -> Iterable[TestCase]: """ Generate a list of test cases by running tests from the given src in generator-mode. :param runner_name: to categorize the test in general as. @@ -20,12 +20,17 @@ def generate_from_tests(runner_name: str, handler_name: str, src: Any, :param fork_name: to run tests against particular phase and/or fork. (if multiple forks are applicable, indicate the last fork) :param bls_active: optional, to override BLS switch preference. Defaults to True. + :param phase: optional, specific phase name :return: an iterable of test cases. """ fn_names = [ name for (name, _) in getmembers(src, isfunction) if name.startswith('test_') ] + + if phase is None: + phase = fork_name + print("generating test vectors from tests source: %s" % src.__name__) for name in fn_names: tfn = getattr(src, name) @@ -42,7 +47,7 @@ def generate_from_tests(runner_name: str, handler_name: str, src: Any, suite_name='pyspec_tests', case_name=case_name, # TODO: with_all_phases and other per-phase tooling, should be replaced with per-fork equivalent. - case_fn=lambda: tfn(generator_mode=True, phase=fork_name, bls_active=bls_active) + case_fn=lambda: tfn(generator_mode=True, phase=phase, bls_active=bls_active) ) diff --git a/tests/generators/forks/main.py b/tests/generators/forks/main.py index a32ece712..d39af802a 100644 --- a/tests/generators/forks/main.py +++ b/tests/generators/forks/main.py @@ -1,7 +1,7 @@ from importlib import reload from typing import Iterable -from eth2spec.test.context import LIGHTCLIENT_PATCH +from eth2spec.test.context import PHASE0, LIGHTCLIENT_PATCH, MINIMAL, MAINNET from eth2spec.config import config_util from eth2spec.test.lightclient_patch.fork import test_fork as test_altair_forks from eth2spec.phase0 import spec as spec_phase0 @@ -10,24 +10,20 @@ from eth2spec.gen_helpers.gen_base import gen_runner, gen_typing from eth2spec.gen_helpers.gen_from_tests.gen import generate_from_tests -pre_specs = { - LIGHTCLIENT_PATCH: spec_phase0, -} - - -def create_provider(fork_name: str, tests_src, config_name: str) -> gen_typing.TestProvider: +def create_provider(tests_src, config_name: str) -> gen_typing.TestProvider: def prepare_fn(configs_path: str) -> str: config_util.prepare_config(configs_path, config_name) - reload(pre_specs[fork_name]) + reload(spec_phase0) return config_name def cases_fn() -> Iterable[gen_typing.TestCase]: return generate_from_tests( - runner_name='forks', - handler_name='core', + runner_name='fork', + handler_name='fork', src=tests_src, - fork_name=fork_name, + fork_name=LIGHTCLIENT_PATCH, + phase=PHASE0, ) return gen_typing.TestProvider(prepare=prepare_fn, make_cases=cases_fn) @@ -35,6 +31,5 @@ def create_provider(fork_name: str, tests_src, config_name: str) -> gen_typing.T if __name__ == "__main__": gen_runner.run_generator("forks", [ - create_provider(LIGHTCLIENT_PATCH, test_altair_forks, 'minimal'), - create_provider(LIGHTCLIENT_PATCH, test_altair_forks, 'minimal'), + create_provider(test_altair_forks, MINIMAL), ]) From 7a10c7108ad5b21efac726afe2a5799383457a3f Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Tue, 9 Mar 2021 21:17:02 +0800 Subject: [PATCH 44/56] Fix decorator calls --- .../eth2spec/test/lightclient_patch/fork/test_fork.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/lightclient_patch/fork/test_fork.py b/tests/core/pyspec/eth2spec/test/lightclient_patch/fork/test_fork.py index 88ff68a06..c5b9b8981 100644 --- a/tests/core/pyspec/eth2spec/test/lightclient_patch/fork/test_fork.py +++ b/tests/core/pyspec/eth2spec/test/lightclient_patch/fork/test_fork.py @@ -95,9 +95,8 @@ def test_fork_many_next_epoch(spec, phases, state): @fork_test @with_phases(([PHASE0])) -@spec_test @with_custom_state(balances_fn=low_balances, threshold_fn=lambda spec: spec.EJECTION_BALANCE) -@with_state +@spec_test @with_meta_tags(HF1_FORK_TEST_META_TAGS) def test_fork_random_low_balances(spec, phases, state): yield from run_fork_test(phases[LIGHTCLIENT_PATCH], state) @@ -106,7 +105,7 @@ def test_fork_random_low_balances(spec, phases, state): @fork_test @with_phases(([PHASE0])) @with_custom_state(balances_fn=misc_balances, threshold_fn=lambda spec: spec.EJECTION_BALANCE) -@with_state +@spec_test @with_meta_tags(HF1_FORK_TEST_META_TAGS) def test_fork_random_misc_balances(spec, phases, state): yield from run_fork_test(phases[LIGHTCLIENT_PATCH], state) @@ -115,7 +114,7 @@ def test_fork_random_misc_balances(spec, phases, state): @fork_test @with_phases(([PHASE0])) @with_custom_state(balances_fn=large_validator_set, threshold_fn=lambda spec: spec.EJECTION_BALANCE) -@with_state +@spec_test @with_meta_tags(HF1_FORK_TEST_META_TAGS) def test_fork_random_large_validator_set(spec, phases, state): yield from run_fork_test(phases[LIGHTCLIENT_PATCH], state) From f025ec40c584e45517aeed1f93ce4fa4db1f0f3d Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Tue, 9 Mar 2021 21:21:32 +0800 Subject: [PATCH 45/56] Fix linter error --- tests/core/pyspec/eth2spec/gen_helpers/gen_from_tests/gen.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/core/pyspec/eth2spec/gen_helpers/gen_from_tests/gen.py b/tests/core/pyspec/eth2spec/gen_helpers/gen_from_tests/gen.py index f04bf46a7..057aa1a2c 100644 --- a/tests/core/pyspec/eth2spec/gen_helpers/gen_from_tests/gen.py +++ b/tests/core/pyspec/eth2spec/gen_helpers/gen_from_tests/gen.py @@ -11,7 +11,8 @@ from eth2spec.gen_helpers.gen_base.gen_typing import TestCase, TestProvider def generate_from_tests(runner_name: str, handler_name: str, src: Any, - fork_name: SpecForkName, bls_active: bool = True, phase: Optional[str]=None) -> Iterable[TestCase]: + fork_name: SpecForkName, bls_active: bool = True, + phase: Optional[str]=None) -> Iterable[TestCase]: """ Generate a list of test cases by running tests from the given src in generator-mode. :param runner_name: to categorize the test in general as. From 5e864af67a161878c294a41dce579a20f98b62bd Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Tue, 9 Mar 2021 21:32:37 +0800 Subject: [PATCH 46/56] Reload Altair spec --- tests/generators/forks/main.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/generators/forks/main.py b/tests/generators/forks/main.py index d39af802a..dd4c0051c 100644 --- a/tests/generators/forks/main.py +++ b/tests/generators/forks/main.py @@ -5,6 +5,7 @@ from eth2spec.test.context import PHASE0, LIGHTCLIENT_PATCH, MINIMAL, MAINNET from eth2spec.config import config_util from eth2spec.test.lightclient_patch.fork import test_fork as test_altair_forks from eth2spec.phase0 import spec as spec_phase0 +from eth2spec.lightclient_patch import spec as spec_lightclient_patch from eth2spec.gen_helpers.gen_base import gen_runner, gen_typing from eth2spec.gen_helpers.gen_from_tests.gen import generate_from_tests @@ -15,6 +16,7 @@ def create_provider(tests_src, config_name: str) -> gen_typing.TestProvider: def prepare_fn(configs_path: str) -> str: config_util.prepare_config(configs_path, config_name) reload(spec_phase0) + reload(spec_lightclient_patch) return config_name def cases_fn() -> Iterable[gen_typing.TestCase]: From f71a3c6b22fe23f28eb49216618a20ef194d1025 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Tue, 9 Mar 2021 21:34:45 +0800 Subject: [PATCH 47/56] Generate with mainnet config --- tests/generators/forks/main.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/generators/forks/main.py b/tests/generators/forks/main.py index dd4c0051c..b22707786 100644 --- a/tests/generators/forks/main.py +++ b/tests/generators/forks/main.py @@ -34,4 +34,5 @@ def create_provider(tests_src, config_name: str) -> gen_typing.TestProvider: if __name__ == "__main__": gen_runner.run_generator("forks", [ create_provider(test_altair_forks, MINIMAL), + create_provider(test_altair_forks, MAINNET), ]) From 956a7a2ef1a20da3472307768d41e28b69c80840 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Tue, 9 Mar 2021 16:09:08 -0700 Subject: [PATCH 48/56] Update tests/core/pyspec/eth2spec/test/context.py --- tests/core/pyspec/eth2spec/test/context.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core/pyspec/eth2spec/test/context.py b/tests/core/pyspec/eth2spec/test/context.py index f3d8e2a8f..916c74e6a 100644 --- a/tests/core/pyspec/eth2spec/test/context.py +++ b/tests/core/pyspec/eth2spec/test/context.py @@ -82,7 +82,7 @@ def _prepare_state(balances_fn: Callable[[Any], Sequence[int]], threshold_fn: Ca # TODO: instead of upgrading a test phase0 genesis state we can also write a phase1 state helper. # Decide based on performance/consistency results later. state = phases[PHASE1].upgrade_to_phase1(state) - elif spec.fork == LIGHTCLIENT_PATCH and not is_fork_test: # do not upgrade if spec ttttest + elif spec.fork == LIGHTCLIENT_PATCH and not is_fork_test: # do not upgrade if spec test state = phases[LIGHTCLIENT_PATCH].upgrade_to_lightclient_patch(state) return state From f9b54ea03ba57ee3335721596513c45f1f2eaa7c Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Tue, 9 Mar 2021 16:18:30 -0700 Subject: [PATCH 49/56] remove fork_test --- tests/core/pyspec/eth2spec/test/context.py | 19 ++++--------------- .../test/lightclient_patch/fork/test_fork.py | 9 +-------- 2 files changed, 5 insertions(+), 23 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/context.py b/tests/core/pyspec/eth2spec/test/context.py index 916c74e6a..1272485de 100644 --- a/tests/core/pyspec/eth2spec/test/context.py +++ b/tests/core/pyspec/eth2spec/test/context.py @@ -70,7 +70,7 @@ class SpecForks(TypedDict, total=False): def _prepare_state(balances_fn: Callable[[Any], Sequence[int]], threshold_fn: Callable[[Any], int], - spec: Spec, phases: SpecForks, is_fork_test: bool): + spec: Spec, phases: SpecForks): p0 = phases[PHASE0] balances = balances_fn(p0) @@ -82,7 +82,7 @@ def _prepare_state(balances_fn: Callable[[Any], Sequence[int]], threshold_fn: Ca # TODO: instead of upgrading a test phase0 genesis state we can also write a phase1 state helper. # Decide based on performance/consistency results later. state = phases[PHASE1].upgrade_to_phase1(state) - elif spec.fork == LIGHTCLIENT_PATCH and not is_fork_test: # do not upgrade if spec test + elif spec.fork == LIGHTCLIENT_PATCH: state = phases[LIGHTCLIENT_PATCH].upgrade_to_lightclient_patch(state) return state @@ -98,11 +98,10 @@ def with_custom_state(balances_fn: Callable[[Any], Sequence[int]], def entry(*args, spec: Spec, phases: SpecForks, **kw): # make a key for the state # genesis fork version separates configs during test-generation runtime. - is_fork_test = kw.pop('fork_test') if 'fork_test' in kw else False - key = (spec.fork, spec.GENESIS_FORK_VERSION, spec.__file__, balances_fn, threshold_fn, is_fork_test) + key = (spec.fork, spec.GENESIS_FORK_VERSION, spec.__file__, balances_fn, threshold_fn) global _custom_state_cache_dict if key not in _custom_state_cache_dict: - state = _prepare_state(balances_fn, threshold_fn, spec, phases, is_fork_test) + state = _prepare_state(balances_fn, threshold_fn, spec, phases) _custom_state_cache_dict[key] = state.get_backing() # Take an entry out of the LRU. @@ -288,16 +287,6 @@ def bls_switch(fn): return entry -def fork_test(fn): - """ - """ - def entry(*args, **kw): - # override fork test setting - kw['fork_test'] = True - return fn(*args, **kw) - return entry - - def disable_process_reveal_deadlines(fn): """ Decorator to make a function execute with `process_reveal_deadlines` OFF. diff --git a/tests/core/pyspec/eth2spec/test/lightclient_patch/fork/test_fork.py b/tests/core/pyspec/eth2spec/test/lightclient_patch/fork/test_fork.py index c5b9b8981..5904805cf 100644 --- a/tests/core/pyspec/eth2spec/test/lightclient_patch/fork/test_fork.py +++ b/tests/core/pyspec/eth2spec/test/lightclient_patch/fork/test_fork.py @@ -1,7 +1,7 @@ from eth2spec.test.context import ( PHASE0, LIGHTCLIENT_PATCH, with_phases, - with_custom_state, fork_test, + with_custom_state, spec_test, with_state, low_balances, misc_balances, large_validator_set, ) @@ -53,7 +53,6 @@ def run_fork_test(spec, pre_state): yield 'post', post_state -@fork_test @with_phases(([PHASE0])) @spec_test @with_state @@ -62,7 +61,6 @@ def test_fork_base_state(spec, phases, state): yield from run_fork_test(phases[LIGHTCLIENT_PATCH], state) -@fork_test @with_phases(([PHASE0])) @spec_test @with_state @@ -72,7 +70,6 @@ def test_fork_next_epoch(spec, phases, state): yield from run_fork_test(phases[LIGHTCLIENT_PATCH], state) -@fork_test @with_phases(([PHASE0])) @spec_test @with_state @@ -82,7 +79,6 @@ def test_fork_next_epoch_with_block(spec, phases, state): yield from run_fork_test(phases[LIGHTCLIENT_PATCH], state) -@fork_test @with_phases(([PHASE0])) @spec_test @with_state @@ -93,7 +89,6 @@ def test_fork_many_next_epoch(spec, phases, state): yield from run_fork_test(phases[LIGHTCLIENT_PATCH], state) -@fork_test @with_phases(([PHASE0])) @with_custom_state(balances_fn=low_balances, threshold_fn=lambda spec: spec.EJECTION_BALANCE) @spec_test @@ -102,7 +97,6 @@ def test_fork_random_low_balances(spec, phases, state): yield from run_fork_test(phases[LIGHTCLIENT_PATCH], state) -@fork_test @with_phases(([PHASE0])) @with_custom_state(balances_fn=misc_balances, threshold_fn=lambda spec: spec.EJECTION_BALANCE) @spec_test @@ -111,7 +105,6 @@ def test_fork_random_misc_balances(spec, phases, state): yield from run_fork_test(phases[LIGHTCLIENT_PATCH], state) -@fork_test @with_phases(([PHASE0])) @with_custom_state(balances_fn=large_validator_set, threshold_fn=lambda spec: spec.EJECTION_BALANCE) @spec_test From 338be1f636b7eae6a6bb3182d4b6682984e788c7 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Tue, 9 Mar 2021 16:27:06 -0700 Subject: [PATCH 50/56] clean up fork gens --- tests/formats/forks/README.md | 2 +- tests/generators/forks/main.py | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/formats/forks/README.md b/tests/formats/forks/README.md index 1a7ee64ad..57cc09227 100644 --- a/tests/formats/forks/README.md +++ b/tests/formats/forks/README.md @@ -3,7 +3,7 @@ The aim of the fork tests is to ensure that a pre-fork state can be transformed into a valid post-fork state, utilizing the `upgrade` function found in the relevant `fork.md` spec. -There is only one handler: `core`. Each fork (after genesis) is handled with the same format, +There is only one handler: `fork`. Each fork (after genesis) is handled with the same format, and the particular fork boundary being tested is noted in `meta.yaml`. ## Test case format diff --git a/tests/generators/forks/main.py b/tests/generators/forks/main.py index b22707786..1a603a0dc 100644 --- a/tests/generators/forks/main.py +++ b/tests/generators/forks/main.py @@ -11,7 +11,7 @@ from eth2spec.gen_helpers.gen_base import gen_runner, gen_typing from eth2spec.gen_helpers.gen_from_tests.gen import generate_from_tests -def create_provider(tests_src, config_name: str) -> gen_typing.TestProvider: +def create_provider(tests_src, config_name: str, phase: str, fork_name: str) -> gen_typing.TestProvider: def prepare_fn(configs_path: str) -> str: config_util.prepare_config(configs_path, config_name) @@ -24,8 +24,9 @@ def create_provider(tests_src, config_name: str) -> gen_typing.TestProvider: runner_name='fork', handler_name='fork', src=tests_src, - fork_name=LIGHTCLIENT_PATCH, - phase=PHASE0, + fork_name=fork_name, + phase=phase, + ) return gen_typing.TestProvider(prepare=prepare_fn, make_cases=cases_fn) @@ -33,6 +34,6 @@ def create_provider(tests_src, config_name: str) -> gen_typing.TestProvider: if __name__ == "__main__": gen_runner.run_generator("forks", [ - create_provider(test_altair_forks, MINIMAL), - create_provider(test_altair_forks, MAINNET), + create_provider(test_altair_forks, MINIMAL, PHASE0, LIGHTCLIENT_PATCH), + create_provider(test_altair_forks, MAINNET, PHASE0, LIGHTCLIENT_PATCH), ]) From 91f6956b3a0a6f210ec4d865f47836cde11e24a5 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Wed, 10 Mar 2021 21:55:50 +0800 Subject: [PATCH 51/56] Bump py_ecc to 5.2.0 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 6cfa0910a..efe2f379f 100644 --- a/setup.py +++ b/setup.py @@ -581,7 +581,7 @@ setup( "eth-utils>=1.3.0,<2", "eth-typing>=2.1.0,<3.0.0", "pycryptodome==3.9.4", - "py_ecc==5.1.0", + "py_ecc==5.2.0", "milagro_bls_binding==1.6.3", "dataclasses==0.6", "remerkleable==0.1.18", From e792c27c915f96e9b576b0a21f3c2cab73a93894 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Wed, 10 Mar 2021 12:27:50 -0700 Subject: [PATCH 52/56] @hwwhww review Co-authored-by: Hsiao-Wei Wang --- .../pyspec/eth2spec/gen_helpers/gen_from_tests/gen.py | 4 ++-- .../eth2spec/test/lightclient_patch/fork/test_fork.py | 8 ++++---- tests/generators/forks/main.py | 1 - 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/tests/core/pyspec/eth2spec/gen_helpers/gen_from_tests/gen.py b/tests/core/pyspec/eth2spec/gen_helpers/gen_from_tests/gen.py index 057aa1a2c..c090869d5 100644 --- a/tests/core/pyspec/eth2spec/gen_helpers/gen_from_tests/gen.py +++ b/tests/core/pyspec/eth2spec/gen_helpers/gen_from_tests/gen.py @@ -18,10 +18,10 @@ def generate_from_tests(runner_name: str, handler_name: str, src: Any, :param runner_name: to categorize the test in general as. :param handler_name: to categorize the test specialization as. :param src: to retrieve tests from (discovered using inspect.getmembers). - :param fork_name: to run tests against particular phase and/or fork. + :param fork_name: the folder name for these tests. (if multiple forks are applicable, indicate the last fork) :param bls_active: optional, to override BLS switch preference. Defaults to True. - :param phase: optional, specific phase name + :param phase: optional, to run tests against a particular spec version. Default to `fork_name` value. :return: an iterable of test cases. """ fn_names = [ diff --git a/tests/core/pyspec/eth2spec/test/lightclient_patch/fork/test_fork.py b/tests/core/pyspec/eth2spec/test/lightclient_patch/fork/test_fork.py index 5904805cf..dada24af9 100644 --- a/tests/core/pyspec/eth2spec/test/lightclient_patch/fork/test_fork.py +++ b/tests/core/pyspec/eth2spec/test/lightclient_patch/fork/test_fork.py @@ -17,10 +17,10 @@ HF1_FORK_TEST_META_TAGS = { } -def run_fork_test(spec, pre_state): +def run_fork_test(post_spec, pre_state): yield 'pre', pre_state - post_state = spec.upgrade_to_lightclient_patch(pre_state) + post_state = post_spec.upgrade_to_lightclient_patch(pre_state) # Stable fields stable_fields = [ @@ -47,8 +47,8 @@ def run_fork_test(spec, pre_state): assert getattr(pre_state, field) != getattr(post_state, field) assert pre_state.fork.current_version == post_state.fork.previous_version - assert post_state.fork.current_version == spec.LIGHTCLIENT_PATCH_FORK_VERSION - assert post_state.fork.epoch == spec.get_current_epoch(post_state) + assert post_state.fork.current_version == post_spec.LIGHTCLIENT_PATCH_FORK_VERSION + assert post_state.fork.epoch == post_spec.get_current_epoch(post_state) yield 'post', post_state diff --git a/tests/generators/forks/main.py b/tests/generators/forks/main.py index 1a603a0dc..190d4620c 100644 --- a/tests/generators/forks/main.py +++ b/tests/generators/forks/main.py @@ -26,7 +26,6 @@ def create_provider(tests_src, config_name: str, phase: str, fork_name: str) -> src=tests_src, fork_name=fork_name, phase=phase, - ) return gen_typing.TestProvider(prepare=prepare_fn, make_cases=cases_fn) From 1f3e73703c10c5e9c8c3dc182632a535222a8d7f Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Wed, 10 Mar 2021 12:38:30 -0700 Subject: [PATCH 53/56] use 'other_phases' for fork tests --- tests/core/pyspec/eth2spec/test/context.py | 11 +++++++---- .../test/lightclient_patch/fork/test_fork.py | 14 +++++++------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/context.py b/tests/core/pyspec/eth2spec/test/context.py index 1272485de..e197124c0 100644 --- a/tests/core/pyspec/eth2spec/test/context.py +++ b/tests/core/pyspec/eth2spec/test/context.py @@ -340,7 +340,7 @@ def with_phases(phases, other_phases=None): available_phases = set(run_phases) if other_phases is not None: - available_phases += set(other_phases) + available_phases |= set(other_phases) # TODO: test state is dependent on phase0 but is immediately transitioned to phase1. # A new state-creation helper for phase 1 may be in place, and then phase1+ tests can run without phase0 @@ -348,9 +348,12 @@ def with_phases(phases, other_phases=None): # Populate all phases for multi-phase tests phase_dir = {} - phase_dir[PHASE0] = spec_phase0 - phase_dir[PHASE1] = spec_phase1 - phase_dir[LIGHTCLIENT_PATCH] = spec_lightclient_patch + if PHASE0 in available_phases: + phase_dir[PHASE0] = spec_phase0 + if PHASE1 in available_phases: + phase_dir[PHASE1] = spec_phase1 + if LIGHTCLIENT_PATCH in available_phases: + phase_dir[LIGHTCLIENT_PATCH] = spec_lightclient_patch # return is ignored whenever multiple phases are ran. If if PHASE0 in run_phases: diff --git a/tests/core/pyspec/eth2spec/test/lightclient_patch/fork/test_fork.py b/tests/core/pyspec/eth2spec/test/lightclient_patch/fork/test_fork.py index dada24af9..27d181510 100644 --- a/tests/core/pyspec/eth2spec/test/lightclient_patch/fork/test_fork.py +++ b/tests/core/pyspec/eth2spec/test/lightclient_patch/fork/test_fork.py @@ -53,7 +53,7 @@ def run_fork_test(post_spec, pre_state): yield 'post', post_state -@with_phases(([PHASE0])) +@with_phases(phases=[PHASE0], other_phases=[LIGHTCLIENT_PATCH]) @spec_test @with_state @with_meta_tags(HF1_FORK_TEST_META_TAGS) @@ -61,7 +61,7 @@ def test_fork_base_state(spec, phases, state): yield from run_fork_test(phases[LIGHTCLIENT_PATCH], state) -@with_phases(([PHASE0])) +@with_phases(phases=[PHASE0], other_phases=[LIGHTCLIENT_PATCH]) @spec_test @with_state @with_meta_tags(HF1_FORK_TEST_META_TAGS) @@ -70,7 +70,7 @@ def test_fork_next_epoch(spec, phases, state): yield from run_fork_test(phases[LIGHTCLIENT_PATCH], state) -@with_phases(([PHASE0])) +@with_phases(phases=[PHASE0], other_phases=[LIGHTCLIENT_PATCH]) @spec_test @with_state @with_meta_tags(HF1_FORK_TEST_META_TAGS) @@ -79,7 +79,7 @@ def test_fork_next_epoch_with_block(spec, phases, state): yield from run_fork_test(phases[LIGHTCLIENT_PATCH], state) -@with_phases(([PHASE0])) +@with_phases(phases=[PHASE0], other_phases=[LIGHTCLIENT_PATCH]) @spec_test @with_state @with_meta_tags(HF1_FORK_TEST_META_TAGS) @@ -89,7 +89,7 @@ def test_fork_many_next_epoch(spec, phases, state): yield from run_fork_test(phases[LIGHTCLIENT_PATCH], state) -@with_phases(([PHASE0])) +@with_phases(phases=[PHASE0], other_phases=[LIGHTCLIENT_PATCH]) @with_custom_state(balances_fn=low_balances, threshold_fn=lambda spec: spec.EJECTION_BALANCE) @spec_test @with_meta_tags(HF1_FORK_TEST_META_TAGS) @@ -97,7 +97,7 @@ def test_fork_random_low_balances(spec, phases, state): yield from run_fork_test(phases[LIGHTCLIENT_PATCH], state) -@with_phases(([PHASE0])) +@with_phases(phases=[PHASE0], other_phases=[LIGHTCLIENT_PATCH]) @with_custom_state(balances_fn=misc_balances, threshold_fn=lambda spec: spec.EJECTION_BALANCE) @spec_test @with_meta_tags(HF1_FORK_TEST_META_TAGS) @@ -105,7 +105,7 @@ def test_fork_random_misc_balances(spec, phases, state): yield from run_fork_test(phases[LIGHTCLIENT_PATCH], state) -@with_phases(([PHASE0])) +@with_phases(phases=[PHASE0], other_phases=[LIGHTCLIENT_PATCH]) @with_custom_state(balances_fn=large_validator_set, threshold_fn=lambda spec: spec.EJECTION_BALANCE) @spec_test @with_meta_tags(HF1_FORK_TEST_META_TAGS) From 7205f70192b5ec9dc409ee2f99eebef37ea123e1 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Wed, 10 Mar 2021 16:48:53 -0700 Subject: [PATCH 54/56] patch remaining generator docs to reflect snappy_ssz encoding --- tests/formats/README.md | 10 +++++----- tests/formats/forks/README.md | 12 ++++-------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/tests/formats/README.md b/tests/formats/README.md index d3933abdd..7808538ad 100644 --- a/tests/formats/README.md +++ b/tests/formats/README.md @@ -134,10 +134,10 @@ Cases are split up too. This enables diffing of parts of the test case, tracking These files allow for custom formats for some parts of the test. E.g. something encoded in SSZ. Or to avoid large files, the SSZ can be compressed with Snappy. -E.g. `pre.ssz_snappy_snappy`, `deposit.ssz_snappy_snappy`, `post.ssz_snappy_snappy`. +E.g. `pre.ssz_snappy`, `deposit.ssz_snappy`, `post.ssz_snappy`. -Diffing a `pre.ssz_snappy_snappy` and `post.ssz_snappy_snappy` provides all the information for testing, when decompressed and decoded. -Then the difference between pre and post can be compared to anything that changes the pre state, e.g. `deposit.ssz_snappy_snappy` +Diffing a `pre.ssz_snappy` and `post.ssz_snappy` provides all the information for testing, when decompressed and decoded. +Then the difference between pre and post can be compared to anything that changes the pre state, e.g. `deposit.ssz_snappy` YAML is generally used for test metadata, and for tests that do not use SSZ: e.g. shuffling and BLS tests. In this case, there is no point in adding special SSZ types. And the size and efficiency of YAML is acceptable. @@ -147,8 +147,8 @@ In this case, there is no point in adding special SSZ types. And the size and ef Between all types of tests, a few formats are common: - **`.yaml`**: A YAML file containing structured data to describe settings or test contents. -- **`.ssz_snappy`**: A file containing raw SSZ-encoded data. Previously widely used in tests, but replaced with compressed variant. -- **`.ssz_snappy_snappy`**: Like `.ssz_snappy`, but compressed with Snappy block compression. +- **`.ssz`**: A file containing raw SSZ-encoded data. Previously widely used in tests, but replaced with compressed variant. +- **`.ssz_snappy`**: Like `.ssz`, but compressed with Snappy block compression. Snappy block compression is already applied to SSZ in Eth2 gossip, available in client implementations, and thus chosen as compression method. diff --git a/tests/formats/forks/README.md b/tests/formats/forks/README.md index 57cc09227..cbafd4e2a 100644 --- a/tests/formats/forks/README.md +++ b/tests/formats/forks/README.md @@ -24,17 +24,13 @@ Key of valid `fork` strings that might be found in `meta.yaml` | - | - | - | - | | `altair` | Phase 0 | Altair | `upgrade_to_lightclient_patch` | -### `pre.yaml` +### `pre.ssz_snappy` -A YAML-encoded `BeaconState`, the state before running the fork transition. +A SSZ-snappy encoded `BeaconState`, the state before running the fork transition. -Also available as `pre.ssz`. +### `post.ssz_snappy` -### `post.yaml` - -A YAML-encoded `BeaconState`, the state after applying the fork transition. - -Also available as `post.ssz`. +A SSZ-snappy encoded `BeaconState`, the state after applying the fork transition. *Note*: This type is the `BeaconState` after the fork and is *not* the same type as `pre`. From c36106e63060c81760827fd1c740ea77ec3ba37a Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Wed, 10 Mar 2021 17:18:11 -0700 Subject: [PATCH 55/56] put snappy in 'generator' extra dep build and use for generator builds --- setup.py | 2 +- tests/generators/README.md | 2 +- tests/generators/bls/requirements.txt | 2 +- tests/generators/epoch_processing/requirements.txt | 2 +- tests/generators/finality/requirements.txt | 2 +- tests/generators/forks/requirements.txt | 2 +- tests/generators/genesis/requirements.txt | 2 +- tests/generators/operations/requirements.txt | 2 +- tests/generators/rewards/requirements.txt | 2 +- tests/generators/shuffling/requirements.txt | 2 +- tests/generators/ssz_generic/requirements.txt | 2 +- tests/generators/ssz_static/requirements.txt | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/setup.py b/setup.py index 7923c0a44..aa74fcb05 100644 --- a/setup.py +++ b/setup.py @@ -576,6 +576,7 @@ setup( extras_require={ "test": ["pytest>=4.4", "pytest-cov", "pytest-xdist"], "lint": ["flake8==3.7.7", "mypy==0.750"], + "generator": ["python-snappy==0.5.4"], }, install_requires=[ "eth-utils>=1.3.0,<2", @@ -587,6 +588,5 @@ setup( "remerkleable==0.1.18", "ruamel.yaml==0.16.5", "lru-dict==1.1.6", - "python-snappy==0.5.4", ] ) diff --git a/tests/generators/README.md b/tests/generators/README.md index 0f1ed478f..6ccf9f118 100644 --- a/tests/generators/README.md +++ b/tests/generators/README.md @@ -79,7 +79,7 @@ It's recommended to extend the base-generator. Create a `requirements.txt` in the root of your generator directory: ``` pytest>=4.4 -../../../ +../../../[generator] ``` The config helper and pyspec is optional, but preferred. We encourage generators to derive tests from the spec itself in order to prevent code duplication and outdated tests. diff --git a/tests/generators/bls/requirements.txt b/tests/generators/bls/requirements.txt index df386450b..182248686 100644 --- a/tests/generators/bls/requirements.txt +++ b/tests/generators/bls/requirements.txt @@ -1,2 +1,2 @@ pytest>=4.4 -../../../ +../../../[generator] diff --git a/tests/generators/epoch_processing/requirements.txt b/tests/generators/epoch_processing/requirements.txt index df386450b..182248686 100644 --- a/tests/generators/epoch_processing/requirements.txt +++ b/tests/generators/epoch_processing/requirements.txt @@ -1,2 +1,2 @@ pytest>=4.4 -../../../ +../../../[generator] diff --git a/tests/generators/finality/requirements.txt b/tests/generators/finality/requirements.txt index df386450b..182248686 100644 --- a/tests/generators/finality/requirements.txt +++ b/tests/generators/finality/requirements.txt @@ -1,2 +1,2 @@ pytest>=4.4 -../../../ +../../../[generator] diff --git a/tests/generators/forks/requirements.txt b/tests/generators/forks/requirements.txt index 816df6e63..735f863fa 100644 --- a/tests/generators/forks/requirements.txt +++ b/tests/generators/forks/requirements.txt @@ -1,2 +1,2 @@ pytest>=4.4 -../../../ \ No newline at end of file +../../../[generator] \ No newline at end of file diff --git a/tests/generators/genesis/requirements.txt b/tests/generators/genesis/requirements.txt index df386450b..182248686 100644 --- a/tests/generators/genesis/requirements.txt +++ b/tests/generators/genesis/requirements.txt @@ -1,2 +1,2 @@ pytest>=4.4 -../../../ +../../../[generator] diff --git a/tests/generators/operations/requirements.txt b/tests/generators/operations/requirements.txt index df386450b..182248686 100644 --- a/tests/generators/operations/requirements.txt +++ b/tests/generators/operations/requirements.txt @@ -1,2 +1,2 @@ pytest>=4.4 -../../../ +../../../[generator] diff --git a/tests/generators/rewards/requirements.txt b/tests/generators/rewards/requirements.txt index df386450b..182248686 100644 --- a/tests/generators/rewards/requirements.txt +++ b/tests/generators/rewards/requirements.txt @@ -1,2 +1,2 @@ pytest>=4.4 -../../../ +../../../[generator] diff --git a/tests/generators/shuffling/requirements.txt b/tests/generators/shuffling/requirements.txt index df386450b..182248686 100644 --- a/tests/generators/shuffling/requirements.txt +++ b/tests/generators/shuffling/requirements.txt @@ -1,2 +1,2 @@ pytest>=4.4 -../../../ +../../../[generator] diff --git a/tests/generators/ssz_generic/requirements.txt b/tests/generators/ssz_generic/requirements.txt index df386450b..182248686 100644 --- a/tests/generators/ssz_generic/requirements.txt +++ b/tests/generators/ssz_generic/requirements.txt @@ -1,2 +1,2 @@ pytest>=4.4 -../../../ +../../../[generator] diff --git a/tests/generators/ssz_static/requirements.txt b/tests/generators/ssz_static/requirements.txt index df386450b..182248686 100644 --- a/tests/generators/ssz_static/requirements.txt +++ b/tests/generators/ssz_static/requirements.txt @@ -1,2 +1,2 @@ pytest>=4.4 -../../../ +../../../[generator] From 4569ddea5d675ee1e743bc5fc5adf2d889923e96 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Wed, 10 Mar 2021 18:49:50 -0700 Subject: [PATCH 56/56] add missing sanity requirements.txt for generators --- tests/generators/sanity/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/generators/sanity/requirements.txt b/tests/generators/sanity/requirements.txt index df386450b..182248686 100644 --- a/tests/generators/sanity/requirements.txt +++ b/tests/generators/sanity/requirements.txt @@ -1,2 +1,2 @@ pytest>=4.4 -../../../ +../../../[generator]