Merge pull request #2390 from ethereum/config-rework

Separation of Constant, Preset and Configuration variables
This commit is contained in:
Danny Ryan
2021-05-21 13:49:19 -06:00
committed by GitHub
90 changed files with 1100 additions and 956 deletions

3
.gitignore vendored
View File

@@ -29,3 +29,6 @@ tests/core/pyspec/test-reports
tests/core/pyspec/eth2spec/test_results.xml
*.egg-info
# TOC tool outputs temporary files
*.tmp

View File

@@ -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

View File

@@ -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.

71
configs/mainnet.yaml Normal file
View File

@@ -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

View File

@@ -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

View File

@@ -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

71
configs/minimal.yaml Normal file
View File

@@ -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

View File

@@ -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

View File

@@ -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

26
presets/README.md Normal file
View File

@@ -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).

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,3 @@
# Mainnet preset - The Merge
# No presets here.

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,3 @@
# Minimal preset - The Merge
# No presets here.

View File

@@ -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

View File

@@ -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

314
setup.py
View File

@@ -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,
]
)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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')` |

View File

@@ -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

View File

@@ -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 |
| - | - | :-: | :-: |

View File

@@ -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

View File

@@ -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)

View File

@@ -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.

View File

@@ -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

View File

@@ -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)
)

View File

@@ -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]]

View File

@@ -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,
))

View File

@@ -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

View File

@@ -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)

View File

@@ -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):

View File

@@ -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))

View File

@@ -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):

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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(),

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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)

View File

@@ -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,

View File

@@ -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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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,
),

View File

@@ -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)}

View File

@@ -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)

View File

@@ -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 (

View File

@@ -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)

View File

@@ -1,4 +1,4 @@
from typing import NewType
SpecForkName = NewType("SpecForkName", str)
ConfigName = NewType("ConfigName", str)
PresetBaseName = NewType("PresetBaseName", str)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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):

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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,

View File

@@ -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,
)

View File

@@ -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

View File

@@ -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',

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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),
])

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)])

View File

@@ -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,

View File

@@ -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
])

View File

@@ -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)