diff --git a/.gitignore b/.gitignore index 5249d6560..788410645 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,6 @@ tests/core/pyspec/test-reports tests/core/pyspec/eth2spec/test_results.xml *.egg-info + +# TOC tool outputs temporary files +*.tmp diff --git a/Makefile b/Makefile index e4969ff2f..007f49f5b 100644 --- a/Makefile +++ b/Makefile @@ -96,11 +96,11 @@ install_test: test: pyspec . venv/bin/activate; cd $(PY_SPEC_DIR); \ - python3 -m pytest -n 4 --disable-bls --cov=eth2spec.phase0.spec --cov=eth2spec.altair.spec --cov-report="html:$(COV_HTML_OUT)" --cov-branch eth2spec + python3 -m pytest -n 4 --disable-bls --cov=eth2spec.phase0.mainnet --cov=eth2spec.altair.mainnet --cov-report="html:$(COV_HTML_OUT)" --cov-branch eth2spec find_test: pyspec . venv/bin/activate; cd $(PY_SPEC_DIR); \ - python3 -m pytest -k=$(K) --disable-bls --cov=eth2spec.phase0.spec --cov=eth2spec.altair.spec --cov-report="html:$(COV_HTML_OUT)" --cov-branch eth2spec + python3 -m pytest -k=$(K) --disable-bls --cov=eth2spec.phase0.mainnet --cov=eth2spec.altair.mainnet --cov-report="html:$(COV_HTML_OUT)" --cov-branch eth2spec citest: pyspec mkdir -p tests/core/pyspec/test-reports/eth2spec; . venv/bin/activate; cd $(PY_SPEC_DIR); \ @@ -167,7 +167,7 @@ define run_generator if ! test -d venv; then python3 -m venv venv; fi; \ . venv/bin/activate; \ pip3 install -r requirements.txt; \ - python3 main.py -o $(CURRENT_DIR)/$(TEST_VECTOR_DIR) -c $(CURRENT_DIR)/$(CONFIGS_DIR); \ + python3 main.py -o $(CURRENT_DIR)/$(TEST_VECTOR_DIR); \ echo "generator $(1) finished" endef diff --git a/configs/README.md b/configs/README.md index 2cf4e3f60..f470b932d 100644 --- a/configs/README.md +++ b/configs/README.md @@ -1,34 +1,39 @@ -# Configs +# Configurations -This directory contains a set of constants presets used for testing, testnets, and mainnet. +This directory contains a set of configurations used for testing, testnets, and mainnet. +A client binary may be compiled for a specific `PRESET_BASE`, +and then load different configurations around that preset to participate in different networks or tests. -A preset file contains all the constants known for its target. -Later-fork constants can be ignored, e.g. ignore Sharding constants as a client that only supports Phase 0 currently. +Standard configs: +- [`mainnet.yaml`](./mainnet.yaml): Mainnet configuration +- [`minimal.yaml`](./minimal.yaml): Minimal configuration, used in spec-testing along with the [`minimal`](../presets/minimal) preset. +Not all network configurations are in scope for the specification, +see [`github.com/eth2-clients/eth2-networks`](https://github.com/eth2-clients/eth2-networks) for common networks, +and additional testnet assets. ## Forking -Configs are not replaced, but extended with forks. This is to support syncing from one state to the other over a fork boundary, without hot-swapping a config. -Instead, for forks that introduce changes in a constant, the constant name is prefixed with a short abbreviation of the fork. +Variables are not replaced but extended with forks. This is to support syncing from one state to another over a fork boundary, without hot-swapping a config. +Instead, for forks that introduce changes in a variable, the variable name is suffixed with the fork name, e.g. `INACTIVITY_PENALTY_QUOTIENT_ALTAIR`. + +Future-fork variables can be ignored, e.g. ignore Sharding variables as a client that only supports Phase 0 currently. Over time, the need to sync an older state may be deprecated. -In this case, the prefix on the new constant may be removed, and the old constant will keep a special name before completely being removed. +In this case, the suffix on the new variable may be removed, and the old variable will keep a special name before completely being removed. -A previous iteration of forking made use of "timelines", but this collides with the definitions used in the spec (constants for special forking slots, etc.), and was not integrated sufficiently in any of the spec tools or implementations. +A previous iteration of forking made use of "timelines", but this collides with the definitions used in the spec (variables for special forking slots, etc.), and was not integrated sufficiently in any of the spec tools or implementations. Instead, the config essentially doubles as fork definition now, e.g. changing the value for `ALTAIR_FORK_EPOCH` changes the fork. - -Another reason to prefer forking through constants is the ability to program a forking moment based on context, instead of being limited to a static slot number. ## Format -Each preset is a key-value mapping. +Each preset and configuration is a key-value mapping. -**Key**: an `UPPER_SNAKE_CASE` (a.k.a. "macro case") formatted string, name of the constant. +**Key**: an `UPPER_SNAKE_CASE` (a.k.a. "macro case") formatted string, name of the variable. **Value** can be either: - an unsigned integer number, can be up to 64 bits (incl.) - a hexadecimal string, prefixed with `0x` -Presets may contain comments to describe the values. - -See [`mainnet/phase0.yaml`](./mainnet/phase0.yaml) for a complete example. +This format is fully YAML compatible. +The presets and configurations may contain comments to describe the values. diff --git a/configs/mainnet.yaml b/configs/mainnet.yaml new file mode 100644 index 000000000..47b02aa8d --- /dev/null +++ b/configs/mainnet.yaml @@ -0,0 +1,71 @@ +# Mainnet config + +# Extends the mainnet preset +PRESET_BASE: 'mainnet' + +# Genesis +# --------------------------------------------------------------- +# `2**14` (= 16,384) +MIN_GENESIS_ACTIVE_VALIDATOR_COUNT: 16384 +# Dec 1, 2020, 12pm UTC +MIN_GENESIS_TIME: 1606824000 +# Mainnet initial fork version, recommend altering for testnets +GENESIS_FORK_VERSION: 0x00000000 +# 604800 seconds (7 days) +GENESIS_DELAY: 604800 + + +# Forking +# --------------------------------------------------------------- +# Some forks are disabled for now: +# - These may be re-assigned to another fork-version later +# - Temporarily set to max uint64 value: 2**64 - 1 + +# Altair +ALTAIR_FORK_VERSION: 0x01000000 +ALTAIR_FORK_EPOCH: 18446744073709551615 +# Merge +MERGE_FORK_VERSION: 0x02000000 +MERGE_FORK_EPOCH: 18446744073709551615 +# Sharding +SHARDING_FORK_VERSION: 0x03000000 +SHARDING_FORK_EPOCH: 18446744073709551615 + +# TBD, 2**32 is a placeholder. Merge transition approach is in active R&D. +TRANSITION_TOTAL_DIFFICULTY: 4294967296 + + +# Time parameters +# --------------------------------------------------------------- +# 12 seconds +SECONDS_PER_SLOT: 12 +# 14 (estimate from Eth1 mainnet) +SECONDS_PER_ETH1_BLOCK: 14 +# 2**8 (= 256) epochs ~27 hours +MIN_VALIDATOR_WITHDRAWABILITY_DELAY: 256 +# 2**8 (= 256) epochs ~27 hours +SHARD_COMMITTEE_PERIOD: 256 +# 2**11 (= 2,048) Eth1 blocks ~8 hours +ETH1_FOLLOW_DISTANCE: 2048 + + +# Validator cycle +# --------------------------------------------------------------- +# 2**2 (= 4) +INACTIVITY_SCORE_BIAS: 4 +# 2**4 (= 16) +INACTIVITY_SCORE_RECOVERY_RATE: 16 +# 2**4 * 10**9 (= 16,000,000,000) Gwei +EJECTION_BALANCE: 16000000000 +# 2**2 (= 4) +MIN_PER_EPOCH_CHURN_LIMIT: 4 +# 2**16 (= 65,536) +CHURN_LIMIT_QUOTIENT: 65536 + + +# Deposit contract +# --------------------------------------------------------------- +# Ethereum PoW Mainnet +DEPOSIT_CHAIN_ID: 1 +DEPOSIT_NETWORK_ID: 1 +DEPOSIT_CONTRACT_ADDRESS: 0x00000000219ab540356cBB839Cbe05303d7705Fa diff --git a/configs/mainnet/altair.yaml b/configs/mainnet/altair.yaml deleted file mode 100644 index a6761b142..000000000 --- a/configs/mainnet/altair.yaml +++ /dev/null @@ -1,53 +0,0 @@ -# Mainnet preset - Altair - -# Updated penalty values -# --------------------------------------------------------------- -# 3 * 2**24 (= 50,331,648) -INACTIVITY_PENALTY_QUOTIENT_ALTAIR: 50331648 -# 2**6 (= 64) -MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR: 64 -# 2 -PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR: 2 - - -# Sync committee -# --------------------------------------------------------------- -# 2**9 (= 512) -SYNC_COMMITTEE_SIZE: 512 -# 2**9 (= 512) -EPOCHS_PER_SYNC_COMMITTEE_PERIOD: 512 - - -# Misc -# --------------------------------------------------------------- -# 2**2 (= 4) -INACTIVITY_SCORE_BIAS: 4 -# 2**4 (= 16) -INACTIVITY_SCORE_RECOVERY_RATE: 16 - - -# Signature domains -# --------------------------------------------------------------- -DOMAIN_SYNC_COMMITTEE: 0x07000000 -DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF: 0x08000000 -DOMAIN_CONTRIBUTION_AND_PROOF: 0x09000000 - - -# Fork -# --------------------------------------------------------------- -# 0x01000000 -ALTAIR_FORK_VERSION: 0x01000000 -# TBD -ALTAIR_FORK_EPOCH: 18446744073709551615 - - -# Sync protocol -# --------------------------------------------------------------- -# 1 -MIN_SYNC_COMMITTEE_PARTICIPANTS: 1 - - -# Validator -# --------------------------------------------------------------- -# 2**2 (= 4) -TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE: 4 diff --git a/configs/mainnet/merge.yaml b/configs/mainnet/merge.yaml deleted file mode 100644 index 4e012ac05..000000000 --- a/configs/mainnet/merge.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# Mainnet preset - The Merge - -# Fork -# --------------------------------------------------------------- -MERGE_FORK_VERSION: 0x02000000 -# TBD, temporarily max uint64 value: 2**64 - 1 -MERGE_FORK_EPOCH: 18446744073709551615 diff --git a/configs/minimal.yaml b/configs/minimal.yaml new file mode 100644 index 000000000..1a04c4ecd --- /dev/null +++ b/configs/minimal.yaml @@ -0,0 +1,71 @@ +# Minimal config + +# Extends the minimal preset +PRESET_BASE: 'minimal' + +# Genesis +# --------------------------------------------------------------- +# [customized] +MIN_GENESIS_ACTIVE_VALIDATOR_COUNT: 64 +# Jan 3, 2020 +MIN_GENESIS_TIME: 1578009600 +# Highest byte set to 0x01 to avoid collisions with mainnet versioning +GENESIS_FORK_VERSION: 0x00000001 +# [customized] Faster to spin up testnets, but does not give validator reasonable warning time for genesis +GENESIS_DELAY: 300 + + +# Forking +# --------------------------------------------------------------- +# Values provided for illustrative purposes. +# Individual tests/testnets may set different values. + +# Altair +ALTAIR_FORK_VERSION: 0x01000001 +ALTAIR_FORK_EPOCH: 18446744073709551615 +# Merge +MERGE_FORK_VERSION: 0x02000001 +MERGE_FORK_EPOCH: 18446744073709551615 +# Sharding +SHARDING_FORK_VERSION: 0x03000001 +SHARDING_FORK_EPOCH: 18446744073709551615 + +# TBD, 2**32 is a placeholder. Merge transition approach is in active R&D. +TRANSITION_TOTAL_DIFFICULTY: 4294967296 + + +# Time parameters +# --------------------------------------------------------------- +# [customized] Faster for testing purposes +SECONDS_PER_SLOT: 6 +# 14 (estimate from Eth1 mainnet) +SECONDS_PER_ETH1_BLOCK: 14 +# 2**8 (= 256) epochs +MIN_VALIDATOR_WITHDRAWABILITY_DELAY: 256 +# [customized] higher frequency of committee turnover and faster time to acceptable voluntary exit +SHARD_COMMITTEE_PERIOD: 64 +# [customized] process deposits more quickly, but insecure +ETH1_FOLLOW_DISTANCE: 16 + + +# Validator cycle +# --------------------------------------------------------------- +# 2**2 (= 4) +INACTIVITY_SCORE_BIAS: 4 +# 2**4 (= 16) +INACTIVITY_SCORE_RECOVERY_RATE: 16 +# 2**4 * 10**9 (= 16,000,000,000) Gwei +EJECTION_BALANCE: 16000000000 +# 2**2 (= 4) +MIN_PER_EPOCH_CHURN_LIMIT: 4 +# 2**16 (= 65,536) +CHURN_LIMIT_QUOTIENT: 65536 + + +# Deposit contract +# --------------------------------------------------------------- +# Ethereum Goerli testnet +DEPOSIT_CHAIN_ID: 5 +DEPOSIT_NETWORK_ID: 5 +# Configured on a per testnet basis +DEPOSIT_CONTRACT_ADDRESS: 0x1234567890123456789012345678901234567890 diff --git a/configs/minimal/altair.yaml b/configs/minimal/altair.yaml deleted file mode 100644 index f9b8401e1..000000000 --- a/configs/minimal/altair.yaml +++ /dev/null @@ -1,54 +0,0 @@ -# Minimal preset - Altair - -# Updated penalty values -# --------------------------------------------------------------- -# 3 * 2**24 (= 50,331,648) -INACTIVITY_PENALTY_QUOTIENT_ALTAIR: 50331648 -# 2**6 (= 64) -MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR: 64 -# 2 -PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR: 2 - - -# Sync committee -# --------------------------------------------------------------- -# [customized] -SYNC_COMMITTEE_SIZE: 32 -# [customized] -EPOCHS_PER_SYNC_COMMITTEE_PERIOD: 8 - - -# Misc -# --------------------------------------------------------------- -# 2**2 (= 4) -INACTIVITY_SCORE_BIAS: 4 -# 2**4 (= 16) -INACTIVITY_SCORE_RECOVERY_RATE: 16 - - -# Signature domains -# --------------------------------------------------------------- -DOMAIN_SYNC_COMMITTEE: 0x07000000 -DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF: 0x08000000 -DOMAIN_CONTRIBUTION_AND_PROOF: 0x09000000 - - -# Fork -# --------------------------------------------------------------- -# [customized] Highest byte set to 0x01 to avoid collisions with mainnet versioning -ALTAIR_FORK_VERSION: 0x01000001 -# [customized] -ALTAIR_FORK_EPOCH: 18446744073709551615 - - -# Sync protocol -# --------------------------------------------------------------- -# 1 -MIN_SYNC_COMMITTEE_PARTICIPANTS: 1 - - - -# Validator -# --------------------------------------------------------------- -# 2**2 (= 4) -TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE: 4 diff --git a/configs/minimal/merge.yaml b/configs/minimal/merge.yaml deleted file mode 100644 index 3b50cd5ca..000000000 --- a/configs/minimal/merge.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# Minimal preset - The Merge - -# Fork -# --------------------------------------------------------------- -MERGE_FORK_VERSION: 0x02000001 -# TBD, temporarily max uint64 value: 2**64 - 1 -MERGE_FORK_EPOCH: 18446744073709551615 diff --git a/presets/README.md b/presets/README.md new file mode 100644 index 000000000..3a438cb2c --- /dev/null +++ b/presets/README.md @@ -0,0 +1,26 @@ +# Presets + +Presets are more extensive than runtime configurations, and generally only applicable during compile-time. +Each preset is defined as a directory, with YAML files per fork. + +Configurations can extend a preset by setting the `PRESET_BASE` variable. +An implementation may choose to only support 1 preset per build-target and should validate +the `PRESET_BASE` variable in the config matches the running build. + +Standard presets: +- [`mainnet/`](./mainnet): Used in mainnet, mainnet-like testnets (e.g. Prater), and spec-testing +- [`minimal/`](./minimal): Used in low-resource local dev testnets, and spec-testing + +Client implementers may opt to support additional presets, e.g. for extra large beacon states for benchmarking. +See [`/configs/`](../configs) for run-time configuration, e.g. to configure a new testnet. + +## Forking + +Like the [config forking](../configs/README.md#forking), +the preset extends with every fork, instead of overwriting previous values. +An implementation can ignore preset files as a whole for future forks, +and can thus implement stricter compile-time warnings on unrecognized or missing variables in current forks. + +## Format + +The preset format matches the [config format](../configs/README.md#format). diff --git a/presets/mainnet/altair.yaml b/presets/mainnet/altair.yaml new file mode 100644 index 000000000..9f0ad9b4c --- /dev/null +++ b/presets/mainnet/altair.yaml @@ -0,0 +1,24 @@ +# Mainnet preset - Altair + +# Updated penalty values +# --------------------------------------------------------------- +# 3 * 2**24 (= 50,331,648) +INACTIVITY_PENALTY_QUOTIENT_ALTAIR: 50331648 +# 2**6 (= 64) +MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR: 64 +# 2 +PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR: 2 + + +# Sync committee +# --------------------------------------------------------------- +# 2**9 (= 512) +SYNC_COMMITTEE_SIZE: 512 +# 2**9 (= 512) +EPOCHS_PER_SYNC_COMMITTEE_PERIOD: 512 + + +# Sync protocol +# --------------------------------------------------------------- +# 1 +MIN_SYNC_COMMITTEE_PARTICIPANTS: 1 diff --git a/configs/mainnet/custody_game.yaml b/presets/mainnet/custody_game.yaml similarity index 66% rename from configs/mainnet/custody_game.yaml rename to presets/mainnet/custody_game.yaml index ecb2dc377..2930f9c78 100644 --- a/configs/mainnet/custody_game.yaml +++ b/presets/mainnet/custody_game.yaml @@ -13,14 +13,6 @@ CUSTODY_PERIOD_TO_RANDAO_PADDING: 2048 # 2**15 (= 32,768) epochs, ~146 days MAX_CHUNK_CHALLENGE_DELAY: 32768 -# Misc parameters -# --------------------------------------------------------------- -# 2**256 - 189 -CUSTODY_PRIME: 115792089237316195423570985008687907853269984665640564039457584007913129639747 -# 3 -CUSTODY_SECRETS: 3 -# 1/1024 chance of custody bit 1 -CUSTODY_PROBABILITY_EXPONENT: 10 # Max operations # --------------------------------------------------------------- @@ -35,14 +27,9 @@ MAX_CUSTODY_CHUNK_CHALLENGE_RESP: 16 # 2**0 (= 1) MAX_CUSTODY_SLASHINGS: 1 + # Reward and penalty quotients # --------------------------------------------------------------- EARLY_DERIVED_SECRET_REVEAL_SLOT_REWARD_MULTIPLE: 2 # 2**8 (= 256) MINOR_REWARD_QUOTIENT: 256 - -# Signature domains -# --------------------------------------------------------------- -DOMAIN_CUSTODY_BIT_SLASHING: 0x83000000 -DOMAIN_LIGHT_SELECTION_PROOF: 0x84000000 -DOMAIN_LIGHT_AGGREGATE_AND_PROOF: 0x85000000 diff --git a/presets/mainnet/merge.yaml b/presets/mainnet/merge.yaml new file mode 100644 index 000000000..97f07c7f0 --- /dev/null +++ b/presets/mainnet/merge.yaml @@ -0,0 +1,3 @@ +# Mainnet preset - The Merge + +# No presets here. diff --git a/configs/mainnet/phase0.yaml b/presets/mainnet/phase0.yaml similarity index 59% rename from configs/mainnet/phase0.yaml rename to presets/mainnet/phase0.yaml index 8b902f1c3..89bb97d6a 100644 --- a/configs/mainnet/phase0.yaml +++ b/presets/mainnet/phase0.yaml @@ -1,4 +1,4 @@ -# Mainnet preset +# Mainnet preset - Phase0 # Misc # --------------------------------------------------------------- @@ -8,16 +8,8 @@ MAX_COMMITTEES_PER_SLOT: 64 TARGET_COMMITTEE_SIZE: 128 # 2**11 (= 2,048) MAX_VALIDATORS_PER_COMMITTEE: 2048 -# 2**2 (= 4) -MIN_PER_EPOCH_CHURN_LIMIT: 4 -# 2**16 (= 65,536) -CHURN_LIMIT_QUOTIENT: 65536 # See issue 563 SHUFFLE_ROUND_COUNT: 90 -# `2**14` (= 16,384) -MIN_GENESIS_ACTIVE_VALIDATOR_COUNT: 16384 -# Dec 1, 2020, 12pm UTC -MIN_GENESIS_TIME: 1606824000 # 4 HYSTERESIS_QUOTIENT: 4 # 1 (minus 0.25) @@ -32,54 +24,18 @@ HYSTERESIS_UPWARD_MULTIPLIER: 5 SAFE_SLOTS_TO_UPDATE_JUSTIFIED: 8 -# Validator -# --------------------------------------------------------------- -# 2**11 (= 2,048) -ETH1_FOLLOW_DISTANCE: 2048 -# 2**4 (= 16) -TARGET_AGGREGATORS_PER_COMMITTEE: 16 -# 2**0 (= 1) -RANDOM_SUBNETS_PER_VALIDATOR: 1 -# 2**8 (= 256) -EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION: 256 -# 14 (estimate from Eth1 mainnet) -SECONDS_PER_ETH1_BLOCK: 14 - - -# Deposit contract -# --------------------------------------------------------------- -# Ethereum PoW Mainnet -DEPOSIT_CHAIN_ID: 1 -DEPOSIT_NETWORK_ID: 1 -# **TBD** -DEPOSIT_CONTRACT_ADDRESS: 0x00000000219ab540356cBB839Cbe05303d7705Fa - - # Gwei values # --------------------------------------------------------------- # 2**0 * 10**9 (= 1,000,000,000) Gwei MIN_DEPOSIT_AMOUNT: 1000000000 # 2**5 * 10**9 (= 32,000,000,000) Gwei MAX_EFFECTIVE_BALANCE: 32000000000 -# 2**4 * 10**9 (= 16,000,000,000) Gwei -EJECTION_BALANCE: 16000000000 # 2**0 * 10**9 (= 1,000,000,000) Gwei EFFECTIVE_BALANCE_INCREMENT: 1000000000 -# Initial values -# --------------------------------------------------------------- -# Mainnet initial fork version, recommend altering for testnets -GENESIS_FORK_VERSION: 0x00000000 -BLS_WITHDRAWAL_PREFIX: 0x00 - - # Time parameters # --------------------------------------------------------------- -# 604800 seconds (7 days) -GENESIS_DELAY: 604800 -# 12 seconds -SECONDS_PER_SLOT: 12 # 2**0 (= 1) slots 12 seconds MIN_ATTESTATION_INCLUSION_DELAY: 1 # 2**5 (= 32) slots 6.4 minutes @@ -90,17 +46,13 @@ MIN_SEED_LOOKAHEAD: 1 MAX_SEED_LOOKAHEAD: 4 # 2**6 (= 64) epochs ~6.8 hours EPOCHS_PER_ETH1_VOTING_PERIOD: 64 -# 2**13 (= 8,192) slots ~13 hours +# 2**13 (= 8,192) slots ~27 hours SLOTS_PER_HISTORICAL_ROOT: 8192 -# 2**8 (= 256) epochs ~27 hours -MIN_VALIDATOR_WITHDRAWABILITY_DELAY: 256 -# 2**8 (= 256) epochs ~27 hours -SHARD_COMMITTEE_PERIOD: 256 # 2**2 (= 4) epochs 25.6 minutes MIN_EPOCHS_TO_INACTIVITY_PENALTY: 4 -# State vector lengths +# State list lengths # --------------------------------------------------------------- # 2**16 (= 65,536) epochs ~0.8 years EPOCHS_PER_HISTORICAL_VECTOR: 65536 @@ -140,14 +92,3 @@ MAX_ATTESTATIONS: 128 MAX_DEPOSITS: 16 # 2**4 (= 16) MAX_VOLUNTARY_EXITS: 16 - - -# Signature domains -# --------------------------------------------------------------- -DOMAIN_BEACON_PROPOSER: 0x00000000 -DOMAIN_BEACON_ATTESTER: 0x01000000 -DOMAIN_RANDAO: 0x02000000 -DOMAIN_DEPOSIT: 0x03000000 -DOMAIN_VOLUNTARY_EXIT: 0x04000000 -DOMAIN_SELECTION_PROOF: 0x05000000 -DOMAIN_AGGREGATE_AND_PROOF: 0x06000000 diff --git a/configs/mainnet/sharding.yaml b/presets/mainnet/sharding.yaml similarity index 65% rename from configs/mainnet/sharding.yaml rename to presets/mainnet/sharding.yaml index af7e94f00..9a81c8cdc 100644 --- a/configs/mainnet/sharding.yaml +++ b/presets/mainnet/sharding.yaml @@ -1,12 +1,5 @@ # Mainnet preset - Sharding -# Fork -# --------------------------------------------------------------- -SHARDING_FORK_VERSION: 0x03000000 -# TBD, temporarily max uint64 value: 2**64 - 1 -SHARDING_FORK_EPOCH: 18446744073709551615 - - # Beacon-chain # --------------------------------------------------------------- # Misc @@ -33,8 +26,3 @@ TARGET_SAMPLES_PER_BLOCK: 1024 MAX_GASPRICE: 8589934592 # 2**3 (= 8) Gwei MIN_GASPRICE: 8 - -# Signature domains -# --------------------------------------------------------------- -DOMAIN_SHARD_PROPOSER: 0x80000000 -DOMAIN_SHARD_COMMITTEE: 0x81000000 diff --git a/presets/minimal/altair.yaml b/presets/minimal/altair.yaml new file mode 100644 index 000000000..88d78bea3 --- /dev/null +++ b/presets/minimal/altair.yaml @@ -0,0 +1,24 @@ +# Minimal preset - Altair + +# Updated penalty values +# --------------------------------------------------------------- +# 3 * 2**24 (= 50,331,648) +INACTIVITY_PENALTY_QUOTIENT_ALTAIR: 50331648 +# 2**6 (= 64) +MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR: 64 +# 2 +PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR: 2 + + +# Sync committee +# --------------------------------------------------------------- +# [customized] +SYNC_COMMITTEE_SIZE: 32 +# [customized] +EPOCHS_PER_SYNC_COMMITTEE_PERIOD: 8 + + +# Sync protocol +# --------------------------------------------------------------- +# 1 +MIN_SYNC_COMMITTEE_PARTICIPANTS: 1 diff --git a/configs/minimal/custody_game.yaml b/presets/minimal/custody_game.yaml similarity index 64% rename from configs/minimal/custody_game.yaml rename to presets/minimal/custody_game.yaml index 8b8992fb6..c06fccad4 100644 --- a/configs/minimal/custody_game.yaml +++ b/presets/minimal/custody_game.yaml @@ -13,14 +13,6 @@ CUSTODY_PERIOD_TO_RANDAO_PADDING: 8 # [customize for faster testing] MAX_CHUNK_CHALLENGE_DELAY: 64 -# Misc parameters -# --------------------------------------------------------------- -# 2**256 - 189 -CUSTODY_PRIME: 115792089237316195423570985008687907853269984665640564039457584007913129639747 -# 3 -CUSTODY_SECRETS: 3 -# 1/4 chance of custody bit 1 [customized for faster testing] -CUSTODY_PROBABILITY_EXPONENT: 2 # Max operations # --------------------------------------------------------------- @@ -35,14 +27,9 @@ MAX_CUSTODY_CHUNK_CHALLENGE_RESP: 8 # 2**0 (= 1) MAX_CUSTODY_SLASHINGS: 1 + # Reward and penalty quotients # --------------------------------------------------------------- EARLY_DERIVED_SECRET_REVEAL_SLOT_REWARD_MULTIPLE: 2 # 2**8 (= 256) MINOR_REWARD_QUOTIENT: 256 - -# Signature domains -# --------------------------------------------------------------- -DOMAIN_CUSTODY_BIT_SLASHING: 0x83000000 -DOMAIN_LIGHT_SELECTION_PROOF: 0x84000000 -DOMAIN_LIGHT_AGGREGATE_AND_PROOF: 0x85000000 diff --git a/presets/minimal/merge.yaml b/presets/minimal/merge.yaml new file mode 100644 index 000000000..88aa86c09 --- /dev/null +++ b/presets/minimal/merge.yaml @@ -0,0 +1,3 @@ +# Minimal preset - The Merge + +# No presets here. diff --git a/configs/minimal/phase0.yaml b/presets/minimal/phase0.yaml similarity index 57% rename from configs/minimal/phase0.yaml rename to presets/minimal/phase0.yaml index 3624a2702..c9c81325f 100644 --- a/configs/minimal/phase0.yaml +++ b/presets/minimal/phase0.yaml @@ -1,24 +1,15 @@ -# Minimal preset +# Minimal preset - Phase0 # Misc # --------------------------------------------------------------- - # [customized] Just 4 committees for slot for testing purposes MAX_COMMITTEES_PER_SLOT: 4 # [customized] unsecure, but fast TARGET_COMMITTEE_SIZE: 4 # 2**11 (= 2,048) MAX_VALIDATORS_PER_COMMITTEE: 2048 -# 2**2 (= 4) -MIN_PER_EPOCH_CHURN_LIMIT: 4 -# 2**16 (= 65,536) -CHURN_LIMIT_QUOTIENT: 65536 # [customized] Faster, but unsecure. SHUFFLE_ROUND_COUNT: 10 -# [customized] -MIN_GENESIS_ACTIVE_VALIDATOR_COUNT: 64 -# Jan 3, 2020 -MIN_GENESIS_TIME: 1578009600 # 4 HYSTERESIS_QUOTIENT: 4 # 1 (minus 0.25) @@ -33,54 +24,18 @@ HYSTERESIS_UPWARD_MULTIPLIER: 5 SAFE_SLOTS_TO_UPDATE_JUSTIFIED: 2 -# Validator -# --------------------------------------------------------------- -# [customized] process deposits more quickly, but insecure -ETH1_FOLLOW_DISTANCE: 16 -# 2**4 (= 16) -TARGET_AGGREGATORS_PER_COMMITTEE: 16 -# 2**0 (= 1) -RANDOM_SUBNETS_PER_VALIDATOR: 1 -# 2**8 (= 256) -EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION: 256 -# 14 (estimate from Eth1 mainnet) -SECONDS_PER_ETH1_BLOCK: 14 - - -# Deposit contract -# --------------------------------------------------------------- -# Ethereum Goerli testnet -DEPOSIT_CHAIN_ID: 5 -DEPOSIT_NETWORK_ID: 5 -# Configured on a per testnet basis -DEPOSIT_CONTRACT_ADDRESS: 0x1234567890123456789012345678901234567890 - - # Gwei values # --------------------------------------------------------------- # 2**0 * 10**9 (= 1,000,000,000) Gwei MIN_DEPOSIT_AMOUNT: 1000000000 # 2**5 * 10**9 (= 32,000,000,000) Gwei MAX_EFFECTIVE_BALANCE: 32000000000 -# 2**4 * 10**9 (= 16,000,000,000) Gwei -EJECTION_BALANCE: 16000000000 # 2**0 * 10**9 (= 1,000,000,000) Gwei EFFECTIVE_BALANCE_INCREMENT: 1000000000 -# Initial values -# --------------------------------------------------------------- -# Highest byte set to 0x01 to avoid collisions with mainnet versioning -GENESIS_FORK_VERSION: 0x00000001 -BLS_WITHDRAWAL_PREFIX: 0x00 - - # Time parameters # --------------------------------------------------------------- -# [customized] Faster to spin up testnets, but does not give validator reasonable warning time for genesis -GENESIS_DELAY: 300 -# [customized] Faster for testing purposes -SECONDS_PER_SLOT: 6 # 2**0 (= 1) slots 6 seconds MIN_ATTESTATION_INCLUSION_DELAY: 1 # [customized] fast epochs @@ -93,15 +48,11 @@ MAX_SEED_LOOKAHEAD: 4 EPOCHS_PER_ETH1_VOTING_PERIOD: 4 # [customized] smaller state SLOTS_PER_HISTORICAL_ROOT: 64 -# 2**8 (= 256) epochs -MIN_VALIDATOR_WITHDRAWABILITY_DELAY: 256 -# [customized] higher frequency of committee turnover and faster time to acceptable voluntary exit -SHARD_COMMITTEE_PERIOD: 64 # 2**2 (= 4) epochs MIN_EPOCHS_TO_INACTIVITY_PENALTY: 4 -# State vector lengths +# State list lengths # --------------------------------------------------------------- # [customized] smaller state EPOCHS_PER_HISTORICAL_VECTOR: 64 @@ -141,14 +92,3 @@ MAX_ATTESTATIONS: 128 MAX_DEPOSITS: 16 # 2**4 (= 16) MAX_VOLUNTARY_EXITS: 16 - - -# Signature domains -# --------------------------------------------------------------- -DOMAIN_BEACON_PROPOSER: 0x00000000 -DOMAIN_BEACON_ATTESTER: 0x01000000 -DOMAIN_RANDAO: 0x02000000 -DOMAIN_DEPOSIT: 0x03000000 -DOMAIN_VOLUNTARY_EXIT: 0x04000000 -DOMAIN_SELECTION_PROOF: 0x05000000 -DOMAIN_AGGREGATE_AND_PROOF: 0x06000000 diff --git a/configs/minimal/sharding.yaml b/presets/minimal/sharding.yaml similarity index 67% rename from configs/minimal/sharding.yaml rename to presets/minimal/sharding.yaml index 2db2acffa..7dedbc926 100644 --- a/configs/minimal/sharding.yaml +++ b/presets/minimal/sharding.yaml @@ -1,12 +1,5 @@ # Minimal preset - Sharding -# Fork -# --------------------------------------------------------------- -SHARDING_FORK_VERSION: 0x03000001 -# TBD, temporarily max uint64 value: 2**64 - 1 -SHARDING_FORK_EPOCH: 18446744073709551615 - - # Beacon-chain # --------------------------------------------------------------- # Misc @@ -33,8 +26,3 @@ TARGET_SAMPLES_PER_BLOCK: 1024 MAX_GASPRICE: 8589934592 # 2**3 (= 8) Gwei MIN_GASPRICE: 8 - -# Signature domains -# --------------------------------------------------------------- -DOMAIN_SHARD_PROPOSER: 0x80000000 -DOMAIN_SHARD_COMMITTEE: 0x81000000 diff --git a/setup.py b/setup.py index 0bdf04b55..8095e3b7f 100644 --- a/setup.py +++ b/setup.py @@ -2,16 +2,26 @@ from setuptools import setup, find_packages, Command from setuptools.command.build_py import build_py from distutils import dir_util from distutils.util import convert_path +from pathlib import Path import os import re import string import textwrap -from typing import Dict, NamedTuple, List, Sequence, Optional +from typing import Dict, NamedTuple, List, Sequence, Optional, TypeVar from abc import ABC, abstractmethod import ast # NOTE: have to programmatically include third-party dependencies in `setup.py`. +RUAMEL_YAML_VERSION = "ruamel.yaml==0.16.5" +try: + import ruamel.yaml +except ImportError: + import pip + pip.main(["install", RUAMEL_YAML_VERSION]) + +from ruamel.yaml import YAML + MARKO_VERSION = "marko==1.0.2" try: import marko @@ -30,10 +40,6 @@ PHASE0 = 'phase0' ALTAIR = 'altair' MERGE = 'merge' -CONFIG_LOADER = ''' -apply_constants_config(globals()) -''' - # The helper functions that are used when defining constants CONSTANT_DEP_SUNDRY_CONSTANTS_FUNCTIONS = ''' def ceillog2(x: int) -> uint64: @@ -54,11 +60,19 @@ class ProtocolDefinition(NamedTuple): functions: Dict[str, str] +class VariableDefinition(NamedTuple): + type_name: Optional[str] + value: str + comment: Optional[str] # e.g. "noqa: E501" + + class SpecObject(NamedTuple): functions: Dict[str, str] protocols: Dict[str, ProtocolDefinition] custom_types: Dict[str, str] - constants: Dict[str, str] + constant_vars: Dict[str, VariableDefinition] + preset_vars: Dict[str, VariableDefinition] + config_vars: Dict[str, VariableDefinition] ssz_dep_constants: Dict[str, str] # the constants that depend on ssz_objects ssz_objects: Dict[str, str] dataclasses: Dict[str, str] @@ -124,10 +138,26 @@ def _get_eth2_spec_comment(child: LinkRefDef) -> Optional[str]: return title[len(ETH2_SPEC_COMMENT_PREFIX):].strip() -def get_spec(file_name: str) -> SpecObject: +def _parse_value(name: str, typed_value: str) -> VariableDefinition: + comment = None + if name == "BLS12_381_Q": + comment = "noqa: E501" + + typed_value = typed_value.strip() + if '(' not in typed_value: + return VariableDefinition(type_name=None, value=typed_value, comment=comment) + i = typed_value.index('(') + type_name = typed_value[:i] + + return VariableDefinition(type_name=type_name, value=typed_value[i+1:-1], comment=comment) + + +def get_spec(file_name: Path, preset: Dict[str, str], config: Dict[str, str]) -> SpecObject: functions: Dict[str, str] = {} protocols: Dict[str, ProtocolDefinition] = {} - constants: Dict[str, str] = {} + constant_vars: Dict[str, VariableDefinition] = {} + preset_vars: Dict[str, VariableDefinition] = {} + config_vars: Dict[str, VariableDefinition] = {} ssz_dep_constants: Dict[str, str] = {} ssz_objects: Dict[str, str] = {} dataclasses: Dict[str, str] = {} @@ -178,18 +208,31 @@ def get_spec(file_name: str) -> SpecObject: if len(cells) >= 2: name_cell = cells[0] name = name_cell.children[0].children + value_cell = cells[1] value = value_cell.children[0].children if isinstance(value, list): # marko parses `**X**` as a list containing a X value = value[0].children - if _is_constant_id(name): - if value.startswith("get_generalized_index"): - ssz_dep_constants[name] = value - else: - constants[name] = value.replace("TBD", "2**32") - elif value.startswith("uint") or value.startswith("Bytes") or value.startswith("ByteList"): - custom_types[name] = value + + if not _is_constant_id(name): + # Check for short type declarations + if value.startswith("uint") or value.startswith("Bytes") or value.startswith("ByteList"): + custom_types[name] = value + continue + + if value.startswith("get_generalized_index"): + ssz_dep_constants[name] = value + continue + + value_def = _parse_value(name, value) + if name in preset: + preset_vars[name] = VariableDefinition(value_def.type_name, preset[name], value_def.comment) + elif name in config: + config_vars[name] = VariableDefinition(value_def.type_name, config[name], value_def.comment) + else: + constant_vars[name] = value_def + elif isinstance(child, LinkRefDef): comment = _get_eth2_spec_comment(child) if comment == "skip": @@ -199,7 +242,9 @@ def get_spec(file_name: str) -> SpecObject: functions=functions, protocols=protocols, custom_types=custom_types, - constants=constants, + constant_vars=constant_vars, + preset_vars=preset_vars, + config_vars=config_vars, ssz_dep_constants=ssz_dep_constants, ssz_objects=ssz_objects, dataclasses=dataclasses, @@ -214,7 +259,7 @@ class SpecBuilder(ABC): @classmethod @abstractmethod - def imports(cls) -> str: + def imports(cls, preset_name: str) -> str: """ Import objects from other libraries. """ @@ -246,7 +291,7 @@ class SpecBuilder(ABC): @classmethod @abstractmethod - def hardcoded_custom_type_dep_constants(cls) -> Dict[str, str]: + def hardcoded_custom_type_dep_constants(cls) -> Dict[str, str]: # TODO """ The constants that are required for custom types. """ @@ -262,7 +307,8 @@ class SpecBuilder(ABC): @classmethod @abstractmethod - def build_spec(cls, source_files: List[str]) -> str: + def build_spec(cls, preset_name: str, + source_files: List[Path], preset_files: Sequence[Path], config_file: Path) -> str: raise NotImplementedError() @@ -273,17 +319,16 @@ class Phase0SpecBuilder(SpecBuilder): fork: str = PHASE0 @classmethod - def imports(cls) -> str: + def imports(cls, preset_name: str) -> str: return '''from lru import LRU from dataclasses import ( dataclass, field, ) from typing import ( - Any, Callable, Dict, Set, Sequence, Tuple, Optional, TypeVar + Any, Callable, Dict, Set, Sequence, Tuple, Optional, TypeVar, NamedTuple ) -from eth2spec.config.config_util import apply_constants_config from eth2spec.utils.ssz.ssz_impl import hash_tree_root, copy, uint_to_bytes from eth2spec.utils.ssz.ssz_typing import ( View, boolean, Container, List, Vector, uint8, uint32, uint64, @@ -297,7 +342,6 @@ from eth2spec.utils.hash_function import hash def preparations(cls) -> str: return ''' SSZObject = TypeVar('SSZObject', bound=View) -CONFIG_NAME = 'mainnet' ''' @classmethod @@ -386,8 +430,9 @@ get_attesting_indices = cache_this( return '' @classmethod - def build_spec(cls, source_files: Sequence[str]) -> str: - return _build_spec(cls.fork, source_files) + def build_spec(cls, preset_name: str, + source_files: Sequence[Path], preset_files: Sequence[Path], config_file: Path) -> str: + return _build_spec(preset_name, cls.fork, source_files, preset_files, config_file) # @@ -397,21 +442,17 @@ class AltairSpecBuilder(Phase0SpecBuilder): fork: str = ALTAIR @classmethod - def imports(cls) -> str: - return super().imports() + '\n' + ''' + def imports(cls, preset_name: str) -> str: + return super().imports(preset_name) + '\n' + f''' from typing import NewType, Union -from importlib import reload -from eth2spec.phase0 import spec as phase0 +from eth2spec.phase0 import {preset_name} as phase0 from eth2spec.utils.ssz.ssz_typing import Path ''' @classmethod def preparations(cls): return super().preparations() + '\n' + ''' -# Whenever this spec version is loaded, make sure we have the latest phase0 -reload(phase0) - SSZVariableName = str GeneralizedIndex = NewType('GeneralizedIndex', int) ''' @@ -449,19 +490,16 @@ class MergeSpecBuilder(Phase0SpecBuilder): fork: str = MERGE @classmethod - def imports(cls): - return super().imports() + ''' + def imports(cls, preset_name: str): + return super().imports(preset_name) + f''' from typing import Protocol -from eth2spec.phase0 import spec as phase0 +from eth2spec.phase0 import {preset_name} as phase0 from eth2spec.utils.ssz.ssz_typing import Bytes20, ByteList, ByteVector, uint256 -from importlib import reload ''' @classmethod def preparations(cls): - return super().preparations() + '\n' + ''' -reload(phase0) -''' + return super().preparations() @classmethod def sundry_functions(cls) -> str: @@ -470,7 +508,8 @@ ExecutionState = Any def get_pow_block(hash: Bytes32) -> PowBlock: - return PowBlock(block_hash=hash, is_valid=True, is_processed=True, total_difficulty=TRANSITION_TOTAL_DIFFICULTY) + return PowBlock(block_hash=hash, is_valid=True, is_processed=True, + total_difficulty=config.TRANSITION_TOTAL_DIFFICULTY) def get_execution_state(execution_state_root: Bytes32) -> ExecutionState: @@ -513,7 +552,10 @@ spec_builders = { } -def objects_to_spec(spec_object: SpecObject, builder: SpecBuilder, ordered_class_objects: Dict[str, str]) -> str: +def objects_to_spec(preset_name: str, + spec_object: SpecObject, + builder: SpecBuilder, + ordered_class_objects: Dict[str, str]) -> str: """ Given all the objects that constitute a spec, combine them into a single pyfile. """ @@ -547,16 +589,46 @@ def objects_to_spec(spec_object: SpecObject, builder: SpecBuilder, ordered_class if "ceillog2" in k or "floorlog2" in k: del spec_object.functions[k] functions_spec = '\n\n\n'.join(spec_object.functions.values()) - for k in list(spec_object.constants.keys()): - if k == "BLS12_381_Q": - spec_object.constants[k] += " # noqa: E501" - constants_spec = '\n'.join(map(lambda x: '%s = %s' % (x, spec_object.constants[x]), spec_object.constants)) + + # Access global dict of config vars for runtime configurables + for name in spec_object.config_vars.keys(): + functions_spec = functions_spec.replace(name, 'config.' + name) + + def format_config_var(name: str, vardef: VariableDefinition) -> str: + if vardef.type_name is None: + out = f'{name}={vardef.value}' + else: + out = f'{name}={vardef.type_name}({vardef.value}),' + if vardef.comment is not None: + out += f' # {vardef.comment}' + return out + + config_spec = 'class Configuration(NamedTuple):\n' + config_spec += ' PRESET_BASE: str\n' + config_spec += '\n'.join(f' {k}: {v.type_name if v.type_name is not None else "int"}' + for k, v in spec_object.config_vars.items()) + config_spec += '\n\n\nconfig = Configuration(\n' + config_spec += f' PRESET_BASE="{preset_name}",\n' + config_spec += '\n'.join(' ' + format_config_var(k, v) for k, v in spec_object.config_vars.items()) + config_spec += '\n)\n' + + def format_constant(name: str, vardef: VariableDefinition) -> str: + if vardef.type_name is None: + out = f'{name} = {vardef.value}' + else: + out = f'{name} = {vardef.type_name}({vardef.value})' + if vardef.comment is not None: + out += f' # {vardef.comment}' + return out + + constant_vars_spec = '# Constant vars\n' + '\n'.join(format_constant(k, v) for k, v in spec_object.constant_vars.items()) + preset_vars_spec = '# Preset vars\n' + '\n'.join(format_constant(k, v) for k, v in spec_object.preset_vars.items()) ordered_class_objects_spec = '\n\n\n'.join(ordered_class_objects.values()) ssz_dep_constants = '\n'.join(map(lambda x: '%s = %s' % (x, builder.hardcoded_ssz_dep_constants()[x]), builder.hardcoded_ssz_dep_constants())) ssz_dep_constants_verification = '\n'.join(map(lambda x: 'assert %s == %s' % (x, spec_object.ssz_dep_constants[x]), builder.hardcoded_ssz_dep_constants())) custom_type_dep_constants = '\n'.join(map(lambda x: '%s = %s' % (x, builder.hardcoded_custom_type_dep_constants()[x]), builder.hardcoded_custom_type_dep_constants())) spec = ( - builder.imports() + builder.imports(preset_name) + builder.preparations() + '\n\n' + f"fork = \'{builder.fork}\'\n" # The constants that some SSZ containers require. Need to be defined before `new_type_definitions` @@ -565,8 +637,9 @@ def objects_to_spec(spec_object: SpecObject, builder: SpecBuilder, ordered_class + '\n' + CONSTANT_DEP_SUNDRY_CONSTANTS_FUNCTIONS # The constants that some SSZ containers require. Need to be defined before `constants_spec` + ('\n\n' + ssz_dep_constants if ssz_dep_constants != '' else '') - + '\n\n' + constants_spec - + '\n\n' + CONFIG_LOADER + + '\n\n' + constant_vars_spec + + '\n\n' + preset_vars_spec + + '\n\n\n' + config_spec + '\n\n' + ordered_class_objects_spec + ('\n\n\n' + protocols_spec if protocols_spec != '' else '') + '\n\n\n' + functions_spec @@ -586,21 +659,16 @@ def combine_protocols(old_protocols: Dict[str, ProtocolDefinition], if key not in old_protocols: old_protocols[key] = value else: - functions = combine_functions(old_protocols[key].functions, value.functions) + functions = combine_dicts(old_protocols[key].functions, value.functions) old_protocols[key] = ProtocolDefinition(functions=functions) return old_protocols -def combine_functions(old_functions: Dict[str, str], new_functions: Dict[str, str]) -> Dict[str, str]: - for key, value in new_functions.items(): - old_functions[key] = value - return old_functions +T = TypeVar('T') -def combine_constants(old_constants: Dict[str, str], new_constants: Dict[str, str]) -> Dict[str, str]: - for key, value in new_constants.items(): - old_constants[key] = value - return old_constants +def combine_dicts(old_dict: Dict[str, T], new_dict: Dict[str, T]) -> Dict[str, T]: + return {**old_dict, **new_dict} ignored_dependencies = [ @@ -649,28 +717,75 @@ def combine_spec_objects(spec0: SpecObject, spec1: SpecObject) -> SpecObject: """ Takes in two spec variants (as tuples of their objects) and combines them using the appropriate combiner function. """ - functions0, protocols0, custom_types0, constants0, ssz_dep_constants0, ssz_objects0, dataclasses0 = spec0 - functions1, protocols1, custom_types1, constants1, ssz_dep_constants1, ssz_objects1, dataclasses1 = spec1 - protocols = combine_protocols(protocols0, protocols1) - functions = combine_functions(functions0, functions1) - custom_types = combine_constants(custom_types0, custom_types1) - constants = combine_constants(constants0, constants1) - ssz_dep_constants = combine_constants(ssz_dep_constants0, ssz_dep_constants1) - ssz_objects = combine_ssz_objects(ssz_objects0, ssz_objects1, custom_types) - dataclasses = combine_functions(dataclasses0, dataclasses1) + protocols = combine_protocols(spec0.protocols, spec1.protocols) + functions = combine_dicts(spec0.functions, spec1.functions) + custom_types = combine_dicts(spec0.custom_types, spec1.custom_types) + constant_vars = combine_dicts(spec0.constant_vars, spec1.constant_vars) + preset_vars = combine_dicts(spec0.preset_vars, spec1.preset_vars) + config_vars = combine_dicts(spec0.config_vars, spec1.config_vars) + ssz_dep_constants = combine_dicts(spec0.ssz_dep_constants, spec1.ssz_dep_constants) + ssz_objects = combine_ssz_objects(spec0.ssz_objects, spec1.ssz_objects, custom_types) + dataclasses = combine_dicts(spec0.dataclasses, spec1.dataclasses) return SpecObject( functions=functions, protocols=protocols, custom_types=custom_types, - constants=constants, + constant_vars=constant_vars, + preset_vars=preset_vars, + config_vars=config_vars, ssz_dep_constants=ssz_dep_constants, ssz_objects=ssz_objects, dataclasses=dataclasses, ) -def _build_spec(fork: str, source_files: Sequence[str]) -> str: - all_specs = [get_spec(spec) for spec in source_files] +def parse_config_vars(conf: Dict[str, str]) -> Dict[str, str]: + """ + Parses a dict of basic str/int/list types into a dict for insertion into the spec code. + """ + out: Dict[str, str] = dict() + for k, v in conf.items(): + if isinstance(v, str) and (v.startswith("0x") or k == 'PRESET_BASE'): + # Represent byte data with string, to avoid misinterpretation as big-endian int. + # Everything is either byte data or an integer, with PRESET_BASE as one exception. + out[k] = f"'{v}'" + else: + out[k] = str(int(v)) + return out + + +def load_preset(preset_files: Sequence[Path]) -> Dict[str, str]: + """ + Loads the a directory of preset files, merges the result into one preset. + """ + preset = {} + for fork_file in preset_files: + yaml = YAML(typ='base') + fork_preset: dict = yaml.load(fork_file) + if fork_preset is None: # for empty YAML files + continue + if not set(fork_preset.keys()).isdisjoint(preset.keys()): + duplicates = set(fork_preset.keys()).intersection(set(preset.keys())) + raise Exception(f"duplicate config var(s) in preset files: {', '.join(duplicates)}") + preset.update(fork_preset) + assert preset != {} + return parse_config_vars(preset) + + +def load_config(config_path: Path) -> Dict[str, str]: + """ + Loads the given configuration file. + """ + yaml = YAML(typ='base') + config_data = yaml.load(config_path) + return parse_config_vars(config_data) + + +def _build_spec(preset_name: str, fork: str, + source_files: Sequence[Path], preset_files: Sequence[Path], config_file: Path) -> str: + preset = load_preset(preset_files) + config = load_config(config_file) + all_specs = [get_spec(spec, preset, config) for spec in source_files] spec_object = all_specs[0] for value in all_specs[1:]: @@ -679,7 +794,13 @@ def _build_spec(fork: str, source_files: Sequence[str]) -> str: class_objects = {**spec_object.ssz_objects, **spec_object.dataclasses} dependency_order_class_objects(class_objects, spec_object.custom_types) - return objects_to_spec(spec_object, spec_builders[fork], class_objects) + return objects_to_spec(preset_name, spec_object, spec_builders[fork], class_objects) + + +class BuildTarget(NamedTuple): + name: str + preset_paths: List[Path] + config_path: Path class PySpecCommand(Command): @@ -690,12 +811,15 @@ class PySpecCommand(Command): spec_fork: str md_doc_paths: str parsed_md_doc_paths: List[str] + build_targets: str + parsed_build_targets: List[BuildTarget] out_dir: str # The format is (long option, short option, description). user_options = [ ('spec-fork=', None, "Spec fork to tag build with. Used to select md-docs defaults."), ('md-doc-paths=', None, "List of paths of markdown files to build spec with"), + ('build-targets=', None, "Names, directory paths of compile-time presets, and default config paths."), ('out-dir=', None, "Output directory to write spec package to") ] @@ -705,6 +829,10 @@ class PySpecCommand(Command): self.spec_fork = PHASE0 self.md_doc_paths = '' self.out_dir = 'pyspec_output' + self.build_targets = """ + minimal:presets/minimal:configs/minimal.yaml + mainnet:presets/mainnet:configs/mainnet.yaml + """ def finalize_options(self): """Post-process options.""" @@ -749,16 +877,40 @@ class PySpecCommand(Command): if not os.path.exists(filename): raise Exception('Pyspec markdown input file "%s" does not exist.' % filename) + self.parsed_build_targets = [] + for target in self.build_targets.split(): + target = target.strip() + data = target.split(':') + if len(data) != 3: + raise Exception('invalid target, expected "name:preset_dir:config_file" format, but got: %s' % target) + name, preset_dir_path, config_path = data + if any((c not in string.digits + string.ascii_letters) for c in name): + raise Exception('invalid target name: "%s"' % name) + if not os.path.exists(preset_dir_path): + raise Exception('Preset dir "%s" does not exist' % preset_dir_path) + _, _, preset_file_names = next(os.walk(preset_dir_path)) + preset_paths = [(Path(preset_dir_path) / name) for name in preset_file_names] + + if not os.path.exists(config_path): + raise Exception('Config file "%s" does not exist' % config_path) + self.parsed_build_targets.append(BuildTarget(name, preset_paths, Path(config_path))) + def run(self): - spec_str = spec_builders[self.spec_fork].build_spec(self.parsed_md_doc_paths) - if self.dry_run: - self.announce('dry run successfully prepared contents for spec.' - f' out dir: "{self.out_dir}", spec fork: "{self.spec_fork}"') - self.debug_print(spec_str) - else: + if not self.dry_run: dir_util.mkpath(self.out_dir) - with open(os.path.join(self.out_dir, 'spec.py'), 'w') as out: - out.write(spec_str) + + for (name, preset_paths, config_path) in self.parsed_build_targets: + spec_str = spec_builders[self.spec_fork].build_spec( + name, self.parsed_md_doc_paths, preset_paths, config_path) + if self.dry_run: + self.announce('dry run successfully prepared contents for spec.' + f' out dir: "{self.out_dir}", spec fork: "{self.spec_fork}", build target: "{name}"') + self.debug_print(spec_str) + else: + with open(os.path.join(self.out_dir, name+'.py'), 'w') as out: + out.write(spec_str) + + if not self.dry_run: with open(os.path.join(self.out_dir, '__init__.py'), 'w') as out: out.write("") @@ -839,11 +991,13 @@ setup( url="https://github.com/ethereum/eth2.0-specs", include_package_data=False, package_data={'configs': ['*.yaml'], + 'presets': ['*.yaml'], 'specs': ['**/*.md'], 'eth2spec': ['VERSION.txt']}, package_dir={ "eth2spec": "tests/core/pyspec/eth2spec", "configs": "configs", + "presets": "presets", "specs": "specs", }, packages=find_packages(where='tests/core/pyspec') + ['configs', 'specs'], @@ -863,8 +1017,8 @@ setup( "milagro_bls_binding==1.6.3", "dataclasses==0.6", "remerkleable==0.1.19", - "ruamel.yaml==0.16.5", + RUAMEL_YAML_VERSION, "lru-dict==1.1.6", - "marko==1.0.2", + MARKO_VERSION, ] ) diff --git a/specs/altair/beacon-chain.md b/specs/altair/beacon-chain.md index 17d1efc51..7412a8490 100644 --- a/specs/altair/beacon-chain.md +++ b/specs/altair/beacon-chain.md @@ -11,12 +11,13 @@ - [Constants](#constants) - [Participation flag indices](#participation-flag-indices) - [Incentivization weights](#incentivization-weights) + - [Domain types](#domain-types) - [Misc](#misc) -- [Configuration](#configuration) +- [Preset](#preset) - [Updated penalty values](#updated-penalty-values) - [Sync committee](#sync-committee) - - [Misc](#misc-1) - - [Domain types](#domain-types) +- [Configuration](#configuration) + - [Inactivity penalties](#inactivity-penalties) - [Containers](#containers) - [Modified containers](#modified-containers) - [`BeaconBlockBody`](#beaconblockbody) @@ -27,7 +28,7 @@ - [Helper functions](#helper-functions) - [`Predicates`](#predicates) - [`eth2_fast_aggregate_verify`](#eth2_fast_aggregate_verify) - - [Misc](#misc-2) + - [Misc](#misc-1) - [`add_flag`](#add_flag) - [`has_flag`](#has_flag) - [Beacon state accessors](#beacon-state-accessors) @@ -94,6 +95,14 @@ Altair is the first beacon chain hard fork. Its main features are: *Note*: The sum of the weights equal `WEIGHT_DENOMINATOR`. +### Domain types + +| Name | Value | +| - | - | +| `DOMAIN_SYNC_COMMITTEE` | `DomainType('0x07000000')` | +| `DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF` | `DomainType('0x08000000')` | +| `DOMAIN_CONTRIBUTION_AND_PROOF` | `DomainType('0x09000000')` | + ### Misc | Name | Value | @@ -101,7 +110,7 @@ Altair is the first beacon chain hard fork. Its main features are: | `G2_POINT_AT_INFINITY` | `BLSSignature(b'\xc0' + b'\x00' * 95)` | | `PARTICIPATION_FLAG_WEIGHTS` | `[TIMELY_SOURCE_WEIGHT, TIMELY_TARGET_WEIGHT, TIMELY_HEAD_WEIGHT]` | -## Configuration +## Preset ### Updated penalty values @@ -122,20 +131,14 @@ This patch updates a few configuration values to move penalty parameters closer | `SYNC_COMMITTEE_SIZE` | `uint64(2**9)` (= 512) | Validators | | | `EPOCHS_PER_SYNC_COMMITTEE_PERIOD` | `uint64(2**9)` (= 512) | epochs | ~54 hours | -### Misc +## Configuration -| Name | Value | -| - | - | -| `INACTIVITY_SCORE_BIAS` | `uint64(4)` | -| `INACTIVITY_SCORE_RECOVERY_RATE` | `uint64(16)` | +### Inactivity penalties -### Domain types - -| Name | Value | -| - | - | -| `DOMAIN_SYNC_COMMITTEE` | `DomainType('0x07000000')` | -| `DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF` | `DomainType('0x08000000')` | -| `DOMAIN_CONTRIBUTION_AND_PROOF` | `DomainType('0x09000000')` | +| Name | Value | Description | +| - | - | - | +| `INACTIVITY_SCORE_BIAS` | `uint64(4)` | score points per inactive epoch | +| `INACTIVITY_SCORE_RECOVERY_RATE` | `uint64(16)` | score points per recovering epoch | ## Containers diff --git a/specs/altair/sync-protocol.md b/specs/altair/sync-protocol.md index 784ea63b2..119d0f998 100644 --- a/specs/altair/sync-protocol.md +++ b/specs/altair/sync-protocol.md @@ -10,7 +10,7 @@ - [Introduction](#introduction) - [Constants](#constants) -- [Configuration](#configuration) +- [Preset](#preset) - [Misc](#misc) - [Containers](#containers) - [`LightClientSnapshot`](#lightclientsnapshot) @@ -43,7 +43,7 @@ uses sync committees introduced in [this beacon chain extension](./beacon-chain. | `FINALIZED_ROOT_INDEX` | `get_generalized_index(BeaconState, 'finalized_checkpoint', 'root')` | | `NEXT_SYNC_COMMITTEE_INDEX` | `get_generalized_index(BeaconState, 'next_sync_committee')` | -## Configuration +## Preset ### Misc diff --git a/specs/custody_game/beacon-chain.md b/specs/custody_game/beacon-chain.md index ca123f5aa..ad99527f7 100644 --- a/specs/custody_game/beacon-chain.md +++ b/specs/custody_game/beacon-chain.md @@ -71,7 +71,13 @@ building upon the [Sharding](../sharding/beacon-chain.md) specification. | `BYTES_PER_CUSTODY_ATOM` | `uint64(32)` | bytes | | `CUSTODY_PROBABILITY_EXPONENT` | `uint64(10)` | - | -## Configuration +### Domain types + +| Name | Value | +| - | - | +| `DOMAIN_CUSTODY_BIT_SLASHING` | `DomainType('0x83000000')` | + +## Preset ### Time parameters diff --git a/specs/merge/beacon-chain.md b/specs/merge/beacon-chain.md index 85953a547..ada6c1a25 100644 --- a/specs/merge/beacon-chain.md +++ b/specs/merge/beacon-chain.md @@ -15,6 +15,7 @@ - [Constants](#constants) - [Execution](#execution) - [Configuration](#configuration) + - [Transition](#transition) - [Containers](#containers) - [Extended containers](#extended-containers) - [`BeaconBlockBody`](#beaconblockbody) @@ -65,6 +66,8 @@ We define the following Python custom types for type hinting and readability: Warning: this configuration is not definitive. +### Transition + | Name | Value | | - | - | | `MERGE_FORK_VERSION` | `Version('0x02000000')` | diff --git a/specs/phase0/beacon-chain.md b/specs/phase0/beacon-chain.md index 3176d543c..0169e2725 100644 --- a/specs/phase0/beacon-chain.md +++ b/specs/phase0/beacon-chain.md @@ -9,16 +9,20 @@ - [Notation](#notation) - [Custom types](#custom-types) - [Constants](#constants) -- [Configuration](#configuration) - [Misc](#misc) - - [Gwei values](#gwei-values) - - [Initial values](#initial-values) - [Withdrawal prefixes](#withdrawal-prefixes) + - [Domain types](#domain-types) +- [Preset](#preset) + - [Misc](#misc-1) + - [Gwei values](#gwei-values) - [Time parameters](#time-parameters) - [State list lengths](#state-list-lengths) - [Rewards and penalties](#rewards-and-penalties) - [Max operations per block](#max-operations-per-block) - - [Domain types](#domain-types) +- [Configuration](#configuration) + - [Genesis settings](#genesis-settings) + - [Time parameters](#time-parameters-1) + - [Validator cycle](#validator-cycle) - [Containers](#containers) - [Misc dependencies](#misc-dependencies) - [`Fork`](#fork) @@ -67,7 +71,7 @@ - [`is_slashable_attestation_data`](#is_slashable_attestation_data) - [`is_valid_indexed_attestation`](#is_valid_indexed_attestation) - [`is_valid_merkle_branch`](#is_valid_merkle_branch) - - [Misc](#misc-1) + - [Misc](#misc-2) - [`compute_shuffled_index`](#compute_shuffled_index) - [`compute_proposer_index`](#compute_proposer_index) - [`compute_committee`](#compute_committee) @@ -170,6 +174,8 @@ We define the following Python custom types for type hinting and readability: The following values are (non-configurable) constants used throughout the specification. +### Misc + | Name | Value | | - | - | | `GENESIS_SLOT` | `Slot(0)` | @@ -180,23 +186,39 @@ The following values are (non-configurable) constants used throughout the specif | `JUSTIFICATION_BITS_LENGTH` | `uint64(4)` | | `ENDIANNESS` | `'little'` | -## Configuration +### Withdrawal prefixes -*Note*: The default mainnet configuration values are included here for illustrative purposes. The different configurations for mainnet, testnets, and YAML-based testing can be found in the [`configs/constant_presets`](../../configs) directory. +| Name | Value | +| - | - | +| `BLS_WITHDRAWAL_PREFIX` | `Bytes1('0x00')` | +| `ETH1_ADDRESS_WITHDRAWAL_PREFIX` | `Bytes1('0x01')` | + +### Domain types + +| Name | Value | +| - | - | +| `DOMAIN_BEACON_PROPOSER` | `DomainType('0x00000000')` | +| `DOMAIN_BEACON_ATTESTER` | `DomainType('0x01000000')` | +| `DOMAIN_RANDAO` | `DomainType('0x02000000')` | +| `DOMAIN_DEPOSIT` | `DomainType('0x03000000')` | +| `DOMAIN_VOLUNTARY_EXIT` | `DomainType('0x04000000')` | +| `DOMAIN_SELECTION_PROOF` | `DomainType('0x05000000')` | +| `DOMAIN_AGGREGATE_AND_PROOF` | `DomainType('0x06000000')` | + +## Preset + +*Note*: The below configuration is bundled as a preset: a bundle of configuration variables which are expected to differ +between different modes of operation, e.g. testing, but not generally between different networks. +Additional preset configurations can be found in the [`configs`](../../configs) directory. ### Misc | Name | Value | | - | - | -| `ETH1_FOLLOW_DISTANCE` | `uint64(2**11)` (= 2,048) | | `MAX_COMMITTEES_PER_SLOT` | `uint64(2**6)` (= 64) | | `TARGET_COMMITTEE_SIZE` | `uint64(2**7)` (= 128) | | `MAX_VALIDATORS_PER_COMMITTEE` | `uint64(2**11)` (= 2,048) | -| `MIN_PER_EPOCH_CHURN_LIMIT` | `uint64(2**2)` (= 4) | -| `CHURN_LIMIT_QUOTIENT` | `uint64(2**16)` (= 65,536) | | `SHUFFLE_ROUND_COUNT` | `uint64(90)` | -| `MIN_GENESIS_ACTIVE_VALIDATOR_COUNT` | `uint64(2**14)` (= 16,384) | -| `MIN_GENESIS_TIME` | `uint64(1606824000)` (Dec 1, 2020, 12pm UTC) | | `HYSTERESIS_QUOTIENT` | `uint64(4)` | | `HYSTERESIS_DOWNWARD_MULTIPLIER` | `uint64(1)` | | `HYSTERESIS_UPWARD_MULTIPLIER` | `uint64(5)` | @@ -209,29 +231,12 @@ The following values are (non-configurable) constants used throughout the specif | - | - | | `MIN_DEPOSIT_AMOUNT` | `Gwei(2**0 * 10**9)` (= 1,000,000,000) | | `MAX_EFFECTIVE_BALANCE` | `Gwei(2**5 * 10**9)` (= 32,000,000,000) | -| `EJECTION_BALANCE` | `Gwei(2**4 * 10**9)` (= 16,000,000,000) | | `EFFECTIVE_BALANCE_INCREMENT` | `Gwei(2**0 * 10**9)` (= 1,000,000,000) | -### Initial values - -| Name | Value | -| - | - | -| `GENESIS_FORK_VERSION` | `Version('0x00000000')` | - -### Withdrawal prefixes - -| Name | Value | -| - | - | -| `BLS_WITHDRAWAL_PREFIX` | `Bytes1('0x00')` | -| `ETH1_ADDRESS_WITHDRAWAL_PREFIX` | `Bytes1('0x01')` | - ### Time parameters | Name | Value | Unit | Duration | | - | - | :-: | :-: | -| `GENESIS_DELAY` | `uint64(604800)` | seconds | 7 days | -| `SECONDS_PER_SLOT` | `uint64(12)` | seconds | 12 seconds | -| `SECONDS_PER_ETH1_BLOCK` | `uint64(14)` | seconds | 14 seconds | | `MIN_ATTESTATION_INCLUSION_DELAY` | `uint64(2**0)` (= 1) | slots | 12 seconds | | `SLOTS_PER_EPOCH` | `uint64(2**5)` (= 32) | slots | 6.4 minutes | | `MIN_SEED_LOOKAHEAD` | `uint64(2**0)` (= 1) | epochs | 6.4 minutes | @@ -239,8 +244,6 @@ The following values are (non-configurable) constants used throughout the specif | `MIN_EPOCHS_TO_INACTIVITY_PENALTY` | `uint64(2**2)` (= 4) | epochs | 25.6 minutes | | `EPOCHS_PER_ETH1_VOTING_PERIOD` | `uint64(2**6)` (= 64) | epochs | ~6.8 hours | | `SLOTS_PER_HISTORICAL_ROOT` | `uint64(2**13)` (= 8,192) | slots | ~27 hours | -| `MIN_VALIDATOR_WITHDRAWABILITY_DELAY` | `uint64(2**8)` (= 256) | epochs | ~27 hours | -| `SHARD_COMMITTEE_PERIOD` | `uint64(2**8)` (= 256) | epochs | ~27 hours | ### State list lengths @@ -276,17 +279,38 @@ The following values are (non-configurable) constants used throughout the specif | `MAX_DEPOSITS` | `2**4` (= 16) | | `MAX_VOLUNTARY_EXITS` | `2**4` (= 16) | -### Domain types +## Configuration + +*Note*: The default mainnet configuration values are included here for illustrative purposes. +Defaults for this more dynamic type of configuration are available with the presets in the [`configs`](../../configs) directory. +Testnets and other types of chain instances may use a different configuration. + +### Genesis settings | Name | Value | | - | - | -| `DOMAIN_BEACON_PROPOSER` | `DomainType('0x00000000')` | -| `DOMAIN_BEACON_ATTESTER` | `DomainType('0x01000000')` | -| `DOMAIN_RANDAO` | `DomainType('0x02000000')` | -| `DOMAIN_DEPOSIT` | `DomainType('0x03000000')` | -| `DOMAIN_VOLUNTARY_EXIT` | `DomainType('0x04000000')` | -| `DOMAIN_SELECTION_PROOF` | `DomainType('0x05000000')` | -| `DOMAIN_AGGREGATE_AND_PROOF` | `DomainType('0x06000000')` | +| `MIN_GENESIS_ACTIVE_VALIDATOR_COUNT` | `uint64(2**14)` (= 16,384) | +| `MIN_GENESIS_TIME` | `uint64(1606824000)` (Dec 1, 2020, 12pm UTC) | +| `GENESIS_FORK_VERSION` | `Version('0x00000000')` | +| `GENESIS_DELAY` | `uint64(604800)` (7 days) | + +### Time parameters + +| Name | Value | Unit | Duration | +| - | - | :-: | :-: | +| `SECONDS_PER_SLOT` | `uint64(12)` | seconds | 12 seconds | +| `SECONDS_PER_ETH1_BLOCK` | `uint64(14)` | seconds | 14 seconds | +| `MIN_VALIDATOR_WITHDRAWABILITY_DELAY` | `uint64(2**8)` (= 256) | epochs | ~27 hours | +| `SHARD_COMMITTEE_PERIOD` | `uint64(2**8)` (= 256) | epochs | ~27 hours | +| `ETH1_FOLLOW_DISTANCE` | `uint64(2**11)` (= 2,048) | Eth1 blocks | ~8 hours | + +### Validator cycle + +| Name | Value | +| - | - | +| `EJECTION_BALANCE` | `Gwei(2**4 * 10**9)` (= 16,000,000,000) | +| `MIN_PER_EPOCH_CHURN_LIMIT` | `uint64(2**2)` (= 4) | +| `CHURN_LIMIT_QUOTIENT` | `uint64(2**16)` (= 65,536) | ## Containers @@ -1556,7 +1580,10 @@ def process_registry_updates(state: BeaconState) -> None: if is_eligible_for_activation_queue(validator): validator.activation_eligibility_epoch = get_current_epoch(state) + 1 - if is_active_validator(validator, get_current_epoch(state)) and validator.effective_balance <= EJECTION_BALANCE: + if ( + is_active_validator(validator, get_current_epoch(state)) + and validator.effective_balance <= EJECTION_BALANCE + ): initiate_validator_exit(state, ValidatorIndex(index)) # Queue validators eligible for activation and not yet dequeued for activation diff --git a/specs/phase0/fork-choice.md b/specs/phase0/fork-choice.md index b5689ecd2..181a874fb 100644 --- a/specs/phase0/fork-choice.md +++ b/specs/phase0/fork-choice.md @@ -7,7 +7,7 @@ - [Introduction](#introduction) - [Fork choice](#fork-choice) - - [Configuration](#configuration) + - [Preset](#preset) - [Helpers](#helpers) - [`LatestMessage`](#latestmessage) - [`Store`](#store) @@ -55,7 +55,7 @@ Any of the above handlers that trigger an unhandled exception (e.g. a failed ass 4) **Manual forks**: Manual forks may arbitrarily change the fork choice rule but are expected to be enacted at epoch transitions, with the fork details reflected in `state.fork`. 5) **Implementation**: The implementation found in this specification is constructed for ease of understanding rather than for optimization in computation, space, or any other resource. A number of optimized alternatives can be found [here](https://github.com/protolambda/lmd-ghost). -### Configuration +### Preset | Name | Value | Unit | Duration | | - | - | :-: | :-: | diff --git a/specs/sharding/beacon-chain.md b/specs/sharding/beacon-chain.md index 8512e15d9..5522e044d 100644 --- a/specs/sharding/beacon-chain.md +++ b/specs/sharding/beacon-chain.md @@ -11,12 +11,14 @@ - [Introduction](#introduction) - [Custom types](#custom-types) - [Constants](#constants) -- [Configuration](#configuration) - [Misc](#misc) - - [Shard block configs](#shard-block-configs) + - [Domain types](#domain-types) +- [Preset](#preset) + - [Misc](#misc-1) + - [Shard block samples](#shard-block-samples) - [Precomputed size verification points](#precomputed-size-verification-points) - [Gwei values](#gwei-values) - - [Domain types](#domain-types) +- [Configuration](#configuration) - [Updated containers](#updated-containers) - [`AttestationData`](#attestationdata) - [`BeaconBlockBody`](#beaconblockbody) @@ -31,7 +33,7 @@ - [`SignedShardBlobReference`](#signedshardblobreference) - [`ShardProposerSlashing`](#shardproposerslashing) - [Helper functions](#helper-functions) - - [Misc](#misc-1) + - [Misc](#misc-2) - [`next_power_of_two`](#next_power_of_two) - [`compute_previous_slot`](#compute_previous_slot) - [`compute_updated_gasprice`](#compute_updated_gasprice) @@ -81,6 +83,8 @@ We define the following Python custom types for type hinting and readability: The following values are (non-configurable) constants used throughout the specification. +### Misc + | Name | Value | Notes | | - | - | - | | `PRIMITIVE_ROOT_OF_UNITY` | `5` | Primitive root of unity of the BLS12_381 (inner) modulus | @@ -88,19 +92,25 @@ The following values are (non-configurable) constants used throughout the specif | `POINTS_PER_SAMPLE` | `uint64(2**3)` (= 8) | 31 * 8 = 248 bytes | | `MODULUS` | `0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001` (curve order of BLS12_381) | -## Configuration +### Domain types + +| Name | Value | +| - | - | +| `DOMAIN_SHARD_PROPOSER` | `DomainType('0x80000000')` | +| `DOMAIN_SHARD_COMMITTEE` | `DomainType('0x81000000')` | + +## Preset ### Misc | Name | Value | Notes | | - | - | - | | `MAX_SHARDS` | `uint64(2**10)` (= 1,024) | Theoretical max shard count (used to determine data structure sizes) | -| `INITIAL_ACTIVE_SHARDS` | `uint64(2**6)` (= 64) | Initial shard count | | `GASPRICE_ADJUSTMENT_COEFFICIENT` | `uint64(2**3)` (= 8) | Gasprice may decrease/increase by at most exp(1 / this value) *per epoch* | -| `MAX_SHARD_HEADERS_PER_SHARD` | `4` | | | `MAX_SHARD_PROPOSER_SLASHINGS` | `2**4` (= 16) | Maximum amount of shard proposer slashing operations per block | +| `MAX_SHARD_HEADERS_PER_SHARD` | `4` | | -### Shard block configs +### Shard block samples | Name | Value | Notes | | - | - | - | @@ -122,12 +132,11 @@ The following values are (non-configurable) constants used throughout the specif | `MAX_GASPRICE` | `Gwei(2**33)` (= 8,589,934,592) | Gwei | Max gasprice charged for a TARGET-sized shard block | | `MIN_GASPRICE` | `Gwei(2**3)` (= 8) | Gwei | Min gasprice charged for a TARGET-sized shard block | -### Domain types +## Configuration -| Name | Value | -| - | - | -| `DOMAIN_SHARD_PROPOSER` | `DomainType('0x80000000')` | -| `DOMAIN_SHARD_COMMITTEE` | `DomainType('0x81000000')` | +| Name | Value | Notes | +| - | - | - | +| `INITIAL_ACTIVE_SHARDS` | `uint64(2**6)` (= 64) | Initial shard count | ## Updated containers diff --git a/tests/core/pyspec/README.md b/tests/core/pyspec/README.md index 33695a223..4a4e20854 100644 --- a/tests/core/pyspec/README.md +++ b/tests/core/pyspec/README.md @@ -57,21 +57,22 @@ Caveats: Full test usage, with explicit configuration for illustration of options usage: ```shell -(venv) python -m pytest --config=minimal eth2spec +(venv) python -m pytest --preset=minimal eth2spec ``` Or, to run a specific test file, specify the full path: ```shell -(venv) python -m pytest --config=minimal ./eth2spec/test/phase0/block_processing/test_process_attestation.py +(venv) python -m pytest --preset=minimal ./eth2spec/test/phase0/block_processing/test_process_attestation.py ``` Or, to run a specific test function (specify the `eth2spec` module, or the script path if the keyword is ambiguous): ```shell -(venv) python -m pytest --config=minimal -k test_success_multi_proposer_index_iterations eth2spec +(venv) python -m pytest --preset=minimal -k test_success_multi_proposer_index_iterations eth2spec ``` Options: -- `--config`, to change the config. Defaults to `minimal`, can be set to `mainnet`, or other configs from the configs directory. +- `--preset`, to change the preset (compile-time configurables). Defaults to `minimal`, can be set to `mainnet`. + Use `@spec_configured_state_test({config here...}` to override runtime configurables on a per-test basis. - `--disable-bls`, to disable BLS (only for tests that can run without) - `--bls-type`, `milagro` or `py_ecc` (default) diff --git a/tests/core/pyspec/eth2spec/config/README.md b/tests/core/pyspec/eth2spec/config/README.md index 314e68aae..5a64d39ba 100644 --- a/tests/core/pyspec/eth2spec/config/README.md +++ b/tests/core/pyspec/eth2spec/config/README.md @@ -1,20 +1,23 @@ # Eth2 config util -For configuration, see [Configs documentation](../../../../../configs/README.md). +For run-time configuration, see [Configs documentation](../../../../../configs/README.md). -## Usage: +For compile-time presets, see [Presets documentation](../../../../../presets/README.md) +and the `build-targets` flag for the `pyspec` distutils command. + +## Config usage: ```python -configs_path = 'configs/' - -... - from eth2spec.config import config_util -from eth2spec.phase0 import spec -from importlib import reload -config_util.prepare_config(configs_path, 'mainnet') -# reload spec to make loaded config effective -reload(spec) +from eth2spec.phase0 import mainnet as spec +from pathlib import Path + +# To load the default configurations +config_util.load_defaults(Path("eth2.0-specs/configs")) # change path to point to equivalent of specs `configs` dir. +# After loading the defaults, a config can be chosen: 'mainnet', 'minimal', or custom network config (by file path) +spec.config = spec.Configuration(**config_util.load_config_file(Path('mytestnet.yaml'))) ``` -WARNING: this overwrites globals, make sure to prevent accidental collisions with other usage of the same imported specs package. +Note: previously the testnet config files included both preset and runtime-configuration data. +The new config loader is compatible with this: all config vars are loaded from the file, +but those that have become presets can be ignored. diff --git a/tests/core/pyspec/eth2spec/config/config_util.py b/tests/core/pyspec/eth2spec/config/config_util.py index 917cf3a60..0d06428ea 100644 --- a/tests/core/pyspec/eth2spec/config/config_util.py +++ b/tests/core/pyspec/eth2spec/config/config_util.py @@ -1,60 +1,63 @@ -import os from pathlib import Path -from typing import Dict, Any - +from typing import Dict, Iterable, Union, BinaryIO, TextIO, Any from ruamel.yaml import YAML -config: Dict[str, Any] = {} - -# Access to overwrite spec constants based on configuration -# This is called by the spec module after declaring its globals, and applies the loaded presets. -def apply_constants_config(spec_globals: Dict[str, Any], warn_if_unknown: bool = False) -> None: - global config - for k, v in config.items(): - # the spec should have default values for everything, if not, the config key is invalid. - if k in spec_globals: - # Keep the same type as the default value indicates (which may be an SSZ basic type subclass, e.g. 'Gwei') - spec_globals[k] = spec_globals[k].__class__(v) - else: - # Note: The phase 0 spec will not warn if Altair or later config values are applied. - # During debugging you can enable explicit warnings. - if warn_if_unknown: - print(f"WARNING: unknown config key: '{k}' with value: '{v}'") - - -# Load presets from a file, and then prepares the global config setting. This does not apply the config. -# To apply the config, reload the spec module (it will re-initialize with the config taken from here). -def prepare_config(configs_path: str, config_name: str) -> None: - global config - config = load_config_file(configs_path, config_name) - - -def load_config_file(configs_dir: str, presets_name: str) -> Dict[str, Any]: +def parse_config_vars(conf: Dict[str, Any]) -> Dict[str, Any]: """ - Loads the given preset - :param presets_name: The name of the presets. (lowercase snake_case) - :return: Dictionary, mapping of constant-name -> constant-value + Parses a dict of basic str/int/list types into more detailed python types """ - present_dir = Path(configs_dir) / presets_name - _, _, config_files = next(os.walk(present_dir)) - config_files.sort() - loaded_config = {} - for config_file_name in config_files: - yaml = YAML(typ='base') - path = present_dir / config_file_name - loaded = yaml.load(path) - loaded_config.update(loaded) - assert loaded_config != {} - out: Dict[str, Any] = dict() - for k, v in loaded_config.items(): + for k, v in conf.items(): if isinstance(v, list): # Clean up integer values. YAML parser renders lists of ints as list of str out[k] = [int(item) if item.isdigit() else item for item in v] elif isinstance(v, str) and v.startswith("0x"): out[k] = bytes.fromhex(v[2:]) - else: + elif k != 'PRESET_BASE': out[k] = int(v) - out['CONFIG_NAME'] = presets_name + else: + out[k] = v return out + + +def load_preset(preset_files: Iterable[Union[Path, BinaryIO, TextIO]]) -> Dict[str, Any]: + """ + Loads the a directory of preset files, merges the result into one preset. + """ + preset = {} + for fork_file in preset_files: + yaml = YAML(typ='base') + fork_preset: dict = yaml.load(fork_file) + if fork_preset is None: # for empty YAML files + continue + if not set(fork_preset.keys()).isdisjoint(preset.keys()): + duplicates = set(fork_preset.keys()).intersection(set(preset.keys())) + raise Exception(f"duplicate config var(s) in preset files: {', '.join(duplicates)}") + preset.update(fork_preset) + assert preset != {} + return parse_config_vars(preset) + + +def load_config_file(config_path: Union[Path, BinaryIO, TextIO]) -> Dict[str, Any]: + """ + Loads the given configuration file. + """ + yaml = YAML(typ='base') + config_data = yaml.load(config_path) + return parse_config_vars(config_data) + + +mainnet_config_data: Dict[str, Any] +minimal_config_data: Dict[str, Any] +loaded_defaults = False + + +def load_defaults(spec_configs_path: Path) -> None: + global mainnet_config_data, minimal_config_data + + mainnet_config_data = load_config_file(spec_configs_path / 'mainnet.yaml') + minimal_config_data = load_config_file(spec_configs_path / 'minimal.yaml') + + global loaded_defaults + loaded_defaults = True diff --git a/tests/core/pyspec/eth2spec/gen_helpers/gen_base/gen_runner.py b/tests/core/pyspec/eth2spec/gen_helpers/gen_base/gen_runner.py index e4f1318ae..2b02d1b5c 100644 --- a/tests/core/pyspec/eth2spec/gen_helpers/gen_base/gen_runner.py +++ b/tests/core/pyspec/eth2spec/gen_helpers/gen_base/gen_runner.py @@ -34,18 +34,6 @@ def validate_output_dir(path_str): return path -def validate_configs_dir(path_str): - path = Path(path_str) - - if not path.exists(): - raise argparse.ArgumentTypeError("Configs directory must exist") - - if not path.is_dir(): - raise argparse.ArgumentTypeError("Config path must lead to a directory") - - return path - - def run_generator(generator_name, test_providers: Iterable[TestProvider]): """ Implementation for a general test generator. @@ -76,22 +64,14 @@ def run_generator(generator_name, test_providers: Iterable[TestProvider]): default=False, help="if set re-generate and overwrite test files if they already exist", ) - parser.add_argument( - "-c", - "--configs-path", - dest="configs_path", - required=True, - type=validate_configs_dir, - help="specify the path of the configs directory", - ) parser.add_argument( "-l", - "--config-list", - dest="config_list", + "--preset-list", + dest="preset_list", nargs='*', type=str, required=False, - help="specify configs to run with. Allows all if no config names are specified.", + help="specify presets to run with. Allows all if no preset names are specified.", ) args = parser.parse_args() @@ -107,27 +87,22 @@ def run_generator(generator_name, test_providers: Iterable[TestProvider]): log_file = Path(output_dir) / 'testgen_error_log.txt' print(f"Generating tests into {output_dir}") - print(f"Reading configs from {args.configs_path}") print(f'Error log file: {log_file}') - configs = args.config_list - if configs is None: - configs = [] + presets = args.preset_list + if presets is None: + presets = [] - if len(configs) != 0: - print(f"Filtering test-generator runs to only include configs: {', '.join(configs)}") + if len(presets) != 0: + print(f"Filtering test-generator runs to only include presets: {', '.join(presets)}") for tprov in test_providers: - # loads configuration etc. - config_name = tprov.prepare(args.configs_path) - if len(configs) != 0 and config_name not in configs: - print(f"skipping tests with config '{config_name}' since it is filtered out") - continue + # runs anything that we don't want to repeat for every test case. + tprov.prepare() - 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(output_dir) / Path(test_case.preset_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) ) diff --git a/tests/core/pyspec/eth2spec/gen_helpers/gen_base/gen_typing.py b/tests/core/pyspec/eth2spec/gen_helpers/gen_base/gen_typing.py index 34bd71db1..669238d1c 100644 --- a/tests/core/pyspec/eth2spec/gen_helpers/gen_base/gen_typing.py +++ b/tests/core/pyspec/eth2spec/gen_helpers/gen_base/gen_typing.py @@ -19,6 +19,7 @@ TestCasePart = NewType("TestCasePart", Tuple[str, str, Any]) @dataclass class TestCase(object): fork_name: str + preset_name: str runner_name: str handler_name: str suite_name: str @@ -28,8 +29,7 @@ class TestCase(object): @dataclass class TestProvider(object): - # Prepares the context with a configuration, loaded from the given config path. - # fn(config path) => chosen config name - prepare: Callable[[str], str] + # Prepares the context for the provider as a whole, as opposed to per-test-case changes. + prepare: Callable[[], None] # Retrieves an iterable of cases, called after prepare() make_cases: Callable[[], Iterable[TestCase]] 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 bc63b212b..db3f9e949 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,18 +1,18 @@ -from importlib import reload, import_module +from importlib import import_module from inspect import getmembers, isfunction from typing import Any, Callable, Dict, Iterable, Optional -from eth2spec.config import config_util from eth2spec.utils import bls -from eth2spec.test.helpers.constants import ALL_CONFIGS, TESTGEN_FORKS -from eth2spec.test.helpers.typing import SpecForkName, ConfigName +from eth2spec.test.helpers.constants import ALL_PRESETS, TESTGEN_FORKS +from eth2spec.test.helpers.typing import SpecForkName, PresetBaseName 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, - fork_name: SpecForkName, bls_active: bool = True, + fork_name: SpecForkName, preset_name: PresetBaseName, + 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. @@ -21,8 +21,10 @@ def generate_from_tests(runner_name: str, handler_name: str, src: Any, :param src: to retrieve tests from (discovered using inspect.getmembers). :param fork_name: the folder name for these tests. (if multiple forks are applicable, indicate the last fork) + :param preset_name: to select a preset. Tests that do not support the preset will be skipped. :param bls_active: optional, to override BLS switch preference. Defaults to True. :param phase: optional, to run tests against a particular spec version. Default to `fork_name` value. + Set to the pre-fork (w.r.t. fork_name) in multi-fork tests. :return: an iterable of test cases. """ fn_names = [ @@ -44,40 +46,36 @@ def generate_from_tests(runner_name: str, handler_name: str, src: Any, yield TestCase( fork_name=fork_name, + preset_name=preset_name, runner_name=runner_name, handler_name=handler_name, 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=phase, bls_active=bls_active) + case_fn=lambda: tfn(generator_mode=True, phase=phase, preset=preset_name, bls_active=bls_active) ) -def get_provider(create_provider_fn: Callable[[SpecForkName, str, str, ConfigName], TestProvider], - config_name: ConfigName, +def get_provider(create_provider_fn: Callable[[SpecForkName, PresetBaseName, str, str], TestProvider], fork_name: SpecForkName, + preset_name: PresetBaseName, 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, + preset_name=preset_name, 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 prepare_fn(configs_path: str) -> str: - config_util.prepare_config(configs_path, config_name) - for spec in specs: - reload(spec) +def get_create_provider_fn(runner_name: str) -> Callable[[SpecForkName, str, str, PresetBaseName], TestProvider]: + def prepare_fn() -> None: bls.use_milagro() - return config_name + return - def create_provider(fork_name: SpecForkName, handler_name: str, - tests_src_mod_name: str, config_name: ConfigName) -> TestProvider: + def create_provider(fork_name: SpecForkName, preset_name: PresetBaseName, + handler_name: str, tests_src_mod_name: str) -> TestProvider: def cases_fn() -> Iterable[TestCase]: tests_src = import_module(tests_src_mod_name) return generate_from_tests( @@ -85,22 +83,26 @@ def get_create_provider_fn( handler_name=handler_name, src=tests_src, fork_name=fork_name, + preset_name=preset_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: +def run_state_test_generators(runner_name: str, + all_mods: Dict[str, Dict[str, str]], + presets: Iterable[PresetBaseName] = ALL_PRESETS, + forks: Iterable[SpecForkName] = TESTGEN_FORKS) -> None: """ - Generate all available state tests of `TESTGEN_FORKS` forks of `ALL_CONFIGS` configs of the given runner. + Generate all available state tests of `TESTGEN_FORKS` forks of `ALL_PRESETS` presets of the given runner. """ - for config_name in ALL_CONFIGS: - for fork_name in TESTGEN_FORKS: + for preset_name in presets: + for fork_name in 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, + create_provider_fn=get_create_provider_fn(runner_name), fork_name=fork_name, + preset_name=preset_name, all_mods=all_mods, )) diff --git a/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_committee.py b/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_committee.py index e3ee32a93..ff388ff37 100644 --- a/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_committee.py +++ b/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_committee.py @@ -17,7 +17,7 @@ from eth2spec.test.helpers.sync_committee import ( from eth2spec.test.context import ( expect_assertion_error, with_altair_and_later, - with_configs, + with_presets, spec_state_test, always_bls, ) @@ -213,7 +213,7 @@ def run_successful_sync_committee_test(spec, state, committee_indices, committee @with_altair_and_later -@with_configs([MINIMAL], reason="to create nonduplicate committee") +@with_presets([MINIMAL], reason="to create nonduplicate committee") @spec_state_test def test_sync_committee_rewards_nonduplicate_committee(spec, state): committee_indices = get_committee_indices(spec, state, duplicates=False) @@ -229,7 +229,7 @@ def test_sync_committee_rewards_nonduplicate_committee(spec, state): @with_altair_and_later -@with_configs([MAINNET], reason="to create duplicate committee") +@with_presets([MAINNET], reason="to create duplicate committee") @spec_state_test def test_sync_committee_rewards_duplicate_committee(spec, state): committee_indices = get_committee_indices(spec, state, duplicates=True) @@ -305,7 +305,7 @@ def test_invalid_signature_past_block(spec, state): @with_altair_and_later -@with_configs([MINIMAL], reason="to produce different committee sets") +@with_presets([MINIMAL], reason="to produce different committee sets") @spec_state_test @always_bls def test_invalid_signature_previous_committee(spec, state): @@ -343,7 +343,7 @@ def test_invalid_signature_previous_committee(spec, state): @with_altair_and_later @spec_state_test @always_bls -@with_configs([MINIMAL], reason="too slow") +@with_presets([MINIMAL], reason="too slow") def test_valid_signature_future_committee(spec, state): # NOTE: the `state` provided is at genesis and the process to select # sync committees currently returns the same committee for the first and second diff --git a/tests/core/pyspec/eth2spec/test/altair/epoch_processing/test_process_sync_committee_updates.py b/tests/core/pyspec/eth2spec/test/altair/epoch_processing/test_process_sync_committee_updates.py index 6af16287c..1c5caff81 100644 --- a/tests/core/pyspec/eth2spec/test/altair/epoch_processing/test_process_sync_committee_updates.py +++ b/tests/core/pyspec/eth2spec/test/altair/epoch_processing/test_process_sync_committee_updates.py @@ -3,7 +3,7 @@ from eth2spec.test.context import ( spec_state_test, spec_test, with_altair_and_later, - with_configs, + with_presets, with_custom_state, single_phase, misc_balances, @@ -48,7 +48,7 @@ def run_sync_committees_progress_test(spec, state): @with_altair_and_later @spec_state_test @always_bls -@with_configs([MINIMAL], reason="too slow") +@with_presets([MINIMAL], reason="too slow") def test_sync_committees_progress_genesis(spec, state): # Genesis epoch period has an exceptional case assert spec.get_current_epoch(state) == spec.GENESIS_EPOCH @@ -59,7 +59,7 @@ def test_sync_committees_progress_genesis(spec, state): @with_altair_and_later @spec_state_test @always_bls -@with_configs([MINIMAL], reason="too slow") +@with_presets([MINIMAL], reason="too slow") def test_sync_committees_progress_not_genesis(spec, state): # Transition out of the genesis epoch period to test non-exceptional case assert spec.get_current_epoch(state) == spec.GENESIS_EPOCH @@ -70,10 +70,10 @@ def test_sync_committees_progress_not_genesis(spec, state): @with_altair_and_later -@with_custom_state(balances_fn=misc_balances, threshold_fn=lambda spec: spec.EJECTION_BALANCE) +@with_custom_state(balances_fn=misc_balances, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) @spec_test @single_phase @always_bls -@with_configs([MINIMAL], reason="too slow") +@with_presets([MINIMAL], reason="too slow") def test_sync_committees_progress_misc_balances(spec, state): yield from run_sync_committees_progress_test(spec, state) diff --git a/tests/core/pyspec/eth2spec/test/altair/fork/test_altair_fork_basic.py b/tests/core/pyspec/eth2spec/test/altair/fork/test_altair_fork_basic.py index bc082026e..6c212afbc 100644 --- a/tests/core/pyspec/eth2spec/test/altair/fork/test_altair_fork_basic.py +++ b/tests/core/pyspec/eth2spec/test/altair/fork/test_altair_fork_basic.py @@ -1,7 +1,7 @@ from eth2spec.test.context import ( with_phases, with_custom_state, - with_configs, + with_presets, spec_test, with_state, low_balances, misc_balances, large_validator_set, ) @@ -57,7 +57,7 @@ def test_fork_many_next_epoch(spec, phases, state): @with_phases(phases=[PHASE0], other_phases=[ALTAIR]) -@with_custom_state(balances_fn=low_balances, threshold_fn=lambda spec: spec.EJECTION_BALANCE) +@with_custom_state(balances_fn=low_balances, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) @spec_test @with_meta_tags(ALTAIR_FORK_TEST_META_TAGS) def test_fork_random_low_balances(spec, phases, state): @@ -65,7 +65,7 @@ def test_fork_random_low_balances(spec, phases, state): @with_phases(phases=[PHASE0], other_phases=[ALTAIR]) -@with_custom_state(balances_fn=misc_balances, threshold_fn=lambda spec: spec.EJECTION_BALANCE) +@with_custom_state(balances_fn=misc_balances, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) @spec_test @with_meta_tags(ALTAIR_FORK_TEST_META_TAGS) def test_fork_random_misc_balances(spec, phases, state): @@ -73,9 +73,9 @@ def test_fork_random_misc_balances(spec, phases, state): @with_phases(phases=[PHASE0], other_phases=[ALTAIR]) -@with_configs([MINIMAL], +@with_presets([MINIMAL], reason="mainnet config leads to larger validator set than limit of public/private keys pre-generated") -@with_custom_state(balances_fn=large_validator_set, threshold_fn=lambda spec: spec.EJECTION_BALANCE) +@with_custom_state(balances_fn=large_validator_set, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) @spec_test @with_meta_tags(ALTAIR_FORK_TEST_META_TAGS) def test_fork_random_large_validator_set(spec, phases, state): diff --git a/tests/core/pyspec/eth2spec/test/altair/fork/test_altair_fork_random.py b/tests/core/pyspec/eth2spec/test/altair/fork/test_altair_fork_random.py index ba350bd68..530261df6 100644 --- a/tests/core/pyspec/eth2spec/test/altair/fork/test_altair_fork_random.py +++ b/tests/core/pyspec/eth2spec/test/altair/fork/test_altair_fork_random.py @@ -3,7 +3,7 @@ from random import Random from eth2spec.test.context import ( with_phases, with_custom_state, - with_configs, + with_presets, spec_test, with_state, low_balances, misc_balances, large_validator_set, ) @@ -93,7 +93,7 @@ def test_altair_fork_random_mismatched_attestations(spec, phases, state): @with_phases(phases=[PHASE0], other_phases=[ALTAIR]) @spec_test -@with_custom_state(balances_fn=low_balances, threshold_fn=lambda spec: spec.EJECTION_BALANCE) +@with_custom_state(balances_fn=low_balances, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) @with_meta_tags(ALTAIR_FORK_TEST_META_TAGS) def test_altair_fork_random_low_balances(spec, phases, state): randomize_state(spec, state, rng=Random(5050)) @@ -102,7 +102,7 @@ def test_altair_fork_random_low_balances(spec, phases, state): @with_phases(phases=[PHASE0], other_phases=[ALTAIR]) @spec_test -@with_custom_state(balances_fn=misc_balances, threshold_fn=lambda spec: spec.EJECTION_BALANCE) +@with_custom_state(balances_fn=misc_balances, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) @with_meta_tags(ALTAIR_FORK_TEST_META_TAGS) def test_altair_fork_random_misc_balances(spec, phases, state): randomize_state(spec, state, rng=Random(6060)) @@ -110,10 +110,10 @@ def test_altair_fork_random_misc_balances(spec, phases, state): @with_phases(phases=[PHASE0], other_phases=[ALTAIR]) -@with_configs([MINIMAL], +@with_presets([MINIMAL], reason="mainnet config leads to larger validator set than limit of public/private keys pre-generated") @spec_test -@with_custom_state(balances_fn=large_validator_set, threshold_fn=lambda spec: spec.EJECTION_BALANCE) +@with_custom_state(balances_fn=large_validator_set, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) @with_meta_tags(ALTAIR_FORK_TEST_META_TAGS) def test_altair_fork_random_large_validator_set(spec, phases, state): randomize_state(spec, state, rng=Random(7070)) diff --git a/tests/core/pyspec/eth2spec/test/altair/rewards/test_inactivity_scores.py b/tests/core/pyspec/eth2spec/test/altair/rewards/test_inactivity_scores.py index 9eca9a92a..b6b362a8b 100644 --- a/tests/core/pyspec/eth2spec/test/altair/rewards/test_inactivity_scores.py +++ b/tests/core/pyspec/eth2spec/test/altair/rewards/test_inactivity_scores.py @@ -45,7 +45,7 @@ def test_random_high_inactivity_scores(spec, state): @with_altair_and_later -@with_custom_state(balances_fn=low_balances, threshold_fn=lambda spec: spec.EJECTION_BALANCE) +@with_custom_state(balances_fn=low_balances, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) @spec_test @single_phase def test_random_inactivity_scores_low_balances_0(spec, state): @@ -54,7 +54,7 @@ def test_random_inactivity_scores_low_balances_0(spec, state): @with_altair_and_later -@with_custom_state(balances_fn=low_balances, threshold_fn=lambda spec: spec.EJECTION_BALANCE) +@with_custom_state(balances_fn=low_balances, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) @spec_test @single_phase def test_random_inactivity_scores_low_balances_1(spec, state): @@ -63,7 +63,7 @@ def test_random_inactivity_scores_low_balances_1(spec, state): @with_altair_and_later -@with_custom_state(balances_fn=misc_balances, threshold_fn=lambda spec: spec.EJECTION_BALANCE) +@with_custom_state(balances_fn=misc_balances, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) @spec_test @single_phase def test_full_random_misc_balances(spec, state): diff --git a/tests/core/pyspec/eth2spec/test/altair/sanity/test_blocks.py b/tests/core/pyspec/eth2spec/test/altair/sanity/test_blocks.py index 407455a0a..0c85bd1e2 100644 --- a/tests/core/pyspec/eth2spec/test/altair/sanity/test_blocks.py +++ b/tests/core/pyspec/eth2spec/test/altair/sanity/test_blocks.py @@ -98,4 +98,4 @@ def test_inactivity_scores(spec, state): yield 'post', state for pre, post in zip(previous_inactivity_scores, state.inactivity_scores): - assert post == pre + spec.INACTIVITY_SCORE_BIAS + assert post == pre + spec.config.INACTIVITY_SCORE_BIAS diff --git a/tests/core/pyspec/eth2spec/test/altair/transition/test_transition.py b/tests/core/pyspec/eth2spec/test/altair/transition/test_transition.py index c3b03d663..aa2f0694b 100644 --- a/tests/core/pyspec/eth2spec/test/altair/transition/test_transition.py +++ b/tests/core/pyspec/eth2spec/test/altair/transition/test_transition.py @@ -69,8 +69,8 @@ def _do_altair_fork(state, spec, post_spec, fork_epoch, with_block=True): state = post_spec.upgrade_to_altair(state) assert state.fork.epoch == fork_epoch - assert state.fork.previous_version == post_spec.GENESIS_FORK_VERSION - assert state.fork.current_version == post_spec.ALTAIR_FORK_VERSION + assert state.fork.previous_version == post_spec.config.GENESIS_FORK_VERSION + assert state.fork.current_version == post_spec.config.ALTAIR_FORK_VERSION if with_block: return state, _state_transition_and_sign_block_at_slot(post_spec, state) diff --git a/tests/core/pyspec/eth2spec/test/altair/unittests/test_config_override.py b/tests/core/pyspec/eth2spec/test/altair/unittests/test_config_override.py new file mode 100644 index 000000000..f1503c39f --- /dev/null +++ b/tests/core/pyspec/eth2spec/test/altair/unittests/test_config_override.py @@ -0,0 +1,19 @@ +from eth2spec.test.context import spec_configured_state_test, with_phases +from eth2spec.test.helpers.constants import ALTAIR + + +@with_phases([ALTAIR]) +@spec_configured_state_test({ + 'GENESIS_FORK_VERSION': '0x12345678', + 'ALTAIR_FORK_VERSION': '0x11111111', + 'ALTAIR_FORK_EPOCH': 4 +}) +def test_config_override(spec, state): + assert spec.config.ALTAIR_FORK_EPOCH == 4 + assert spec.config.GENESIS_FORK_VERSION != spec.Version('0x00000000') + assert spec.config.GENESIS_FORK_VERSION == spec.Version('0x12345678') + assert spec.config.ALTAIR_FORK_VERSION == spec.Version('0x11111111') + assert state.fork.current_version == spec.Version('0x11111111') + # TODO: it would be nice if the create_genesis_state actually outputs a state + # for the fork with a slot that matches at least the fork boundary. + # assert spec.get_current_epoch(state) >= 4 diff --git a/tests/core/pyspec/eth2spec/test/altair/unittests/test_sync_protocol.py b/tests/core/pyspec/eth2spec/test/altair/unittests/test_sync_protocol.py index 554cebda8..a3cf8b7ca 100644 --- a/tests/core/pyspec/eth2spec/test/altair/unittests/test_sync_protocol.py +++ b/tests/core/pyspec/eth2spec/test/altair/unittests/test_sync_protocol.py @@ -1,6 +1,6 @@ from eth2spec.test.context import ( spec_state_test, - with_configs, + with_presets, with_phases, ) from eth2spec.test.helpers.attestations import next_epoch_with_attestations @@ -83,7 +83,7 @@ def test_process_light_client_update_not_updated(spec, state): @with_phases([ALTAIR]) @spec_state_test -@with_configs([MINIMAL], reason="too slow") +@with_presets([MINIMAL], reason="too slow") def test_process_light_client_update_timeout(spec, state): pre_snapshot = spec.LightClientSnapshot( header=spec.BeaconBlockHeader(), @@ -149,7 +149,7 @@ def test_process_light_client_update_timeout(spec, state): @with_phases([ALTAIR]) @spec_state_test -@with_configs([MINIMAL], reason="too slow") +@with_presets([MINIMAL], reason="too slow") def test_process_light_client_update_finality_updated(spec, state): pre_snapshot = spec.LightClientSnapshot( header=spec.BeaconBlockHeader(), diff --git a/tests/core/pyspec/eth2spec/test/altair/unittests/validator/test_validator.py b/tests/core/pyspec/eth2spec/test/altair/unittests/validator/test_validator.py index 18fb730d7..dfe90b5b5 100644 --- a/tests/core/pyspec/eth2spec/test/altair/unittests/validator/test_validator.py +++ b/tests/core/pyspec/eth2spec/test/altair/unittests/validator/test_validator.py @@ -8,7 +8,7 @@ from eth2spec.utils import bls from eth2spec.utils.bls import only_with_bls from eth2spec.test.context import ( with_altair_and_later, - with_configs, + with_presets, with_state, ) from eth2spec.test.helpers.constants import ( @@ -95,7 +95,7 @@ def _get_sync_committee_signature( @only_with_bls() @with_altair_and_later -@with_configs([MINIMAL], reason="too slow") +@with_presets([MINIMAL], reason="too slow") @with_state def test_process_sync_committee_contributions(phases, spec, state): # skip over slots at genesis @@ -157,7 +157,7 @@ def _get_expected_subnets_by_pubkey(sync_committee_members): @with_altair_and_later -@with_configs([MINIMAL], reason="too slow") +@with_presets([MINIMAL], reason="too slow") @with_state def test_compute_subnets_for_sync_committee(state, spec, phases): # Transition to the head of the next period @@ -186,7 +186,7 @@ def test_compute_subnets_for_sync_committee(state, spec, phases): @with_altair_and_later -@with_configs([MINIMAL], reason="too slow") +@with_presets([MINIMAL], reason="too slow") @with_state def test_compute_subnets_for_sync_committee_slot_period_boundary(state, spec, phases): # Transition to the end of the period diff --git a/tests/core/pyspec/eth2spec/test/conftest.py b/tests/core/pyspec/eth2spec/test/conftest.py index b961ee082..e6d8352e0 100644 --- a/tests/core/pyspec/eth2spec/test/conftest.py +++ b/tests/core/pyspec/eth2spec/test/conftest.py @@ -1,4 +1,3 @@ -from eth2spec.config import config_util from eth2spec.test import context from eth2spec.utils import bls as bls_utils @@ -27,8 +26,8 @@ def fixture(*args, **kwargs): def pytest_addoption(parser): parser.addoption( - "--config", action="store", type=str, default="minimal", - help="config: make the pyspec use the specified configuration" + "--preset", action="store", type=str, default="minimal", + help="preset: make the pyspec use the specified preset" ) parser.addoption( "--disable-bls", action="store_true", default=False, @@ -41,11 +40,8 @@ def pytest_addoption(parser): @fixture(autouse=True) -def config(request): - config_name = request.config.getoption("--config") - config_util.prepare_config('../../../configs/', config_name) - # now that the presets are loaded, reload the specs to apply them - context.reload_specs() +def preset(request): + context.DEFAULT_TEST_PRESET = request.config.getoption("--preset") @fixture(autouse=True) diff --git a/tests/core/pyspec/eth2spec/test/context.py b/tests/core/pyspec/eth2spec/test/context.py index 57071169f..362f64abf 100644 --- a/tests/core/pyspec/eth2spec/test/context.py +++ b/tests/core/pyspec/eth2spec/test/context.py @@ -1,38 +1,38 @@ import pytest - -from eth2spec.phase0 import spec as spec_phase0 -from eth2spec.altair import spec as spec_altair -from eth2spec.merge import spec as spec_merge +from copy import deepcopy +from eth2spec.phase0 import mainnet as spec_phase0_mainnet, minimal as spec_phase0_minimal +from eth2spec.altair import mainnet as spec_altair_mainnet, minimal as spec_altair_minimal +from eth2spec.merge import mainnet as spec_merge_mainnet, minimal as spec_merge_minimal from eth2spec.utils import bls from .exceptions import SkippedTest from .helpers.constants import ( - PHASE0, ALTAIR, MERGE, + SpecForkName, PresetBaseName, + PHASE0, ALTAIR, MERGE, MINIMAL, MAINNET, ALL_PHASES, FORKS_BEFORE_ALTAIR, FORKS_BEFORE_MERGE, ) from .helpers.genesis import create_genesis_state from .utils import vector_test, with_meta_tags, build_transition_test from random import Random -from typing import Any, Callable, Sequence, TypedDict, Protocol +from typing import Any, Callable, Sequence, TypedDict, Protocol, Dict from lru import LRU -from importlib import reload - - -def reload_specs(): - reload(spec_phase0) - reload(spec_altair) - reload(spec_merge) +# Without pytest CLI arg or pyspec-test-generator 'preset' argument, this will be the config to apply. +DEFAULT_TEST_PRESET = MINIMAL # TODO: currently phases are defined as python modules. # It would be better if they would be more well-defined interfaces for stronger typing. +class Configuration(Protocol): + PRESET_BASE: str + class Spec(Protocol): - version: str + fork: str + config: Configuration class SpecPhase0(Spec): @@ -47,6 +47,20 @@ class SpecMerge(Spec): ... +spec_targets: Dict[PresetBaseName, Dict[SpecForkName, Spec]] = { + MINIMAL: { + PHASE0: spec_phase0_minimal, + ALTAIR: spec_altair_minimal, + MERGE: spec_merge_minimal, + }, + MAINNET: { + PHASE0: spec_phase0_mainnet, + ALTAIR: spec_altair_mainnet, + MERGE: spec_merge_mainnet, + }, +} + + class SpecForks(TypedDict, total=False): PHASE0: SpecPhase0 ALTAIR: SpecAltair @@ -71,8 +85,8 @@ def with_custom_state(balances_fn: Callable[[Any], Sequence[int]], def deco(fn): def entry(*args, spec: Spec, phases: SpecForks, **kw): - # make a key for the state - key = (spec.fork, spec.CONFIG_NAME, spec.__file__, balances_fn, threshold_fn) + # make a key for the state, unique to the fork + config (incl preset choice) and balances/activations + key = (spec.fork, spec.config.__hash__(), 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) @@ -204,6 +218,14 @@ def spec_state_test(fn): return spec_test(with_state(single_phase(fn))) +def spec_configured_state_test(conf): + overrides = with_config_overrides(conf) + + def decorator(fn): + return spec_test(overrides(with_state(single_phase(fn)))) + return decorator + + def expect_assertion_error(fn): bad = False try: @@ -320,6 +342,11 @@ def with_phases(phases, other_phases=None): if other_phases is not None: available_phases |= set(other_phases) + preset_name = DEFAULT_TEST_PRESET + if 'preset' in kw: + preset_name = kw.pop('preset') + targets = spec_targets[preset_name] + # TODO: test state is dependent on phase0 but is immediately transitioned to later phases. # A new state-creation helper for later phases may be in place, and then tests can run without phase0 available_phases.add(PHASE0) @@ -327,20 +354,20 @@ def with_phases(phases, other_phases=None): # Populate all phases for multi-phase tests phase_dir = {} if PHASE0 in available_phases: - phase_dir[PHASE0] = spec_phase0 + phase_dir[PHASE0] = targets[PHASE0] if ALTAIR in available_phases: - phase_dir[ALTAIR] = spec_altair + phase_dir[ALTAIR] = targets[ALTAIR] if MERGE in available_phases: - phase_dir[MERGE] = spec_merge + phase_dir[MERGE] = targets[MERGE] # return is ignored whenever multiple phases are ran. # This return is for test generators to emit python generators (yielding test vector outputs) if PHASE0 in run_phases: - ret = fn(spec=spec_phase0, phases=phase_dir, *args, **kw) + ret = fn(spec=targets[PHASE0], phases=phase_dir, *args, **kw) if ALTAIR in run_phases: - ret = fn(spec=spec_altair, phases=phase_dir, *args, **kw) + ret = fn(spec=targets[ALTAIR], phases=phase_dir, *args, **kw) if MERGE in run_phases: - ret = fn(spec=spec_merge, phases=phase_dir, *args, **kw) + ret = fn(spec=targets[MERGE], phases=phase_dir, *args, **kw) # TODO: merge, sharding, custody_game and das are not executable yet. # Tests that specify these features will not run, and get ignored for these specific phases. @@ -349,12 +376,13 @@ def with_phases(phases, other_phases=None): return decorator -def with_configs(configs, reason=None): +def with_presets(preset_bases, reason=None): + available_presets = set(preset_bases) + def decorator(fn): def wrapper(*args, spec: Spec, **kw): - available_configs = set(configs) - if spec.CONFIG_NAME not in available_configs: - message = f"doesn't support this config: {spec.CONFIG_NAME}." + if spec.config.PRESET_BASE not in available_presets: + message = f"doesn't support this preset base: {spec.config.PRESET_BASE}." if reason is not None: message = f"{message} Reason: {reason}" dump_skipping_message(message) @@ -365,6 +393,45 @@ def with_configs(configs, reason=None): return decorator +def with_config_overrides(config_overrides): + """ + WARNING: the spec_test decorator must wrap this, to ensure the decorated test actually runs. + This decorator forces the test to yield, and pytest doesn't run generator tests, and instead silently passes it. + Use 'spec_configured_state_test' instead of 'spec_state_test' if you are unsure. + + This is a decorator that applies a dict of config value overrides to the spec during execution. + """ + def decorator(fn): + def wrapper(*args, spec: Spec, **kw): + # remember the old config + old_config = spec.config + + # apply our overrides to a copy of it, and apply it to the spec + tmp_config = deepcopy(old_config._asdict()) # not a private method, there are multiple + tmp_config.update(config_overrides) + config_types = spec.Configuration.__annotations__ + # Retain types of all config values + test_config = {k: config_types[k](v) for k, v in tmp_config.items()} + + # Output the config for test vectors (TODO: check config YAML encoding) + yield 'config', 'data', test_config + + spec.config = spec.Configuration(**test_config) + + # Run the function + out = fn(*args, spec=spec, **kw) + # If it's not returning None like a normal test function, + # it's generating things, and we need to complete it before setting back the config. + if out is not None: + yield from out + + # Restore the old config and apply it + spec.config = old_config + + return wrapper + return decorator + + def is_post_altair(spec): if spec.fork == MERGE: # TODO: remove parallel Altair-Merge condition after rebase. return False diff --git a/tests/core/pyspec/eth2spec/test/custody_game/block_processing/test_process_chunk_challenge.py b/tests/core/pyspec/eth2spec/test/custody_game/block_processing/test_process_chunk_challenge.py index 5a939c108..87f0238fb 100644 --- a/tests/core/pyspec/eth2spec/test/custody_game/block_processing/test_process_chunk_challenge.py +++ b/tests/core/pyspec/eth2spec/test/custody_game/block_processing/test_process_chunk_challenge.py @@ -16,7 +16,7 @@ from eth2spec.test.context import ( disable_process_reveal_deadlines, spec_state_test, with_phases, - with_configs, + with_presets, ) from eth2spec.test.phase0.block_processing.test_process_attestation import run_attestation_processing @@ -72,7 +72,7 @@ def run_custody_chunk_response_processing(spec, state, custody_response, valid=T @with_phases([CUSTODY_GAME]) @spec_state_test -@with_configs([MINIMAL], reason="too slow") +@with_presets([MINIMAL], reason="too slow") @disable_process_reveal_deadlines def test_challenge_appended(spec, state): transition_to_valid_shard_slot(spec, state) @@ -97,7 +97,7 @@ def test_challenge_appended(spec, state): @with_phases([CUSTODY_GAME]) @spec_state_test @disable_process_reveal_deadlines -@with_configs([MINIMAL], reason="too slow") +@with_presets([MINIMAL], reason="too slow") def test_challenge_empty_element_replaced(spec, state): transition_to_valid_shard_slot(spec, state) transition_to(spec, state, state.slot + 1) # Make len(offset_slots) == 1 @@ -123,7 +123,7 @@ def test_challenge_empty_element_replaced(spec, state): @with_phases([CUSTODY_GAME]) @spec_state_test @disable_process_reveal_deadlines -@with_configs([MINIMAL], reason="too slow") +@with_presets([MINIMAL], reason="too slow") def test_duplicate_challenge(spec, state): transition_to_valid_shard_slot(spec, state) transition_to(spec, state, state.slot + 1) # Make len(offset_slots) == 1 @@ -149,7 +149,7 @@ def test_duplicate_challenge(spec, state): @with_phases([CUSTODY_GAME]) @spec_state_test @disable_process_reveal_deadlines -@with_configs([MINIMAL], reason="too slow") +@with_presets([MINIMAL], reason="too slow") def test_second_challenge(spec, state): transition_to_valid_shard_slot(spec, state) transition_to(spec, state, state.slot + 1) # Make len(offset_slots) == 1 @@ -177,7 +177,7 @@ def test_second_challenge(spec, state): @with_phases([CUSTODY_GAME]) @spec_state_test @disable_process_reveal_deadlines -@with_configs([MINIMAL], reason="too slow") +@with_presets([MINIMAL], reason="too slow") def test_multiple_epochs_custody(spec, state): transition_to_valid_shard_slot(spec, state) transition_to(spec, state, state.slot + spec.SLOTS_PER_EPOCH * 3) @@ -202,7 +202,7 @@ def test_multiple_epochs_custody(spec, state): @with_phases([CUSTODY_GAME]) @spec_state_test @disable_process_reveal_deadlines -@with_configs([MINIMAL], reason="too slow") +@with_presets([MINIMAL], reason="too slow") def test_many_epochs_custody(spec, state): transition_to_valid_shard_slot(spec, state) transition_to(spec, state, state.slot + spec.SLOTS_PER_EPOCH * 20) @@ -227,7 +227,7 @@ def test_many_epochs_custody(spec, state): @with_phases([CUSTODY_GAME]) @spec_state_test @disable_process_reveal_deadlines -@with_configs([MINIMAL], reason="too slow") +@with_presets([MINIMAL], reason="too slow") def test_off_chain_attestation(spec, state): transition_to_valid_shard_slot(spec, state) transition_to(spec, state, state.slot + spec.SLOTS_PER_EPOCH) @@ -248,7 +248,7 @@ def test_off_chain_attestation(spec, state): @with_phases([CUSTODY_GAME]) @spec_state_test @disable_process_reveal_deadlines -@with_configs([MINIMAL], reason="too slow") +@with_presets([MINIMAL], reason="too slow") def test_custody_response(spec, state): transition_to_valid_shard_slot(spec, state) transition_to(spec, state, state.slot + spec.SLOTS_PER_EPOCH) @@ -280,7 +280,7 @@ def test_custody_response(spec, state): @with_phases([CUSTODY_GAME]) @spec_state_test @disable_process_reveal_deadlines -@with_configs([MINIMAL], reason="too slow") +@with_presets([MINIMAL], reason="too slow") def test_custody_response_chunk_index_2(spec, state): transition_to(spec, state, state.slot + spec.SLOTS_PER_EPOCH) @@ -311,7 +311,7 @@ def test_custody_response_chunk_index_2(spec, state): @with_phases([CUSTODY_GAME]) @spec_state_test @disable_process_reveal_deadlines -@with_configs([MINIMAL], reason="too slow") +@with_presets([MINIMAL], reason="too slow") def test_custody_response_multiple_epochs(spec, state): transition_to_valid_shard_slot(spec, state) transition_to(spec, state, state.slot + spec.SLOTS_PER_EPOCH * 3) @@ -343,7 +343,7 @@ def test_custody_response_multiple_epochs(spec, state): @with_phases([CUSTODY_GAME]) @spec_state_test @disable_process_reveal_deadlines -@with_configs([MINIMAL], reason="too slow") +@with_presets([MINIMAL], reason="too slow") def test_custody_response_many_epochs(spec, state): transition_to_valid_shard_slot(spec, state) transition_to(spec, state, state.slot + spec.SLOTS_PER_EPOCH * 20) diff --git a/tests/core/pyspec/eth2spec/test/custody_game/block_processing/test_process_custody_slashing.py b/tests/core/pyspec/eth2spec/test/custody_game/block_processing/test_process_custody_slashing.py index f554761f3..7ee5cd394 100644 --- a/tests/core/pyspec/eth2spec/test/custody_game/block_processing/test_process_custody_slashing.py +++ b/tests/core/pyspec/eth2spec/test/custody_game/block_processing/test_process_custody_slashing.py @@ -17,7 +17,7 @@ from eth2spec.test.context import ( spec_state_test, expect_assertion_error, disable_process_reveal_deadlines, - with_configs, + with_presets, ) from eth2spec.test.phase0.block_processing.test_process_attestation import run_attestation_processing @@ -117,7 +117,7 @@ def run_standard_custody_slashing_test(spec, @with_phases([CUSTODY_GAME]) @spec_state_test @disable_process_reveal_deadlines -@with_configs([MINIMAL], reason="too slow") +@with_presets([MINIMAL], reason="too slow") def test_custody_slashing(spec, state): yield from run_standard_custody_slashing_test(spec, state) @@ -125,7 +125,7 @@ def test_custody_slashing(spec, state): @with_phases([CUSTODY_GAME]) @spec_state_test @disable_process_reveal_deadlines -@with_configs([MINIMAL], reason="too slow") +@with_presets([MINIMAL], reason="too slow") def test_incorrect_custody_slashing(spec, state): yield from run_standard_custody_slashing_test(spec, state, correct=False) @@ -133,7 +133,7 @@ def test_incorrect_custody_slashing(spec, state): @with_phases([CUSTODY_GAME]) @spec_state_test @disable_process_reveal_deadlines -@with_configs([MINIMAL], reason="too slow") +@with_presets([MINIMAL], reason="too slow") def test_multiple_epochs_custody(spec, state): yield from run_standard_custody_slashing_test(spec, state, shard_lateness=spec.SLOTS_PER_EPOCH * 3) @@ -141,7 +141,7 @@ def test_multiple_epochs_custody(spec, state): @with_phases([CUSTODY_GAME]) @spec_state_test @disable_process_reveal_deadlines -@with_configs([MINIMAL], reason="too slow") +@with_presets([MINIMAL], reason="too slow") def test_many_epochs_custody(spec, state): yield from run_standard_custody_slashing_test(spec, state, shard_lateness=spec.SLOTS_PER_EPOCH * 5) @@ -149,7 +149,7 @@ def test_many_epochs_custody(spec, state): @with_phases([CUSTODY_GAME]) @spec_state_test @disable_process_reveal_deadlines -@with_configs([MINIMAL], reason="too slow") +@with_presets([MINIMAL], reason="too slow") def test_invalid_custody_slashing(spec, state): yield from run_standard_custody_slashing_test( spec, diff --git a/tests/core/pyspec/eth2spec/test/custody_game/epoch_processing/test_process_challenge_deadlines.py b/tests/core/pyspec/eth2spec/test/custody_game/epoch_processing/test_process_challenge_deadlines.py index 42ff54303..7332dcc80 100644 --- a/tests/core/pyspec/eth2spec/test/custody_game/epoch_processing/test_process_challenge_deadlines.py +++ b/tests/core/pyspec/eth2spec/test/custody_game/epoch_processing/test_process_challenge_deadlines.py @@ -9,7 +9,7 @@ from eth2spec.test.helpers.state import transition_to, transition_to_valid_shard from eth2spec.test.context import ( spec_state_test, with_phases, - with_configs, + with_presets, ) from eth2spec.test.phase0.block_processing.test_process_attestation import run_attestation_processing from eth2spec.test.helpers.constants import ( @@ -29,7 +29,7 @@ def run_process_challenge_deadlines(spec, state): @with_phases([CUSTODY_GAME]) @spec_state_test -@with_configs([MINIMAL], reason="too slow") +@with_presets([MINIMAL], reason="too slow") def test_validator_slashed_after_chunk_challenge(spec, state): transition_to_valid_shard_slot(spec, state) transition_to(spec, state, state.slot + 1) # Make len(offset_slots) == 1 diff --git a/tests/core/pyspec/eth2spec/test/custody_game/epoch_processing/test_process_reveal_deadlines.py b/tests/core/pyspec/eth2spec/test/custody_game/epoch_processing/test_process_reveal_deadlines.py index aec24bca8..b831ccff7 100644 --- a/tests/core/pyspec/eth2spec/test/custody_game/epoch_processing/test_process_reveal_deadlines.py +++ b/tests/core/pyspec/eth2spec/test/custody_game/epoch_processing/test_process_reveal_deadlines.py @@ -4,7 +4,7 @@ from eth2spec.test.helpers.custody import ( from eth2spec.test.helpers.state import transition_to from eth2spec.test.context import ( with_phases, - with_configs, + with_presets, spec_state_test, ) from eth2spec.test.helpers.constants import ( @@ -23,7 +23,7 @@ def run_process_challenge_deadlines(spec, state): @with_phases([CUSTODY_GAME]) @spec_state_test -@with_configs([MINIMAL], reason="too slow") +@with_presets([MINIMAL], reason="too slow") def test_validator_slashed_after_reveal_deadline(spec, state): assert state.validators[0].slashed == 0 transition_to(spec, state, spec.get_randao_epoch_for_custody_period(0, 0) * spec.SLOTS_PER_EPOCH) @@ -43,7 +43,7 @@ def test_validator_slashed_after_reveal_deadline(spec, state): @with_phases([CUSTODY_GAME]) @spec_state_test -@with_configs([MINIMAL], reason="too slow") +@with_presets([MINIMAL], reason="too slow") def test_validator_not_slashed_after_reveal(spec, state): transition_to(spec, state, spec.EPOCHS_PER_CUSTODY_PERIOD * spec.SLOTS_PER_EPOCH) custody_key_reveal = get_valid_custody_key_reveal(spec, state) diff --git a/tests/core/pyspec/eth2spec/test/custody_game/sanity/test_blocks.py b/tests/core/pyspec/eth2spec/test/custody_game/sanity/test_blocks.py index 5f5eadef3..f242c361b 100644 --- a/tests/core/pyspec/eth2spec/test/custody_game/sanity/test_blocks.py +++ b/tests/core/pyspec/eth2spec/test/custody_game/sanity/test_blocks.py @@ -3,7 +3,7 @@ from typing import Dict, Sequence from eth2spec.test.context import ( with_phases, spec_state_test, - with_configs, + with_presets, ) from eth2spec.test.helpers.attestations import get_valid_on_time_attestation from eth2spec.test.helpers.block import build_empty_block @@ -83,7 +83,7 @@ def test_with_shard_transition_with_custody_challenge_and_response(spec, state): @with_phases([CUSTODY_GAME]) @spec_state_test -@with_configs([MINIMAL]) +@with_presets([MINIMAL]) def test_custody_key_reveal(spec, state): transition_to_valid_shard_slot(spec, state) transition_to(spec, state, state.slot + spec.EPOCHS_PER_CUSTODY_PERIOD * spec.SLOTS_PER_EPOCH) diff --git a/tests/core/pyspec/eth2spec/test/helpers/altair/fork.py b/tests/core/pyspec/eth2spec/test/helpers/altair/fork.py index b1074c881..78f37c50e 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/altair/fork.py +++ b/tests/core/pyspec/eth2spec/test/helpers/altair/fork.py @@ -36,7 +36,7 @@ def run_fork_test(post_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 == post_spec.ALTAIR_FORK_VERSION + assert post_state.fork.current_version == post_spec.config.ALTAIR_FORK_VERSION assert post_state.fork.epoch == post_spec.get_current_epoch(post_state) yield 'post', post_state diff --git a/tests/core/pyspec/eth2spec/test/helpers/constants.py b/tests/core/pyspec/eth2spec/test/helpers/constants.py index d8f2a37ba..4e98845c4 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/constants.py +++ b/tests/core/pyspec/eth2spec/test/helpers/constants.py @@ -1,4 +1,4 @@ -from .typing import SpecForkName, ConfigName +from .typing import SpecForkName, PresetBaseName # @@ -28,7 +28,7 @@ FORKS_BEFORE_MERGE = (PHASE0,) # # Config # -MAINNET = ConfigName('mainnet') -MINIMAL = ConfigName('minimal') +MAINNET = PresetBaseName('mainnet') +MINIMAL = PresetBaseName('minimal') -ALL_CONFIGS = (MINIMAL, MAINNET) +ALL_PRESETS = (MINIMAL, MAINNET) diff --git a/tests/core/pyspec/eth2spec/test/helpers/fork_choice.py b/tests/core/pyspec/eth2spec/test/helpers/fork_choice.py index f3b80b2ac..f6b007894 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/fork_choice.py +++ b/tests/core/pyspec/eth2spec/test/helpers/fork_choice.py @@ -10,7 +10,7 @@ def get_anchor_root(spec, state): def add_block_to_store(spec, store, signed_block): pre_state = store.block_states[signed_block.message.parent_root] - block_time = pre_state.genesis_time + signed_block.message.slot * spec.SECONDS_PER_SLOT + block_time = pre_state.genesis_time + signed_block.message.slot * spec.config.SECONDS_PER_SLOT if store.time < block_time: spec.on_tick(store, block_time) @@ -23,7 +23,7 @@ def tick_and_run_on_block(spec, store, signed_block, test_steps=None): test_steps = [] pre_state = store.block_states[signed_block.message.parent_root] - block_time = pre_state.genesis_time + signed_block.message.slot * spec.SECONDS_PER_SLOT + block_time = pre_state.genesis_time + signed_block.message.slot * spec.config.SECONDS_PER_SLOT if store.time < block_time: on_tick_and_append_step(spec, store, block_time, test_steps) @@ -37,8 +37,8 @@ def tick_and_run_on_attestation(spec, store, attestation, test_steps=None): parent_block = store.blocks[attestation.data.beacon_block_root] pre_state = store.block_states[spec.hash_tree_root(parent_block)] - block_time = pre_state.genesis_time + parent_block.slot * spec.SECONDS_PER_SLOT - next_epoch_time = block_time + spec.SLOTS_PER_EPOCH * spec.SECONDS_PER_SLOT + block_time = pre_state.genesis_time + parent_block.slot * spec.config.SECONDS_PER_SLOT + next_epoch_time = block_time + spec.SLOTS_PER_EPOCH * spec.config.SECONDS_PER_SLOT if store.time < next_epoch_time: spec.on_tick(store, next_epoch_time) diff --git a/tests/core/pyspec/eth2spec/test/helpers/genesis.py b/tests/core/pyspec/eth2spec/test/helpers/genesis.py index c57442766..8617ce9f3 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/genesis.py +++ b/tests/core/pyspec/eth2spec/test/helpers/genesis.py @@ -25,12 +25,12 @@ def create_genesis_state(spec, validator_balances, activation_threshold): deposit_root = b'\x42' * 32 eth1_block_hash = b'\xda' * 32 - current_version = spec.GENESIS_FORK_VERSION + current_version = spec.config.GENESIS_FORK_VERSION if spec.fork == ALTAIR: - current_version = spec.ALTAIR_FORK_VERSION + current_version = spec.config.ALTAIR_FORK_VERSION elif spec.fork == MERGE: - current_version = spec.MERGE_FORK_VERSION + current_version = spec.config.MERGE_FORK_VERSION state = spec.BeaconState( genesis_time=0, @@ -41,7 +41,7 @@ def create_genesis_state(spec, validator_balances, activation_threshold): block_hash=eth1_block_hash, ), fork=spec.Fork( - previous_version=spec.GENESIS_FORK_VERSION, + previous_version=spec.config.GENESIS_FORK_VERSION, current_version=current_version, epoch=spec.GENESIS_EPOCH, ), diff --git a/tests/core/pyspec/eth2spec/test/helpers/keys.py b/tests/core/pyspec/eth2spec/test/helpers/keys.py index d813870e0..5e36e90df 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/keys.py +++ b/tests/core/pyspec/eth2spec/test/helpers/keys.py @@ -1,6 +1,6 @@ from py_ecc.bls import G2ProofOfPossession as bls -from eth2spec.phase0 import spec -privkeys = [i + 1 for i in range(spec.SLOTS_PER_EPOCH * 256)] +# Enough keys for 256 validators per slot in worst-case epoch length +privkeys = [i + 1 for i in range(32 * 256)] pubkeys = [bls.SkToPk(privkey) for privkey in privkeys] pubkey_to_privkey = {pubkey: privkey for privkey, pubkey in zip(privkeys, pubkeys)} diff --git a/tests/core/pyspec/eth2spec/test/helpers/multi_operations.py b/tests/core/pyspec/eth2spec/test/helpers/multi_operations.py index 89ac95a3e..4b6c9b25d 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/multi_operations.py +++ b/tests/core/pyspec/eth2spec/test/helpers/multi_operations.py @@ -19,7 +19,7 @@ def run_slash_and_exit(spec, state, slash_index, exit_index, valid=True): Helper function to run a test that slashes and exits two validators """ # move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit - state.slot += spec.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH + state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH yield 'pre', state @@ -127,7 +127,7 @@ def get_random_voluntary_exits(spec, state, to_be_slashed_indices, rng): def run_test_full_random_operations(spec, state, rng=Random(2080)): # move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit - state.slot += spec.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH + state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH # prepare state for deposits before building block deposits = prepare_state_and_get_random_deposits(spec, state, rng) diff --git a/tests/core/pyspec/eth2spec/test/helpers/rewards.py b/tests/core/pyspec/eth2spec/test/helpers/rewards.py index 86bb70133..83b99f66d 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/rewards.py +++ b/tests/core/pyspec/eth2spec/test/helpers/rewards.py @@ -1,7 +1,7 @@ from random import Random from lru import LRU -from eth2spec.phase0 import spec as spec_phase0 +from eth2spec.phase0.mainnet import VALIDATOR_REGISTRY_LIMIT # equal everywhere, fine to import from eth2spec.test.context import is_post_altair from eth2spec.test.helpers.state import ( next_epoch, @@ -17,8 +17,8 @@ from eth2spec.utils.ssz.ssz_typing import Container, uint64, List class Deltas(Container): - rewards: List[uint64, spec_phase0.VALIDATOR_REGISTRY_LIMIT] - penalties: List[uint64, spec_phase0.VALIDATOR_REGISTRY_LIMIT] + rewards: List[uint64, VALIDATOR_REGISTRY_LIMIT] + penalties: List[uint64, VALIDATOR_REGISTRY_LIMIT] def has_enough_for_reward(spec, state, index): @@ -45,7 +45,7 @@ def has_enough_for_leak_penalty(spec, state, index): if is_post_altair(spec): return ( state.validators[index].effective_balance * state.inactivity_scores[index] - > spec.INACTIVITY_SCORE_BIAS * spec.INACTIVITY_PENALTY_QUOTIENT_ALTAIR + > spec.config.INACTIVITY_SCORE_BIAS * spec.INACTIVITY_PENALTY_QUOTIENT_ALTAIR ) else: return ( diff --git a/tests/core/pyspec/eth2spec/test/helpers/state.py b/tests/core/pyspec/eth2spec/test/helpers/state.py index d61df7610..74521087d 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/state.py +++ b/tests/core/pyspec/eth2spec/test/helpers/state.py @@ -42,10 +42,10 @@ def transition_to_slot_via_block(spec, state, slot): def transition_to_valid_shard_slot(spec, state): """ - Transition to slot `compute_epoch_at_slot(spec.SHARDING_FORK_EPOCH) + 1` - and fork at `compute_epoch_at_slot(spec.SHARDING_FORK_EPOCH)`. + Transition to slot `compute_epoch_at_slot(spec.config.SHARDING_FORK_EPOCH) + 1` + and fork at `compute_epoch_at_slot(spec.config.SHARDING_FORK_EPOCH)`. """ - transition_to(spec, state, spec.compute_epoch_at_slot(spec.SHARDING_FORK_EPOCH)) + transition_to(spec, state, spec.compute_epoch_at_slot(spec.config.SHARDING_FORK_EPOCH)) next_slot(spec, state) diff --git a/tests/core/pyspec/eth2spec/test/helpers/typing.py b/tests/core/pyspec/eth2spec/test/helpers/typing.py index 04578f64c..19657a8f7 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/typing.py +++ b/tests/core/pyspec/eth2spec/test/helpers/typing.py @@ -1,4 +1,4 @@ from typing import NewType SpecForkName = NewType("SpecForkName", str) -ConfigName = NewType("ConfigName", str) +PresetBaseName = NewType("PresetBaseName", str) diff --git a/tests/core/pyspec/eth2spec/test/phase0/block_processing/test_process_attestation.py b/tests/core/pyspec/eth2spec/test/phase0/block_processing/test_process_attestation.py index 0f5eef407..38a050ebc 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/block_processing/test_process_attestation.py +++ b/tests/core/pyspec/eth2spec/test/phase0/block_processing/test_process_attestation.py @@ -32,7 +32,7 @@ def test_success(spec, state): @with_all_phases @spec_test -@with_custom_state(balances_fn=low_balances, threshold_fn=lambda spec: spec.EJECTION_BALANCE) +@with_custom_state(balances_fn=low_balances, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) @single_phase def test_success_multi_proposer_index_iterations(spec, state): next_slots(spec, state, spec.SLOTS_PER_EPOCH * 2) 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 7345e62ba..940bc47fb 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 @@ -1,4 +1,4 @@ -import random +from random import Random from eth2spec.test.context import ( spec_state_test, expect_assertion_error, always_bls, with_all_phases, @@ -127,7 +127,7 @@ def test_success_already_exited_recent(spec, state): @with_all_phases -@with_custom_state(balances_fn=low_balances, threshold_fn=lambda spec: spec.EJECTION_BALANCE) +@with_custom_state(balances_fn=low_balances, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) @spec_test @single_phase def test_success_low_balances(spec, state): @@ -137,7 +137,7 @@ def test_success_low_balances(spec, state): @with_all_phases -@with_custom_state(balances_fn=misc_balances, threshold_fn=lambda spec: spec.EJECTION_BALANCE) +@with_custom_state(balances_fn=misc_balances, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) @spec_test @single_phase def test_success_misc_balances(spec, state): @@ -147,14 +147,15 @@ def test_success_misc_balances(spec, state): @with_all_phases -@with_custom_state(balances_fn=misc_balances, threshold_fn=lambda spec: spec.EJECTION_BALANCE) +@with_custom_state(balances_fn=misc_balances, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) @spec_test @single_phase def test_success_with_effective_balance_disparity(spec, state): # Jitter balances to be different from effective balances + rng = Random(12345) for i in range(len(state.balances)): pre = int(state.balances[i]) - state.balances[i] += random.randrange(max(pre - 5000, 0), pre + 5000) + state.balances[i] += rng.randrange(max(pre - 5000, 0), pre + 5000) attester_slashing = get_valid_attester_slashing(spec, state, signed_1=True, signed_2=True) diff --git a/tests/core/pyspec/eth2spec/test/phase0/block_processing/test_process_voluntary_exit.py b/tests/core/pyspec/eth2spec/test/phase0/block_processing/test_process_voluntary_exit.py index 9464f80aa..f713d1792 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/block_processing/test_process_voluntary_exit.py +++ b/tests/core/pyspec/eth2spec/test/phase0/block_processing/test_process_voluntary_exit.py @@ -35,7 +35,7 @@ def run_voluntary_exit_processing(spec, state, signed_voluntary_exit, valid=True @spec_state_test def test_success(spec, state): # move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit - state.slot += spec.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH + state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH current_epoch = spec.get_current_epoch(state) validator_index = spec.get_active_validator_indices(state, current_epoch)[0] @@ -54,7 +54,7 @@ def test_success(spec, state): @always_bls def test_invalid_signature(spec, state): # move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit - state.slot += spec.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH + state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH current_epoch = spec.get_current_epoch(state) validator_index = spec.get_active_validator_indices(state, current_epoch)[0] @@ -72,7 +72,7 @@ def test_invalid_signature(spec, state): @spec_state_test def test_success_exit_queue(spec, state): # move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit - state.slot += spec.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH + state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH current_epoch = spec.get_current_epoch(state) @@ -116,7 +116,7 @@ def test_success_exit_queue(spec, state): @spec_state_test def test_default_exit_epoch_subsequent_exit(spec, state): # move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit - state.slot += spec.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH + state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH current_epoch = spec.get_current_epoch(state) validator_index = spec.get_active_validator_indices(state, current_epoch)[0] @@ -138,7 +138,7 @@ def test_default_exit_epoch_subsequent_exit(spec, state): @spec_state_test def test_validator_exit_in_future(spec, state): # move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit - state.slot += spec.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH + state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH current_epoch = spec.get_current_epoch(state) validator_index = spec.get_active_validator_indices(state, current_epoch)[0] @@ -157,7 +157,7 @@ def test_validator_exit_in_future(spec, state): @spec_state_test def test_validator_invalid_validator_index(spec, state): # move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit - state.slot += spec.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH + state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH current_epoch = spec.get_current_epoch(state) validator_index = spec.get_active_validator_indices(state, current_epoch)[0] @@ -191,7 +191,7 @@ def test_validator_not_active(spec, state): @spec_state_test def test_validator_already_exited(spec, state): # move state forward SHARD_COMMITTEE_PERIOD epochs to allow validator able to exit - state.slot += spec.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH + state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH current_epoch = spec.get_current_epoch(state) validator_index = spec.get_active_validator_indices(state, current_epoch)[0] @@ -218,7 +218,7 @@ def test_validator_not_active_long_enough(spec, state): assert ( current_epoch - state.validators[validator_index].activation_epoch < - spec.SHARD_COMMITTEE_PERIOD + spec.config.SHARD_COMMITTEE_PERIOD ) yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit, False) diff --git a/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_effective_balance_updates.py b/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_effective_balance_updates.py index dc4c047a2..43fe12220 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_effective_balance_updates.py +++ b/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_effective_balance_updates.py @@ -10,7 +10,7 @@ def test_effective_balance_hysteresis(spec, state): run_epoch_processing_to(spec, state, 'process_effective_balance_updates') # Set some edge cases for balances max = spec.MAX_EFFECTIVE_BALANCE - min = spec.EJECTION_BALANCE + min = spec.config.EJECTION_BALANCE inc = spec.EFFECTIVE_BALANCE_INCREMENT div = spec.HYSTERESIS_QUOTIENT hys_inc = inc // div diff --git a/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_registry_updates.py b/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_registry_updates.py index ee40984a6..6e7784aa9 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_registry_updates.py +++ b/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_registry_updates.py @@ -153,7 +153,7 @@ def test_ejection(spec, state): assert state.validators[index].exit_epoch == spec.FAR_FUTURE_EPOCH # Mock an ejection - state.validators[index].effective_balance = spec.EJECTION_BALANCE + state.validators[index].effective_balance = spec.config.EJECTION_BALANCE yield from run_process_registry_updates(spec, state) @@ -174,7 +174,7 @@ def test_ejection_past_churn_limit(spec, state): mock_ejections = churn_limit * 3 for i in range(mock_ejections): - state.validators[i].effective_balance = spec.EJECTION_BALANCE + state.validators[i].effective_balance = spec.config.EJECTION_BALANCE expected_ejection_epoch = spec.compute_activation_exit_epoch(spec.get_current_epoch(state)) @@ -211,7 +211,7 @@ def test_activation_queue_activation_and_ejection(spec, state): # ready for ejection ejection_index = 2 - state.validators[ejection_index].effective_balance = spec.EJECTION_BALANCE + state.validators[ejection_index].effective_balance = spec.config.EJECTION_BALANCE yield from run_process_registry_updates(spec, state) diff --git a/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_rewards_and_penalties.py b/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_rewards_and_penalties.py index 9abcff57e..7ff4e83d3 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_rewards_and_penalties.py +++ b/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_rewards_and_penalties.py @@ -423,7 +423,7 @@ def test_attestations_some_slashed(spec, state): attesting_indices_before_slashings = list(spec.get_unslashed_attesting_indices(state, attestations)) # Slash maximum amount of validators allowed per epoch. - for i in range(spec.MIN_PER_EPOCH_CHURN_LIMIT): + for i in range(spec.config.MIN_PER_EPOCH_CHURN_LIMIT): spec.slash_validator(state, attesting_indices_before_slashings[i]) if not is_post_altair(spec): @@ -435,5 +435,5 @@ def test_attestations_some_slashed(spec, state): attesting_indices = spec.get_unslashed_attesting_indices(state, attestations) assert len(attesting_indices) > 0 - assert len(attesting_indices_before_slashings) - len(attesting_indices) == spec.MIN_PER_EPOCH_CHURN_LIMIT + assert len(attesting_indices_before_slashings) - len(attesting_indices) == spec.config.MIN_PER_EPOCH_CHURN_LIMIT validate_resulting_balances(spec, pre_state, state, attestations) 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 b7ae3cf4e..e336ebef7 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 @@ -82,7 +82,7 @@ def test_minimal_penalty(spec, state): # # Just the bare minimum for this one validator - state.balances[0] = state.validators[0].effective_balance = spec.EJECTION_BALANCE + state.balances[0] = state.validators[0].effective_balance = spec.config.EJECTION_BALANCE # All the other validators get the maximum. for i in range(1, len(state.validators)): state.validators[i].effective_balance = state.balances[i] = spec.MAX_EFFECTIVE_BALANCE @@ -120,7 +120,7 @@ def test_scaled_penalties(spec, state): next_epoch(spec, state) # Also mock some previous slashings, so that we test to have the delta in the penalties computation. - base = spec.EJECTION_BALANCE + base = spec.config.EJECTION_BALANCE incr = spec.EFFECTIVE_BALANCE_INCREMENT # Just add some random slashings. non-zero slashings are at least the minimal effective balance. state.slashings[0] = base + (incr * 12) diff --git a/tests/core/pyspec/eth2spec/test/phase0/fork_choice/test_get_head.py b/tests/core/pyspec/eth2spec/test/phase0/fork_choice/test_get_head.py index 0822d44c2..bce886931 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/fork_choice/test_get_head.py +++ b/tests/core/pyspec/eth2spec/test/phase0/fork_choice/test_get_head.py @@ -4,7 +4,7 @@ from eth2spec.test.context import ( is_post_altair, spec_state_test, with_all_phases, - with_configs, + with_presets, ) from eth2spec.test.helpers.attestations import get_valid_attestation, next_epoch_with_attestations from eth2spec.test.helpers.block import build_empty_block_for_next_slot @@ -174,7 +174,7 @@ def test_shorter_chain_but_heavier_weight(spec, state): @with_all_phases @spec_state_test -@with_configs([MINIMAL], reason="too slow") +@with_presets([MINIMAL], reason="too slow") def test_filtered_block_tree(spec, state): test_steps = [] # Initialization @@ -197,7 +197,7 @@ def test_filtered_block_tree(spec, state): assert state.current_justified_checkpoint.epoch > prev_state.current_justified_checkpoint.epoch # tick time forward and add blocks and attestations to store - current_time = state.slot * spec.SECONDS_PER_SLOT + store.genesis_time + current_time = state.slot * spec.config.SECONDS_PER_SLOT + store.genesis_time on_tick_and_append_step(spec, store, current_time, test_steps) for signed_block in signed_blocks: yield from run_on_block(spec, store, signed_block, test_steps) @@ -243,7 +243,7 @@ def test_filtered_block_tree(spec, state): attestations.append(attestation) # tick time forward to be able to include up to the latest attestation - current_time = (attestations[-1].data.slot + 1) * spec.SECONDS_PER_SLOT + store.genesis_time + current_time = (attestations[-1].data.slot + 1) * spec.config.SECONDS_PER_SLOT + store.genesis_time on_tick_and_append_step(spec, store, current_time, test_steps) # include rogue block and associated attestations in the store diff --git a/tests/core/pyspec/eth2spec/test/phase0/genesis/test_initialization.py b/tests/core/pyspec/eth2spec/test/phase0/genesis/test_initialization.py index be9d120b4..53dd3760a 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/genesis/test_initialization.py +++ b/tests/core/pyspec/eth2spec/test/phase0/genesis/test_initialization.py @@ -2,7 +2,7 @@ from eth2spec.test.context import ( is_post_altair, single_phase, spec_test, - with_configs, + with_presets, with_all_phases, ) from eth2spec.test.helpers.constants import MINIMAL @@ -26,12 +26,12 @@ def eth1_init_data(eth1_block_hash, eth1_timestamp): @with_all_phases @spec_test @single_phase -@with_configs([MINIMAL], reason="too slow") +@with_presets([MINIMAL], reason="too slow") def test_initialize_beacon_state_from_eth1(spec): if is_post_altair(spec): yield 'description', 'meta', get_post_altair_description(spec) - deposit_count = spec.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT + deposit_count = spec.config.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT deposits, deposit_root, _ = prepare_full_genesis_deposits( spec, spec.MAX_EFFECTIVE_BALANCE, @@ -40,7 +40,7 @@ def test_initialize_beacon_state_from_eth1(spec): ) eth1_block_hash = b'\x12' * 32 - eth1_timestamp = spec.MIN_GENESIS_TIME + eth1_timestamp = spec.config.MIN_GENESIS_TIME yield from eth1_init_data(eth1_block_hash, eth1_timestamp) yield 'deposits', deposits @@ -48,7 +48,7 @@ def test_initialize_beacon_state_from_eth1(spec): # initialize beacon_state state = spec.initialize_beacon_state_from_eth1(eth1_block_hash, eth1_timestamp, deposits) - assert state.genesis_time == eth1_timestamp + spec.GENESIS_DELAY + assert state.genesis_time == eth1_timestamp + spec.config.GENESIS_DELAY assert len(state.validators) == deposit_count assert state.eth1_data.deposit_root == deposit_root assert state.eth1_data.deposit_count == deposit_count @@ -62,12 +62,12 @@ def test_initialize_beacon_state_from_eth1(spec): @with_all_phases @spec_test @single_phase -@with_configs([MINIMAL], reason="too slow") +@with_presets([MINIMAL], reason="too slow") def test_initialize_beacon_state_some_small_balances(spec): if is_post_altair(spec): yield 'description', 'meta', get_post_altair_description(spec) - main_deposit_count = spec.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT + main_deposit_count = spec.config.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT main_deposits, _, deposit_data_list = prepare_full_genesis_deposits( spec, spec.MAX_EFFECTIVE_BALANCE, deposit_count=main_deposit_count, signed=True, @@ -83,7 +83,7 @@ def test_initialize_beacon_state_some_small_balances(spec): deposits = main_deposits + small_deposits eth1_block_hash = b'\x12' * 32 - eth1_timestamp = spec.MIN_GENESIS_TIME + eth1_timestamp = spec.config.MIN_GENESIS_TIME yield from eth1_init_data(eth1_block_hash, eth1_timestamp) yield 'deposits', deposits @@ -91,7 +91,7 @@ def test_initialize_beacon_state_some_small_balances(spec): # initialize beacon_state state = spec.initialize_beacon_state_from_eth1(eth1_block_hash, eth1_timestamp, deposits) - assert state.genesis_time == eth1_timestamp + spec.GENESIS_DELAY + assert state.genesis_time == eth1_timestamp + spec.config.GENESIS_DELAY assert len(state.validators) == small_deposit_count assert state.eth1_data.deposit_root == deposit_root assert state.eth1_data.deposit_count == len(deposits) @@ -106,13 +106,13 @@ def test_initialize_beacon_state_some_small_balances(spec): @with_all_phases @spec_test @single_phase -@with_configs([MINIMAL], reason="too slow") +@with_presets([MINIMAL], reason="too slow") def test_initialize_beacon_state_one_topup_activation(spec): if is_post_altair(spec): yield 'description', 'meta', get_post_altair_description(spec) # Submit all but one deposit as MAX_EFFECTIVE_BALANCE - main_deposit_count = spec.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT - 1 + main_deposit_count = spec.config.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT - 1 main_deposits, _, deposit_data_list = prepare_full_genesis_deposits( spec, spec.MAX_EFFECTIVE_BALANCE, deposit_count=main_deposit_count, signed=True, @@ -139,7 +139,7 @@ def test_initialize_beacon_state_one_topup_activation(spec): deposits = main_deposits + partial_deposits + top_up_deposits eth1_block_hash = b'\x13' * 32 - eth1_timestamp = spec.MIN_GENESIS_TIME + eth1_timestamp = spec.config.MIN_GENESIS_TIME yield from eth1_init_data(eth1_block_hash, eth1_timestamp) yield 'deposits', deposits @@ -155,7 +155,7 @@ def test_initialize_beacon_state_one_topup_activation(spec): @with_all_phases @spec_test @single_phase -@with_configs([MINIMAL], reason="too slow") +@with_presets([MINIMAL], reason="too slow") def test_initialize_beacon_state_random_invalid_genesis(spec): if is_post_altair(spec): yield 'description', 'meta', get_post_altair_description(spec) @@ -167,7 +167,7 @@ def test_initialize_beacon_state_random_invalid_genesis(spec): max_pubkey_index=10, ) eth1_block_hash = b'\x14' * 32 - eth1_timestamp = spec.MIN_GENESIS_TIME + 1 + eth1_timestamp = spec.config.MIN_GENESIS_TIME + 1 yield from eth1_init_data(eth1_block_hash, eth1_timestamp) yield 'deposits', deposits @@ -182,7 +182,7 @@ def test_initialize_beacon_state_random_invalid_genesis(spec): @with_all_phases @spec_test @single_phase -@with_configs([MINIMAL], reason="too slow") +@with_presets([MINIMAL], reason="too slow") def test_initialize_beacon_state_random_valid_genesis(spec): if is_post_altair(spec): yield 'description', 'meta', get_post_altair_description(spec) @@ -191,22 +191,22 @@ def test_initialize_beacon_state_random_valid_genesis(spec): random_deposits, _, deposit_data_list = prepare_random_genesis_deposits( spec, deposit_count=20, - min_pubkey_index=spec.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT - 5, - max_pubkey_index=spec.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT + 5, + min_pubkey_index=spec.config.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT - 5, + max_pubkey_index=spec.config.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT + 5, ) - # Then make spec.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT full deposits + # Then make spec.config.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT full deposits full_deposits, _, _ = prepare_full_genesis_deposits( spec, spec.MAX_EFFECTIVE_BALANCE, - deposit_count=spec.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT, + deposit_count=spec.config.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT, signed=True, deposit_data_list=deposit_data_list ) deposits = random_deposits + full_deposits eth1_block_hash = b'\x15' * 32 - eth1_timestamp = spec.MIN_GENESIS_TIME + 2 + eth1_timestamp = spec.config.MIN_GENESIS_TIME + 2 yield from eth1_init_data(eth1_block_hash, eth1_timestamp) yield 'deposits', deposits diff --git a/tests/core/pyspec/eth2spec/test/phase0/genesis/test_validity.py b/tests/core/pyspec/eth2spec/test/phase0/genesis/test_validity.py index 91148da1d..e17e72a4e 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/genesis/test_validity.py +++ b/tests/core/pyspec/eth2spec/test/phase0/genesis/test_validity.py @@ -2,7 +2,7 @@ from eth2spec.test.context import ( is_post_altair, spec_test, single_phase, - with_configs, + with_presets, with_all_phases, ) from eth2spec.test.helpers.constants import MINIMAL @@ -16,7 +16,7 @@ def get_post_altair_description(spec): def create_valid_beacon_state(spec): - deposit_count = spec.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT + deposit_count = spec.config.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT deposits, _, _ = prepare_full_genesis_deposits( spec, amount=spec.MAX_EFFECTIVE_BALANCE, @@ -25,7 +25,7 @@ def create_valid_beacon_state(spec): ) eth1_block_hash = b'\x12' * 32 - eth1_timestamp = spec.MIN_GENESIS_TIME + eth1_timestamp = spec.config.MIN_GENESIS_TIME return spec.initialize_beacon_state_from_eth1(eth1_block_hash, eth1_timestamp, deposits) @@ -44,7 +44,7 @@ def run_is_valid_genesis_state(spec, state, valid=True): @with_all_phases @spec_test @single_phase -@with_configs([MINIMAL], reason="too slow") +@with_presets([MINIMAL], reason="too slow") def test_is_valid_genesis_state_true(spec): if is_post_altair(spec): yield 'description', 'meta', get_post_altair_description(spec) @@ -57,13 +57,13 @@ def test_is_valid_genesis_state_true(spec): @with_all_phases @spec_test @single_phase -@with_configs([MINIMAL], reason="too slow") +@with_presets([MINIMAL], reason="too slow") def test_is_valid_genesis_state_false_invalid_timestamp(spec): if is_post_altair(spec): yield 'description', 'meta', get_post_altair_description(spec) state = create_valid_beacon_state(spec) - state.genesis_time = spec.MIN_GENESIS_TIME - 1 + state.genesis_time = spec.config.MIN_GENESIS_TIME - 1 yield from run_is_valid_genesis_state(spec, state, valid=False) @@ -71,7 +71,7 @@ def test_is_valid_genesis_state_false_invalid_timestamp(spec): @with_all_phases @spec_test @single_phase -@with_configs([MINIMAL], reason="too slow") +@with_presets([MINIMAL], reason="too slow") def test_is_valid_genesis_state_true_more_balance(spec): if is_post_altair(spec): yield 'description', 'meta', get_post_altair_description(spec) @@ -85,12 +85,12 @@ def test_is_valid_genesis_state_true_more_balance(spec): @with_all_phases @spec_test @single_phase -@with_configs([MINIMAL], reason="too slow") +@with_presets([MINIMAL], reason="too slow") def test_is_valid_genesis_state_true_one_more_validator(spec): if is_post_altair(spec): yield 'description', 'meta', get_post_altair_description(spec) - deposit_count = spec.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT + 1 + deposit_count = spec.config.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT + 1 deposits, _, _ = prepare_full_genesis_deposits( spec, amount=spec.MAX_EFFECTIVE_BALANCE, @@ -99,7 +99,7 @@ def test_is_valid_genesis_state_true_one_more_validator(spec): ) eth1_block_hash = b'\x12' * 32 - eth1_timestamp = spec.MIN_GENESIS_TIME + eth1_timestamp = spec.config.MIN_GENESIS_TIME state = spec.initialize_beacon_state_from_eth1(eth1_block_hash, eth1_timestamp, deposits) yield from run_is_valid_genesis_state(spec, state, valid=True) @@ -108,12 +108,12 @@ def test_is_valid_genesis_state_true_one_more_validator(spec): @with_all_phases @spec_test @single_phase -@with_configs([MINIMAL], reason="too slow") +@with_presets([MINIMAL], reason="too slow") def test_is_valid_genesis_state_false_not_enough_validator(spec): if is_post_altair(spec): yield 'description', 'meta', get_post_altair_description(spec) - deposit_count = spec.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT - 1 + deposit_count = spec.config.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT - 1 deposits, _, _ = prepare_full_genesis_deposits( spec, amount=spec.MAX_EFFECTIVE_BALANCE, @@ -122,7 +122,7 @@ def test_is_valid_genesis_state_false_not_enough_validator(spec): ) eth1_block_hash = b'\x12' * 32 - eth1_timestamp = spec.MIN_GENESIS_TIME + eth1_timestamp = spec.config.MIN_GENESIS_TIME state = spec.initialize_beacon_state_from_eth1(eth1_block_hash, eth1_timestamp, deposits) yield from run_is_valid_genesis_state(spec, state, valid=False) diff --git a/tests/core/pyspec/eth2spec/test/phase0/rewards/test_random.py b/tests/core/pyspec/eth2spec/test/phase0/rewards/test_random.py index b1af64a77..1184a6617 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/rewards/test_random.py +++ b/tests/core/pyspec/eth2spec/test/phase0/rewards/test_random.py @@ -36,7 +36,7 @@ def test_full_random_3(spec, state): @with_all_phases -@with_custom_state(balances_fn=low_balances, threshold_fn=lambda spec: spec.EJECTION_BALANCE) +@with_custom_state(balances_fn=low_balances, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) @spec_test @single_phase def test_full_random_low_balances_0(spec, state): @@ -44,7 +44,7 @@ def test_full_random_low_balances_0(spec, state): @with_all_phases -@with_custom_state(balances_fn=low_balances, threshold_fn=lambda spec: spec.EJECTION_BALANCE) +@with_custom_state(balances_fn=low_balances, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) @spec_test @single_phase def test_full_random_low_balances_1(spec, state): @@ -52,7 +52,7 @@ def test_full_random_low_balances_1(spec, state): @with_all_phases -@with_custom_state(balances_fn=misc_balances, threshold_fn=lambda spec: spec.EJECTION_BALANCE) +@with_custom_state(balances_fn=misc_balances, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) @spec_test @single_phase def test_full_random_misc_balances(spec, state): 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 15f64ac79..0e22e75b8 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/sanity/test_blocks.py +++ b/tests/core/pyspec/eth2spec/test/phase0/sanity/test_blocks.py @@ -30,7 +30,7 @@ from eth2spec.test.context import ( with_phases, with_all_phases, single_phase, expect_assertion_error, always_bls, disable_process_reveal_deadlines, - with_configs, + with_presets, with_custom_state, large_validator_set, is_post_altair, @@ -98,10 +98,10 @@ def test_empty_block_transition(spec, state): @with_all_phases -@with_configs([MINIMAL], +@with_presets([MINIMAL], reason="mainnet config leads to larger validator set than limit of public/private keys pre-generated") @spec_test -@with_custom_state(balances_fn=large_validator_set, threshold_fn=lambda spec: spec.EJECTION_BALANCE) +@with_custom_state(balances_fn=large_validator_set, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) @single_phase def test_empty_block_transition_large_validator_set(spec, state): pre_slot = state.slot @@ -326,10 +326,10 @@ def test_empty_epoch_transition(spec, state): @with_all_phases -@with_configs([MINIMAL], +@with_presets([MINIMAL], reason="mainnet config leads to larger validator set than limit of public/private keys pre-generated") @spec_test -@with_custom_state(balances_fn=large_validator_set, threshold_fn=lambda spec: spec.EJECTION_BALANCE) +@with_custom_state(balances_fn=large_validator_set, threshold_fn=lambda spec: spec.config.EJECTION_BALANCE) @single_phase def test_empty_epoch_transition_large_validator_set(spec, state): pre_slot = state.slot @@ -814,7 +814,7 @@ def test_voluntary_exit(spec, state): validator_index = spec.get_active_validator_indices(state, spec.get_current_epoch(state))[-1] # move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit - state.slot += spec.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH + state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH signed_exits = prepare_signed_exits(spec, state, [validator_index]) yield 'pre', state @@ -842,7 +842,7 @@ def test_double_validator_exit_same_block(spec, state): validator_index = spec.get_active_validator_indices(state, spec.get_current_epoch(state))[-1] # move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit - state.slot += spec.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH + state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH # Same index tries to exit twice, but should only be able to do so once. signed_exits = prepare_signed_exits(spec, state, [validator_index, validator_index]) @@ -866,7 +866,7 @@ def test_multiple_different_validator_exits_same_block(spec, state): for i in range(3) ] # move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit - state.slot += spec.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH + state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH signed_exits = prepare_signed_exits(spec, state, validator_indices) yield 'pre', state @@ -916,7 +916,7 @@ def test_balance_driven_status_transitions(spec, state): assert state.validators[validator_index].exit_epoch == spec.FAR_FUTURE_EPOCH # set validator balance to below ejection threshold - state.validators[validator_index].effective_balance = spec.EJECTION_BALANCE + state.validators[validator_index].effective_balance = spec.config.EJECTION_BALANCE yield 'pre', state diff --git a/tests/core/pyspec/eth2spec/test/phase0/unittests/fork_choice/test_on_attestation.py b/tests/core/pyspec/eth2spec/test/phase0/unittests/fork_choice/test_on_attestation.py index 8ff6bbb38..9007a778f 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/unittests/fork_choice/test_on_attestation.py +++ b/tests/core/pyspec/eth2spec/test/phase0/unittests/fork_choice/test_on_attestation.py @@ -35,7 +35,7 @@ def run_on_attestation(spec, state, store, attestation, valid=True): @spec_state_test def test_on_attestation_current_epoch(spec, state): store = get_genesis_forkchoice_store(spec, state) - spec.on_tick(store, store.time + spec.SECONDS_PER_SLOT * 2) + spec.on_tick(store, store.time + spec.config.SECONDS_PER_SLOT * 2) block = build_empty_block_for_next_slot(spec, state) signed_block = state_transition_and_sign_block(spec, state, block) @@ -54,7 +54,7 @@ def test_on_attestation_current_epoch(spec, state): @spec_state_test def test_on_attestation_previous_epoch(spec, state): store = get_genesis_forkchoice_store(spec, state) - spec.on_tick(store, store.time + spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH) + spec.on_tick(store, store.time + spec.config.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH) block = build_empty_block_for_next_slot(spec, state) signed_block = state_transition_and_sign_block(spec, state, block) @@ -75,7 +75,7 @@ def test_on_attestation_past_epoch(spec, state): store = get_genesis_forkchoice_store(spec, state) # move time forward 2 epochs - time = store.time + 2 * spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH + time = store.time + 2 * spec.config.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH spec.on_tick(store, time) # create and store block from 3 epochs ago @@ -95,7 +95,7 @@ def test_on_attestation_past_epoch(spec, state): @spec_state_test def test_on_attestation_mismatched_target_and_slot(spec, state): store = get_genesis_forkchoice_store(spec, state) - spec.on_tick(store, store.time + spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH) + spec.on_tick(store, store.time + spec.config.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH) block = build_empty_block_for_next_slot(spec, state) signed_block = state_transition_and_sign_block(spec, state, block) @@ -118,7 +118,7 @@ def test_on_attestation_mismatched_target_and_slot(spec, state): @spec_state_test def test_on_attestation_inconsistent_target_and_head(spec, state): store = get_genesis_forkchoice_store(spec, state) - spec.on_tick(store, store.time + 2 * spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH) + spec.on_tick(store, store.time + 2 * spec.config.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH) # Create chain 1 as empty chain between genesis and start of 1st epoch target_state_1 = state.copy() @@ -156,7 +156,7 @@ def test_on_attestation_inconsistent_target_and_head(spec, state): @spec_state_test def test_on_attestation_target_block_not_in_store(spec, state): store = get_genesis_forkchoice_store(spec, state) - time = store.time + spec.SECONDS_PER_SLOT * (spec.SLOTS_PER_EPOCH + 1) + time = store.time + spec.config.SECONDS_PER_SLOT * (spec.SLOTS_PER_EPOCH + 1) spec.on_tick(store, time) # move to immediately before next epoch to make block new target @@ -178,7 +178,7 @@ def test_on_attestation_target_block_not_in_store(spec, state): @spec_state_test def test_on_attestation_target_checkpoint_not_in_store(spec, state): store = get_genesis_forkchoice_store(spec, state) - time = store.time + spec.SECONDS_PER_SLOT * (spec.SLOTS_PER_EPOCH + 1) + time = store.time + spec.config.SECONDS_PER_SLOT * (spec.SLOTS_PER_EPOCH + 1) spec.on_tick(store, time) # move to immediately before next epoch to make block new target @@ -203,7 +203,7 @@ def test_on_attestation_target_checkpoint_not_in_store(spec, state): @spec_state_test def test_on_attestation_target_checkpoint_not_in_store_diff_slot(spec, state): store = get_genesis_forkchoice_store(spec, state) - time = store.time + spec.SECONDS_PER_SLOT * (spec.SLOTS_PER_EPOCH + 1) + time = store.time + spec.config.SECONDS_PER_SLOT * (spec.SLOTS_PER_EPOCH + 1) spec.on_tick(store, time) # move to two slots before next epoch to make target block one before an empty slot @@ -230,7 +230,7 @@ def test_on_attestation_target_checkpoint_not_in_store_diff_slot(spec, state): @spec_state_test def test_on_attestation_beacon_block_not_in_store(spec, state): store = get_genesis_forkchoice_store(spec, state) - time = store.time + spec.SECONDS_PER_SLOT * (spec.SLOTS_PER_EPOCH + 1) + time = store.time + spec.config.SECONDS_PER_SLOT * (spec.SLOTS_PER_EPOCH + 1) spec.on_tick(store, time) # move to immediately before next epoch to make block new target @@ -259,7 +259,7 @@ def test_on_attestation_beacon_block_not_in_store(spec, state): @spec_state_test def test_on_attestation_future_epoch(spec, state): store = get_genesis_forkchoice_store(spec, state) - time = store.time + 3 * spec.SECONDS_PER_SLOT + time = store.time + 3 * spec.config.SECONDS_PER_SLOT spec.on_tick(store, time) block = build_empty_block_for_next_slot(spec, state) @@ -279,7 +279,7 @@ def test_on_attestation_future_epoch(spec, state): @spec_state_test def test_on_attestation_future_block(spec, state): store = get_genesis_forkchoice_store(spec, state) - time = store.time + spec.SECONDS_PER_SLOT * 5 + time = store.time + spec.config.SECONDS_PER_SLOT * 5 spec.on_tick(store, time) block = build_empty_block_for_next_slot(spec, state) @@ -299,7 +299,7 @@ def test_on_attestation_future_block(spec, state): @spec_state_test def test_on_attestation_same_slot(spec, state): store = get_genesis_forkchoice_store(spec, state) - time = store.time + spec.SECONDS_PER_SLOT + time = store.time + spec.config.SECONDS_PER_SLOT spec.on_tick(store, time) block = build_empty_block_for_next_slot(spec, state) @@ -315,7 +315,7 @@ def test_on_attestation_same_slot(spec, state): @spec_state_test def test_on_attestation_invalid_attestation(spec, state): store = get_genesis_forkchoice_store(spec, state) - time = store.time + 3 * spec.SECONDS_PER_SLOT + time = store.time + 3 * spec.config.SECONDS_PER_SLOT spec.on_tick(store, time) block = build_empty_block_for_next_slot(spec, state) diff --git a/tests/core/pyspec/eth2spec/test/phase0/unittests/fork_choice/test_on_block.py b/tests/core/pyspec/eth2spec/test/phase0/unittests/fork_choice/test_on_block.py index 48ea78e39..b1862d093 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/unittests/fork_choice/test_on_block.py +++ b/tests/core/pyspec/eth2spec/test/phase0/unittests/fork_choice/test_on_block.py @@ -30,7 +30,7 @@ def apply_next_epoch_with_attestations(spec, state, store): store.blocks[block_root] = block store.block_states[block_root] = post_state last_signed_block = signed_block - spec.on_tick(store, store.time + state.slot * spec.SECONDS_PER_SLOT) + spec.on_tick(store, store.time + state.slot * spec.config.SECONDS_PER_SLOT) return post_state, store, last_signed_block @@ -49,7 +49,7 @@ def test_basic(spec, state): run_on_block(spec, store, signed_block) # On receiving a block of next epoch - store.time = time + spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH + store.time = time + spec.config.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH block = build_empty_block(spec, state, state.slot + spec.SLOTS_PER_EPOCH) signed_block = state_transition_and_sign_block(spec, state, block) @@ -67,10 +67,10 @@ def test_on_block_checkpoints(spec, state): spec.on_tick(store, time) next_epoch(spec, state) - spec.on_tick(store, store.time + state.slot * spec.SECONDS_PER_SLOT) + spec.on_tick(store, store.time + state.slot * spec.config.SECONDS_PER_SLOT) state, store, last_signed_block = apply_next_epoch_with_attestations(spec, state, store) next_epoch(spec, state) - spec.on_tick(store, store.time + state.slot * spec.SECONDS_PER_SLOT) + spec.on_tick(store, store.time + state.slot * spec.config.SECONDS_PER_SLOT) last_block_root = hash_tree_root(last_signed_block.message) # Mock the finalized_checkpoint @@ -153,7 +153,7 @@ def test_on_block_finalized_skip_slots(spec, state): # Build block that includes the skipped slots up to finality in chain block = build_empty_block(spec, state, spec.compute_start_slot_at_epoch(store.finalized_checkpoint.epoch) + 2) signed_block = state_transition_and_sign_block(spec, state, block) - spec.on_tick(store, store.time + state.slot * spec.SECONDS_PER_SLOT) + spec.on_tick(store, store.time + state.slot * spec.config.SECONDS_PER_SLOT) run_on_block(spec, store, signed_block) @@ -178,7 +178,7 @@ def test_on_block_finalized_skip_slots_not_in_skip_chain(spec, state): # Includes finalized block in chain, but not at appropriate skip slot block = build_empty_block(spec, state, spec.compute_start_slot_at_epoch(store.finalized_checkpoint.epoch) + 2) signed_block = state_transition_and_sign_block(spec, state, block) - spec.on_tick(store, store.time + state.slot * spec.SECONDS_PER_SLOT) + spec.on_tick(store, store.time + state.slot * spec.config.SECONDS_PER_SLOT) run_on_block(spec, store, signed_block, False) @@ -191,10 +191,10 @@ def test_on_block_update_justified_checkpoint_within_safe_slots(spec, state): spec.on_tick(store, time) next_epoch(spec, state) - spec.on_tick(store, store.time + state.slot * spec.SECONDS_PER_SLOT) + spec.on_tick(store, store.time + state.slot * spec.config.SECONDS_PER_SLOT) state, store, last_signed_block = apply_next_epoch_with_attestations(spec, state, store) next_epoch(spec, state) - spec.on_tick(store, store.time + state.slot * spec.SECONDS_PER_SLOT) + spec.on_tick(store, store.time + state.slot * spec.config.SECONDS_PER_SLOT) last_block_root = hash_tree_root(last_signed_block.message) # Mock the justified checkpoint @@ -222,7 +222,7 @@ def test_on_block_outside_safe_slots_and_multiple_better_justified(spec, state): spec.on_tick(store, time) next_epoch(spec, state) - spec.on_tick(store, store.time + state.slot * spec.SECONDS_PER_SLOT) + spec.on_tick(store, store.time + state.slot * spec.config.SECONDS_PER_SLOT) state, store, last_signed_block = apply_next_epoch_with_attestations(spec, state, store) last_block_root = hash_tree_root(last_signed_block.message) @@ -233,14 +233,14 @@ def test_on_block_outside_safe_slots_and_multiple_better_justified(spec, state): ) next_epoch(spec, state) - spec.on_tick(store, store.time + state.slot * spec.SECONDS_PER_SLOT) + spec.on_tick(store, store.time + state.slot * spec.config.SECONDS_PER_SLOT) # Create new higher justified checkpoint not in branch of store's justified checkpoint just_block = build_empty_block_for_next_slot(spec, state) store.blocks[just_block.hash_tree_root()] = just_block # Step time past safe slots - spec.on_tick(store, store.time + spec.SAFE_SLOTS_TO_UPDATE_JUSTIFIED * spec.SECONDS_PER_SLOT) + spec.on_tick(store, store.time + spec.SAFE_SLOTS_TO_UPDATE_JUSTIFIED * spec.config.SECONDS_PER_SLOT) assert spec.get_current_slot(store) % spec.SLOTS_PER_EPOCH >= spec.SAFE_SLOTS_TO_UPDATE_JUSTIFIED previously_justified = store.justified_checkpoint @@ -277,7 +277,7 @@ def test_on_block_outside_safe_slots_but_finality(spec, state): spec.on_tick(store, time) next_epoch(spec, state) - spec.on_tick(store, store.time + state.slot * spec.SECONDS_PER_SLOT) + spec.on_tick(store, store.time + state.slot * spec.config.SECONDS_PER_SLOT) state, store, last_signed_block = apply_next_epoch_with_attestations(spec, state, store) last_block_root = hash_tree_root(last_signed_block.message) @@ -288,14 +288,14 @@ def test_on_block_outside_safe_slots_but_finality(spec, state): ) next_epoch(spec, state) - spec.on_tick(store, store.time + state.slot * spec.SECONDS_PER_SLOT) + spec.on_tick(store, store.time + state.slot * spec.config.SECONDS_PER_SLOT) # Create new higher justified checkpoint not in branch of store's justified checkpoint just_block = build_empty_block_for_next_slot(spec, state) store.blocks[just_block.hash_tree_root()] = just_block # Step time past safe slots - spec.on_tick(store, store.time + spec.SAFE_SLOTS_TO_UPDATE_JUSTIFIED * spec.SECONDS_PER_SLOT) + spec.on_tick(store, store.time + spec.SAFE_SLOTS_TO_UPDATE_JUSTIFIED * spec.config.SECONDS_PER_SLOT) assert spec.get_current_slot(store) % spec.SLOTS_PER_EPOCH >= spec.SAFE_SLOTS_TO_UPDATE_JUSTIFIED # Mock justified and finalized update in state diff --git a/tests/core/pyspec/eth2spec/test/phase0/unittests/fork_choice/test_on_tick.py b/tests/core/pyspec/eth2spec/test/phase0/unittests/fork_choice/test_on_tick.py index 9cf0e9e26..ef643fd6b 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/unittests/fork_choice/test_on_tick.py +++ b/tests/core/pyspec/eth2spec/test/phase0/unittests/fork_choice/test_on_tick.py @@ -30,7 +30,7 @@ def test_update_justified_single(spec, state): store = get_genesis_forkchoice_store(spec, state) next_epoch = spec.get_current_epoch(state) + 1 next_epoch_start_slot = spec.compute_start_slot_at_epoch(next_epoch) - seconds_until_next_epoch = next_epoch_start_slot * spec.SECONDS_PER_SLOT - store.time + seconds_until_next_epoch = next_epoch_start_slot * spec.config.SECONDS_PER_SLOT - store.time store.best_justified_checkpoint = spec.Checkpoint( epoch=store.justified_checkpoint.epoch + 1, @@ -44,7 +44,7 @@ def test_update_justified_single(spec, state): @spec_state_test def test_no_update_same_slot_at_epoch_boundary(spec, state): store = get_genesis_forkchoice_store(spec, state) - seconds_per_epoch = spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH + seconds_per_epoch = spec.config.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH store.best_justified_checkpoint = spec.Checkpoint( epoch=store.justified_checkpoint.epoch + 1, @@ -67,14 +67,14 @@ def test_no_update_not_epoch_boundary(spec, state): root=b'\x55' * 32, ) - run_on_tick(spec, store, store.time + spec.SECONDS_PER_SLOT) + run_on_tick(spec, store, store.time + spec.config.SECONDS_PER_SLOT) @with_all_phases @spec_state_test def test_no_update_new_justified_equal_epoch(spec, state): store = get_genesis_forkchoice_store(spec, state) - seconds_per_epoch = spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH + seconds_per_epoch = spec.config.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH store.best_justified_checkpoint = spec.Checkpoint( epoch=store.justified_checkpoint.epoch + 1, @@ -93,7 +93,7 @@ def test_no_update_new_justified_equal_epoch(spec, state): @spec_state_test def test_no_update_new_justified_later_epoch(spec, state): store = get_genesis_forkchoice_store(spec, state) - seconds_per_epoch = spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH + seconds_per_epoch = spec.config.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH store.best_justified_checkpoint = spec.Checkpoint( epoch=store.justified_checkpoint.epoch + 1, diff --git a/tests/core/pyspec/eth2spec/test/phase0/unittests/validator/test_validator_unittest.py b/tests/core/pyspec/eth2spec/test/phase0/unittests/validator/test_validator_unittest.py index fb63839d6..cf7ef392f 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/unittests/validator/test_validator_unittest.py +++ b/tests/core/pyspec/eth2spec/test/phase0/unittests/validator/test_validator_unittest.py @@ -41,8 +41,8 @@ def run_is_candidate_block(spec, eth1_block, period_start, success=True): def get_min_new_period_epochs(spec): return ( - (spec.SECONDS_PER_ETH1_BLOCK * spec.ETH1_FOLLOW_DISTANCE * 2) # to seconds - // spec.SECONDS_PER_SLOT // spec.SLOTS_PER_EPOCH + (spec.config.SECONDS_PER_ETH1_BLOCK * spec.config.ETH1_FOLLOW_DISTANCE * 2) # to seconds + // spec.config.SECONDS_PER_SLOT // spec.SLOTS_PER_EPOCH ) @@ -140,28 +140,29 @@ def test_get_epoch_signature(spec, state): @with_all_phases @spec_state_test def test_is_candidate_block(spec, state): - period_start = spec.SECONDS_PER_ETH1_BLOCK * spec.ETH1_FOLLOW_DISTANCE * 2 + 1000 + distance_duration = spec.config.SECONDS_PER_ETH1_BLOCK * spec.config.ETH1_FOLLOW_DISTANCE + period_start = distance_duration * 2 + 1000 run_is_candidate_block( spec, - spec.Eth1Block(timestamp=period_start - spec.SECONDS_PER_ETH1_BLOCK * spec.ETH1_FOLLOW_DISTANCE), + spec.Eth1Block(timestamp=period_start - distance_duration), period_start, success=True, ) run_is_candidate_block( spec, - spec.Eth1Block(timestamp=period_start - spec.SECONDS_PER_ETH1_BLOCK * spec.ETH1_FOLLOW_DISTANCE + 1), + spec.Eth1Block(timestamp=period_start - distance_duration + 1), period_start, success=False, ) run_is_candidate_block( spec, - spec.Eth1Block(timestamp=period_start - spec.SECONDS_PER_ETH1_BLOCK * spec.ETH1_FOLLOW_DISTANCE * 2), + spec.Eth1Block(timestamp=period_start - distance_duration * 2), period_start, success=True, ) run_is_candidate_block( spec, - spec.Eth1Block(timestamp=period_start - spec.SECONDS_PER_ETH1_BLOCK * spec.ETH1_FOLLOW_DISTANCE * 2 - 1), + spec.Eth1Block(timestamp=period_start - distance_duration * 2 - 1), period_start, success=False, ) @@ -193,12 +194,12 @@ def test_get_eth1_vote_consensus_vote(spec, state): state.eth1_data_votes = () block_1 = spec.Eth1Block( - timestamp=period_start - spec.SECONDS_PER_ETH1_BLOCK * spec.ETH1_FOLLOW_DISTANCE - 1, + timestamp=period_start - spec.config.SECONDS_PER_ETH1_BLOCK * spec.config.ETH1_FOLLOW_DISTANCE - 1, deposit_count=state.eth1_data.deposit_count, deposit_root=b'\x04' * 32, ) block_2 = spec.Eth1Block( - timestamp=period_start - spec.SECONDS_PER_ETH1_BLOCK * spec.ETH1_FOLLOW_DISTANCE, + timestamp=period_start - spec.config.SECONDS_PER_ETH1_BLOCK * spec.config.ETH1_FOLLOW_DISTANCE, deposit_count=state.eth1_data.deposit_count + 1, deposit_root=b'\x05' * 32, ) @@ -229,12 +230,12 @@ def test_get_eth1_vote_tie(spec, state): state.eth1_data_votes = () block_1 = spec.Eth1Block( - timestamp=period_start - spec.SECONDS_PER_ETH1_BLOCK * spec.ETH1_FOLLOW_DISTANCE - 1, + timestamp=period_start - spec.config.SECONDS_PER_ETH1_BLOCK * spec.config.ETH1_FOLLOW_DISTANCE - 1, deposit_count=state.eth1_data.deposit_count, deposit_root=b'\x04' * 32, ) block_2 = spec.Eth1Block( - timestamp=period_start - spec.SECONDS_PER_ETH1_BLOCK * spec.ETH1_FOLLOW_DISTANCE, + timestamp=period_start - spec.config.SECONDS_PER_ETH1_BLOCK * spec.config.ETH1_FOLLOW_DISTANCE, deposit_count=state.eth1_data.deposit_count + 1, deposit_root=b'\x05' * 32, ) @@ -268,7 +269,7 @@ def test_get_eth1_vote_chain_in_past(spec, state): state.eth1_data_votes = () block_1 = spec.Eth1Block( - timestamp=period_start - spec.SECONDS_PER_ETH1_BLOCK * spec.ETH1_FOLLOW_DISTANCE, + timestamp=period_start - spec.config.SECONDS_PER_ETH1_BLOCK * spec.config.ETH1_FOLLOW_DISTANCE, deposit_count=state.eth1_data.deposit_count - 1, # Chain prior to current eth1data deposit_root=b'\x42' * 32, ) diff --git a/tests/formats/README.md b/tests/formats/README.md index 16f756fc1..39968832f 100644 --- a/tests/formats/README.md +++ b/tests/formats/README.md @@ -176,21 +176,14 @@ reveal_deadlines_setting: -- optional, can have 2 different values: 1: `process_reveal_deadlines` is OFF. ``` +##### `config.yaml` -## Config +The runtime-configurables may be different for specific tests. +When present, this replaces the default runtime-config that comes with the otherwise compile-time preset settings. -A configuration is a separate YAML file. -Separation of configuration and tests aims to: -- Prevent duplication of configuration -- Make all tests easy to upgrade (e.g. when a new config constant is introduced) -- Clearly define which constants to use -- Be easily shareable between clients, for cross-client short- or long-lived testnets -- Minimize the amount of different constants permutations to compile as a client. - *Note*: Some clients prefer compile-time constants and optimizations. - They should compile for each configuration once, and run the corresponding tests per build target. -- Include constants to coordinate forking with - -The format is described in [`/configs`](../../configs/README.md#format). +The format matches that of the `mainnet_config.yaml` and `minimal_config.yaml`, +see the [`/configs`](../../configs/README.md#format) documentation. +Config values that are introduced at a later fork may be omitted from tests of previous forks. ## Config sourcing diff --git a/tests/generators/bls/main.py b/tests/generators/bls/main.py index 3d67c9db3..3ebaa1354 100644 --- a/tests/generators/bls/main.py +++ b/tests/generators/bls/main.py @@ -358,10 +358,10 @@ def case05_aggregate_verify(): def create_provider(handler_name: str, test_case_fn: Callable[[], Iterable[Tuple[str, Dict[str, Any]]]]) -> gen_typing.TestProvider: - def prepare_fn(configs_path: str) -> str: + def prepare_fn() -> None: # Nothing to load / change in spec. Maybe in future forks. # Put the tests into the general config category, to not require any particular configuration. - return 'general' + return def cases_fn() -> Iterable[gen_typing.TestCase]: for data in test_case_fn(): @@ -369,6 +369,7 @@ def create_provider(handler_name: str, (case_name, case_content) = data yield gen_typing.TestCase( fork_name=PHASE0, + preset_name='general', runner_name='bls', handler_name=handler_name, suite_name='small', diff --git a/tests/generators/epoch_processing/main.py b/tests/generators/epoch_processing/main.py index 2aa6381ff..a3d0f82be 100644 --- a/tests/generators/epoch_processing/main.py +++ b/tests/generators/epoch_processing/main.py @@ -1,13 +1,7 @@ from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators -from eth2spec.phase0 import spec as spec_phase0 -from eth2spec.altair import spec as spec_altair -from eth2spec.merge import spec as spec_merge from eth2spec.test.helpers.constants import PHASE0, ALTAIR, MERGE -specs = (spec_phase0, spec_altair, spec_merge) - - if __name__ == "__main__": phase_0_mods = {key: 'eth2spec.test.phase0.epoch_processing.test_process_' + key for key in [ 'justification_and_finalization', @@ -45,4 +39,4 @@ if __name__ == "__main__": MERGE: merge_mods, } - run_state_test_generators(runner_name="epoch_processing", specs=specs, all_mods=all_mods) + run_state_test_generators(runner_name="epoch_processing", all_mods=all_mods) diff --git a/tests/generators/finality/main.py b/tests/generators/finality/main.py index 148ddef96..b4c8da39a 100644 --- a/tests/generators/finality/main.py +++ b/tests/generators/finality/main.py @@ -1,13 +1,7 @@ from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators -from eth2spec.phase0 import spec as spec_phase0 -from eth2spec.altair import spec as spec_altair -from eth2spec.merge import spec as spec_merge from eth2spec.test.helpers.constants import PHASE0, ALTAIR, MERGE -specs = (spec_phase0, spec_altair, spec_merge) - - if __name__ == "__main__": phase_0_mods = {'finality': 'eth2spec.test.phase0.finality.test_finality'} altair_mods = phase_0_mods # No additional Altair specific finality tests @@ -16,7 +10,7 @@ if __name__ == "__main__": all_mods = { PHASE0: phase_0_mods, ALTAIR: altair_mods, - MERGE: spec_merge, + MERGE: merge_mods, } - run_state_test_generators(runner_name="finality", specs=specs, all_mods=all_mods) + run_state_test_generators(runner_name="finality", all_mods=all_mods) diff --git a/tests/generators/fork_choice/main.py b/tests/generators/fork_choice/main.py index ae15caa1d..f162d9564 100644 --- a/tests/generators/fork_choice/main.py +++ b/tests/generators/fork_choice/main.py @@ -1,13 +1,7 @@ from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators -from eth2spec.phase0 import spec as spec_phase0 -from eth2spec.altair import spec as spec_altair -from eth2spec.merge import spec as spec_merge from eth2spec.test.helpers.constants import PHASE0, ALTAIR, MERGE -specs = (spec_phase0, spec_altair, spec_merge) - - if __name__ == "__main__": phase_0_mods = {key: 'eth2spec.test.phase0.fork_choice.test_' + key for key in [ 'get_head', @@ -23,4 +17,4 @@ if __name__ == "__main__": MERGE: merge_mods, } - run_state_test_generators(runner_name="fork_choice", specs=specs, all_mods=all_mods) + run_state_test_generators(runner_name="fork_choice", all_mods=all_mods) diff --git a/tests/generators/forks/main.py b/tests/generators/forks/main.py index 33d706d73..7be79847d 100644 --- a/tests/generators/forks/main.py +++ b/tests/generators/forks/main.py @@ -1,23 +1,17 @@ -from importlib import reload from typing import Iterable from eth2spec.test.helpers.constants import PHASE0, ALTAIR, MINIMAL, MAINNET -from eth2spec.config import config_util +from eth2spec.test.helpers.typing import SpecForkName, PresetBaseName from eth2spec.test.altair.fork import test_altair_fork_basic, test_altair_fork_random -from eth2spec.phase0 import spec as spec_phase0 -from eth2spec.altair import spec as spec_altair - 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, phase: str, fork_name: str) -> gen_typing.TestProvider: +def create_provider(tests_src, preset_name: PresetBaseName, + phase: SpecForkName, fork_name: SpecForkName) -> gen_typing.TestProvider: - def prepare_fn(configs_path: str) -> str: - config_util.prepare_config(configs_path, config_name) - reload(spec_phase0) - reload(spec_altair) - return config_name + def prepare_fn() -> None: + return def cases_fn() -> Iterable[gen_typing.TestCase]: return generate_from_tests( @@ -25,6 +19,7 @@ def create_provider(tests_src, config_name: str, phase: str, fork_name: str) -> handler_name='fork', src=tests_src, fork_name=fork_name, + preset_name=preset_name, phase=phase, ) @@ -34,7 +29,7 @@ def create_provider(tests_src, config_name: str, phase: str, fork_name: str) -> if __name__ == "__main__": gen_runner.run_generator("forks", [ create_provider(test_altair_fork_basic, MINIMAL, PHASE0, ALTAIR), - create_provider(test_altair_fork_random, MINIMAL, PHASE0, ALTAIR), create_provider(test_altair_fork_basic, MAINNET, PHASE0, ALTAIR), + create_provider(test_altair_fork_random, MINIMAL, PHASE0, ALTAIR), create_provider(test_altair_fork_random, MAINNET, PHASE0, ALTAIR), ]) diff --git a/tests/generators/genesis/main.py b/tests/generators/genesis/main.py index 3b4d045a3..8e0294bf0 100644 --- a/tests/generators/genesis/main.py +++ b/tests/generators/genesis/main.py @@ -1,12 +1,7 @@ from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators -from eth2spec.phase0 import spec as spec_phase0 -from eth2spec.altair import spec as spec_altair from eth2spec.test.helpers.constants import PHASE0, ALTAIR -specs = (spec_phase0, spec_altair) - - if __name__ == "__main__": phase_0_mods = {key: 'eth2spec.test.phase0.genesis.test_' + key for key in [ 'initialization', @@ -18,4 +13,4 @@ if __name__ == "__main__": ALTAIR: altair_mods, } - run_state_test_generators(runner_name="genesis", specs=specs, all_mods=all_mods) + run_state_test_generators(runner_name="genesis", all_mods=all_mods) diff --git a/tests/generators/operations/main.py b/tests/generators/operations/main.py index 316ccdf10..554d0b30a 100644 --- a/tests/generators/operations/main.py +++ b/tests/generators/operations/main.py @@ -1,13 +1,7 @@ from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators -from eth2spec.phase0 import spec as spec_phase0 -from eth2spec.altair import spec as spec_altair -from eth2spec.merge import spec as spec_merge from eth2spec.test.helpers.constants import PHASE0, ALTAIR, MERGE -specs = (spec_phase0, spec_altair, spec_merge) - - if __name__ == "__main__": phase_0_mods = {key: 'eth2spec.test.phase0.block_processing.test_process_' + key for key in [ 'attestation', @@ -46,4 +40,4 @@ if __name__ == "__main__": MERGE: merge_mods, } - run_state_test_generators(runner_name="operations", specs=specs, all_mods=all_mods) + run_state_test_generators(runner_name="operations", all_mods=all_mods) diff --git a/tests/generators/rewards/main.py b/tests/generators/rewards/main.py index 8e50732e1..a3072daca 100644 --- a/tests/generators/rewards/main.py +++ b/tests/generators/rewards/main.py @@ -1,13 +1,7 @@ from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators -from eth2spec.phase0 import spec as spec_phase0 -from eth2spec.altair import spec as spec_altair -from eth2spec.merge import spec as spec_merge from eth2spec.test.helpers.constants import PHASE0, ALTAIR, MERGE -specs = (spec_phase0, spec_altair, spec_merge) - - if __name__ == "__main__": phase_0_mods = {key: 'eth2spec.test.phase0.rewards.test_' + key for key in [ 'basic', @@ -28,4 +22,4 @@ if __name__ == "__main__": MERGE: merge_mods, } - run_state_test_generators(runner_name="rewards", specs=specs, all_mods=all_mods) + run_state_test_generators(runner_name="rewards", all_mods=all_mods) diff --git a/tests/generators/sanity/main.py b/tests/generators/sanity/main.py index 3bed6672d..8caedc8e5 100644 --- a/tests/generators/sanity/main.py +++ b/tests/generators/sanity/main.py @@ -1,14 +1,7 @@ -from eth2spec.phase0 import spec as spec_phase0 -from eth2spec.altair import spec as spec_altair -from eth2spec.merge import spec as spec_merge from eth2spec.test.helpers.constants import PHASE0, ALTAIR, MERGE - from eth2spec.gen_helpers.gen_from_tests.gen import run_state_test_generators -specs = (spec_phase0, spec_altair, spec_merge) - - if __name__ == "__main__": phase_0_mods = {key: 'eth2spec.test.phase0.sanity.test_' + key for key in [ 'blocks', @@ -29,4 +22,4 @@ if __name__ == "__main__": MERGE: merge_mods, } - run_state_test_generators(runner_name="sanity", specs=specs, all_mods=all_mods) + run_state_test_generators(runner_name="sanity", all_mods=all_mods) diff --git a/tests/generators/shuffling/main.py b/tests/generators/shuffling/main.py index 73b714760..b85fd42a2 100644 --- a/tests/generators/shuffling/main.py +++ b/tests/generators/shuffling/main.py @@ -1,15 +1,14 @@ from eth_utils import to_tuple from typing import Iterable -from importlib import reload from eth2spec.gen_helpers.gen_base import gen_runner, gen_typing +from eth2spec.test.helpers.typing import PresetBaseName -from eth2spec.config import config_util -from eth2spec.phase0 import spec as spec -from eth2spec.test.helpers.constants import PHASE0 +from eth2spec.phase0 import mainnet as spec_mainnet, minimal as spec_minimal +from eth2spec.test.helpers.constants import PHASE0, MINIMAL, MAINNET -def shuffling_case_fn(seed, count): +def shuffling_case_fn(spec, seed, count): yield 'mapping', 'data', { 'seed': '0x' + seed.hex(), 'count': count, @@ -17,28 +16,33 @@ def shuffling_case_fn(seed, count): } -def shuffling_case(seed, count): - return f'shuffle_0x{seed.hex()}_{count}', lambda: shuffling_case_fn(seed, count) +def shuffling_case(spec, seed, count): + return f'shuffle_0x{seed.hex()}_{count}', lambda: shuffling_case_fn(spec, seed, count) @to_tuple -def shuffling_test_cases(): +def shuffling_test_cases(spec): for seed in [spec.hash(seed_init_value.to_bytes(length=4, byteorder='little')) for seed_init_value in range(30)]: for count in [0, 1, 2, 3, 5, 10, 33, 100, 1000, 9999]: - yield shuffling_case(seed, count) + yield shuffling_case(spec, seed, count) -def create_provider(config_name: str) -> gen_typing.TestProvider: +def create_provider(preset_name: PresetBaseName) -> gen_typing.TestProvider: - def prepare_fn(configs_path: str) -> str: - config_util.prepare_config(configs_path, config_name) - reload(spec) - return config_name + def prepare_fn() -> None: + return def cases_fn() -> Iterable[gen_typing.TestCase]: - for (case_name, case_fn) in shuffling_test_cases(): + if preset_name == MAINNET: + spec = spec_mainnet + elif preset_name == MINIMAL: + spec = spec_minimal + else: + raise Exception(f"unrecognized preset: {preset_name}") + for (case_name, case_fn) in shuffling_test_cases(spec): yield gen_typing.TestCase( fork_name=PHASE0, + preset_name=preset_name, runner_name='shuffling', handler_name='core', suite_name='shuffle', @@ -50,4 +54,4 @@ def create_provider(config_name: str) -> gen_typing.TestProvider: if __name__ == "__main__": - gen_runner.run_generator("shuffling", [create_provider("minimal"), create_provider("mainnet")]) + gen_runner.run_generator("shuffling", [create_provider(MINIMAL), create_provider(MAINNET)]) diff --git a/tests/generators/ssz_generic/main.py b/tests/generators/ssz_generic/main.py index e6cd3d976..2e96ce2e8 100644 --- a/tests/generators/ssz_generic/main.py +++ b/tests/generators/ssz_generic/main.py @@ -11,13 +11,14 @@ from eth2spec.test.helpers.constants import PHASE0 def create_provider(handler_name: str, suite_name: str, case_maker) -> gen_typing.TestProvider: - def prepare_fn(configs_path: str) -> str: - return "general" + def prepare_fn() -> None: + return def cases_fn() -> Iterable[gen_typing.TestCase]: for (case_name, case_fn) in case_maker(): yield gen_typing.TestCase( fork_name=PHASE0, + preset_name="general", runner_name='ssz_generic', handler_name=handler_name, suite_name=suite_name, diff --git a/tests/generators/ssz_static/main.py b/tests/generators/ssz_static/main.py index d86636e85..3f894ea79 100644 --- a/tests/generators/ssz_static/main.py +++ b/tests/generators/ssz_static/main.py @@ -1,16 +1,12 @@ from random import Random from typing import Iterable -from importlib import reload from inspect import getmembers, isclass from eth2spec.gen_helpers.gen_base import gen_runner, gen_typing from eth2spec.debug import random_value, encode -from eth2spec.config import config_util -from eth2spec.phase0 import spec as spec_phase0 -from eth2spec.altair import spec as spec_altair -from eth2spec.merge import spec as spec_merge -from eth2spec.test.helpers.constants import ALTAIR, MERGE, TESTGEN_FORKS, MINIMAL, MAINNET +from eth2spec.test.helpers.constants import TESTGEN_FORKS, MINIMAL, MAINNET +from eth2spec.test.context import spec_targets from eth2spec.utils.ssz.ssz_typing import Container from eth2spec.utils.ssz.ssz_impl import ( hash_tree_root, @@ -40,7 +36,7 @@ def get_spec_ssz_types(spec): ] -def ssz_static_cases(fork_name: str, seed: int, name, ssz_type, +def ssz_static_cases(fork_name: str, preset_name: str, seed: int, name, ssz_type, mode: random_value.RandomizationMode, chaos: bool, count: int): random_mode_name = mode.to_name() @@ -50,6 +46,7 @@ def ssz_static_cases(fork_name: str, seed: int, name, ssz_type, for i in range(count): yield gen_typing.TestCase( fork_name=fork_name, + preset_name=preset_name, runner_name='ssz_static', handler_name=name, suite_name=f"ssz_{random_mode_name}{'_chaos' if chaos else ''}", @@ -58,26 +55,17 @@ def ssz_static_cases(fork_name: str, seed: int, name, ssz_type, ) -def create_provider(fork_name, config_name: str, seed: int, mode: random_value.RandomizationMode, chaos: bool, +def create_provider(fork_name, preset_name: str, seed: int, mode: random_value.RandomizationMode, chaos: bool, cases_if_random: int) -> gen_typing.TestProvider: - def prepare_fn(configs_path: str) -> str: - # Apply changes to presets, this affects some of the vector types. - config_util.prepare_config(configs_path, config_name) - reload(spec_phase0) - reload(spec_altair) - reload(spec_merge) - return config_name + def prepare_fn() -> None: + return def cases_fn() -> Iterable[gen_typing.TestCase]: count = cases_if_random if chaos or mode.is_changing() else 1 - spec = spec_phase0 - if fork_name == ALTAIR: - spec = spec_altair - elif fork_name == MERGE: - spec = spec_merge + spec = spec_targets[preset_name][fork_name] 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) + yield from ssz_static_cases(fork_name, preset_name, seed * 1000 + i, name, ssz_type, mode, chaos, count) return gen_typing.TestProvider(prepare=prepare_fn, make_cases=cases_fn) @@ -95,6 +83,6 @@ if __name__ == "__main__": seed += 1 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 + create_provider(fork, preset_name, seed, mode, chaos, cases_if_random) + for (seed, preset_name, mode, chaos, cases_if_random) in settings ]) diff --git a/tests/generators/transition/main.py b/tests/generators/transition/main.py index b7fd7b0a8..2ded56a13 100644 --- a/tests/generators/transition/main.py +++ b/tests/generators/transition/main.py @@ -1,23 +1,16 @@ -from importlib import reload from typing import Iterable from eth2spec.test.helpers.constants import ALTAIR, MINIMAL, MAINNET, PHASE0 -from eth2spec.config import config_util from eth2spec.test.altair.transition import test_transition as test_altair_transition -from eth2spec.phase0 import spec as spec_phase0 -from eth2spec.altair import spec as spec_altair 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, pre_fork_name: str, post_fork_name: str) -> gen_typing.TestProvider: +def create_provider(tests_src, preset_name: str, pre_fork_name: str, post_fork_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_altair) - return config_name + def prepare_fn() -> None: + return def cases_fn() -> Iterable[gen_typing.TestCase]: return generate_from_tests( @@ -26,6 +19,7 @@ def create_provider(tests_src, config_name: str, pre_fork_name: str, post_fork_n src=tests_src, fork_name=post_fork_name, phase=pre_fork_name, + preset_name=preset_name, ) return gen_typing.TestProvider(prepare=prepare_fn, make_cases=cases_fn)