Skip to content

Commit

Permalink
Merge pull request #2444 from ethereum/invariant-checks
Browse files Browse the repository at this point in the history
Add some invariant checks to pyspec unit tests
  • Loading branch information
djrtwo authored Jun 7, 2021
2 parents ad1e51a + 8ba740a commit b97972c
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 20 deletions.
20 changes: 0 additions & 20 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,14 +303,6 @@ def hardcoded_custom_type_dep_constants(cls) -> Dict[str, str]: # TODO
"""
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]:
Expand Down Expand Up @@ -436,10 +428,6 @@ def hardcoded_ssz_dep_constants(cls) -> Dict[str, str]:
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
Expand Down Expand Up @@ -490,13 +478,6 @@ def hardcoded_ssz_dep_constants(cls) -> Dict[str, str]:
}
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:
Expand Down Expand Up @@ -668,7 +649,6 @@ def format_constant(name: str, vardef: VariableDefinition) -> 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
Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -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
6 changes: 6 additions & 0 deletions tests/core/pyspec/eth2spec/test/helpers/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,9 @@
MINIMAL = PresetBaseName('minimal')

ALL_PRESETS = (MINIMAL, MAINNET)


#
# Number
#
MAX_UINT_64 = 2**64 - 1
Empty file.
Original file line number Diff line number Diff line change
@@ -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
Empty file.

0 comments on commit b97972c

Please sign in to comment.