diff --git a/setup.py b/setup.py index 9eb7a1b55..2f28a75ee 100644 --- a/setup.py +++ b/setup.py @@ -303,14 +303,6 @@ class SpecBuilder(ABC): """ raise NotImplementedError() - @classmethod - @abstractmethod - def invariant_checks(cls) -> str: - """ - The invariant checks - """ - raise NotImplementedError() - @classmethod @abstractmethod def implement_optimizations(cls, functions: Dict[str, str]) -> Dict[str, str]: @@ -436,10 +428,6 @@ get_attesting_indices = cache_this( def hardcoded_custom_type_dep_constants(cls) -> Dict[str, str]: return {} - @classmethod - def invariant_checks(cls) -> str: - return '' - @classmethod def implement_optimizations(cls, functions: Dict[str, str]) -> Dict[str, str]: return functions @@ -490,13 +478,6 @@ def get_generalized_index(ssz_class: Any, *path: Sequence[Union[int, SSZVariable } return {**super().hardcoded_ssz_dep_constants(), **constants} - @classmethod - def invariant_checks(cls) -> str: - return ''' -assert ( - TIMELY_HEAD_WEIGHT + TIMELY_SOURCE_WEIGHT + TIMELY_TARGET_WEIGHT + SYNC_REWARD_WEIGHT + PROPOSER_WEIGHT -) == WEIGHT_DENOMINATOR''' - @classmethod def implement_optimizations(cls, functions: Dict[str, str]) -> Dict[str, str]: if "eth2_aggregate_pubkeys" in functions: @@ -668,7 +649,6 @@ def objects_to_spec(preset_name: str, # Since some constants are hardcoded in setup.py, the following assertions verify that the hardcoded constants are # as same as the spec definition. + ('\n\n\n' + ssz_dep_constants_verification if ssz_dep_constants_verification != '' else '') - + ('\n' + builder.invariant_checks() if builder.invariant_checks() != '' else '') + '\n' ) return spec diff --git a/tests/core/pyspec/eth2spec/test/altair/unittests/__init__.py b/tests/core/pyspec/eth2spec/test/altair/unittests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/core/pyspec/eth2spec/test/altair/unittests/test_config_invariants.py b/tests/core/pyspec/eth2spec/test/altair/unittests/test_config_invariants.py new file mode 100644 index 000000000..4443f97e0 --- /dev/null +++ b/tests/core/pyspec/eth2spec/test/altair/unittests/test_config_invariants.py @@ -0,0 +1,23 @@ +from eth2spec.test.context import ( + spec_state_test, + with_phases, +) +from eth2spec.test.helpers.constants import ALTAIR + + +@with_phases([ALTAIR]) +@spec_state_test +def test_weight_denominator(spec, state): + assert ( + spec.TIMELY_HEAD_WEIGHT + + spec.TIMELY_SOURCE_WEIGHT + + spec.TIMELY_TARGET_WEIGHT + + spec.SYNC_REWARD_WEIGHT + + spec.PROPOSER_WEIGHT + ) == spec.WEIGHT_DENOMINATOR + + +@with_phases([ALTAIR]) +@spec_state_test +def test_inactivity_score(spec, state): + assert spec.config.INACTIVITY_SCORE_BIAS <= spec.config.INACTIVITY_SCORE_RECOVERY_RATE diff --git a/tests/core/pyspec/eth2spec/test/helpers/constants.py b/tests/core/pyspec/eth2spec/test/helpers/constants.py index 4e98845c4..8f116dc3d 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/constants.py +++ b/tests/core/pyspec/eth2spec/test/helpers/constants.py @@ -32,3 +32,9 @@ MAINNET = PresetBaseName('mainnet') MINIMAL = PresetBaseName('minimal') ALL_PRESETS = (MINIMAL, MAINNET) + + +# +# Number +# +MAX_UINT_64 = 2**64 - 1 diff --git a/tests/core/pyspec/eth2spec/test/phase0/unittests/__init__.py b/tests/core/pyspec/eth2spec/test/phase0/unittests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/core/pyspec/eth2spec/test/phase0/unittests/test_config_invariants.py b/tests/core/pyspec/eth2spec/test/phase0/unittests/test_config_invariants.py new file mode 100644 index 000000000..b39b011b4 --- /dev/null +++ b/tests/core/pyspec/eth2spec/test/phase0/unittests/test_config_invariants.py @@ -0,0 +1,74 @@ +from eth2spec.test.context import ( + spec_state_test, + with_all_phases, + is_post_altair, +) +from eth2spec.test.helpers.constants import MAX_UINT_64 + + +def check_bound(value, lower_bound, upper_bound): + assert value >= lower_bound + assert value <= upper_bound + + +@with_all_phases +@spec_state_test +def test_validators(spec, state): + check_bound(spec.VALIDATOR_REGISTRY_LIMIT, 1, MAX_UINT_64) + check_bound(spec.MAX_COMMITTEES_PER_SLOT, 1, MAX_UINT_64) + check_bound(spec.TARGET_COMMITTEE_SIZE, 1, MAX_UINT_64) + + # Note: can be less if you assume stricters bounds on validator set based on total ETH supply + maximum_validators_per_committee = ( + spec.VALIDATOR_REGISTRY_LIMIT + // spec.SLOTS_PER_EPOCH + // spec.MAX_COMMITTEES_PER_SLOT + ) + check_bound(spec.MAX_VALIDATORS_PER_COMMITTEE, 1, maximum_validators_per_committee) + check_bound(spec.config.MIN_PER_EPOCH_CHURN_LIMIT, 1, spec.VALIDATOR_REGISTRY_LIMIT) + check_bound(spec.config.CHURN_LIMIT_QUOTIENT, 1, spec.VALIDATOR_REGISTRY_LIMIT) + + check_bound(spec.config.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT, spec.TARGET_COMMITTEE_SIZE, MAX_UINT_64) + + +@with_all_phases +@spec_state_test +def test_balances(spec, state): + assert spec.MAX_EFFECTIVE_BALANCE % spec.EFFECTIVE_BALANCE_INCREMENT == 0 + check_bound(spec.MIN_DEPOSIT_AMOUNT, 1, MAX_UINT_64) + check_bound(spec.MAX_EFFECTIVE_BALANCE, spec.MIN_DEPOSIT_AMOUNT, MAX_UINT_64) + check_bound(spec.MAX_EFFECTIVE_BALANCE, spec.EFFECTIVE_BALANCE_INCREMENT, MAX_UINT_64) + + +@with_all_phases +@spec_state_test +def test_hysteresis_quotient(spec, state): + check_bound(spec.HYSTERESIS_QUOTIENT, 1, MAX_UINT_64) + check_bound(spec.HYSTERESIS_DOWNWARD_MULTIPLIER, 1, spec.HYSTERESIS_QUOTIENT) + check_bound(spec.HYSTERESIS_UPWARD_MULTIPLIER, spec.HYSTERESIS_QUOTIENT, MAX_UINT_64) + + +@with_all_phases +@spec_state_test +def test_incentives(spec, state): + # Ensure no ETH is minted in slash_validator + if is_post_altair(spec): + assert spec.MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR <= spec.WHISTLEBLOWER_REWARD_QUOTIENT + else: + assert spec.MIN_SLASHING_PENALTY_QUOTIENT <= spec.WHISTLEBLOWER_REWARD_QUOTIENT + + +@with_all_phases +@spec_state_test +def test_time(spec, state): + assert spec.SLOTS_PER_EPOCH <= spec.SLOTS_PER_HISTORICAL_ROOT + assert spec.MIN_SEED_LOOKAHEAD < spec.MAX_SEED_LOOKAHEAD + assert spec.SLOTS_PER_HISTORICAL_ROOT % spec.SLOTS_PER_EPOCH == 0 + check_bound(spec.SLOTS_PER_HISTORICAL_ROOT, spec.SLOTS_PER_EPOCH, MAX_UINT_64) + check_bound(spec.MIN_ATTESTATION_INCLUSION_DELAY, 1, spec.SLOTS_PER_EPOCH) + + +@with_all_phases +@spec_state_test +def test_networking(spec, state): + assert spec.RANDOM_SUBNETS_PER_VALIDATOR <= spec.ATTESTATION_SUBNET_COUNT diff --git a/tests/core/pyspec/eth2spec/test/phase0/unittests/validator/__init__.py b/tests/core/pyspec/eth2spec/test/phase0/unittests/validator/__init__.py new file mode 100644 index 000000000..e69de29bb