Merge branch 'ci-phasesconfig' into lc-eph

This commit is contained in:
Etan Kissling 2022-12-12 00:36:13 +01:00
commit 08a2080937
No known key found for this signature in database
GPG Key ID: B21DA824C5A3D03D
2 changed files with 77 additions and 21 deletions

View File

@ -1,11 +1,15 @@
from eth2spec.test.context import (
spec_configured_state_test,
spec_state_test_with_matching_config,
spec_test,
with_all_phases,
with_config_overrides,
with_matching_spec_config,
with_phases,
with_state,
)
from eth2spec.test.helpers.constants import (
PHASE0, ALTAIR,
PHASE0, ALTAIR, BELLATRIX,
ALL_PHASES,
)
from eth2spec.test.helpers.forks import is_post_fork
@ -30,7 +34,7 @@ def test_config_override(spec, state):
@with_all_phases
@spec_state_test_with_matching_config
def test_override_config_fork_epoch(spec, state):
def test_config_override_matching_fork_epochs(spec, state):
# Fork schedule must be consistent with state fork
epoch = spec.get_current_epoch(state)
if is_post_fork(spec.fork, ALTAIR):
@ -56,3 +60,27 @@ def test_override_config_fork_epoch(spec, state):
continue
fork_epoch_field = fork.upper() + '_FORK_EPOCH'
assert getattr(spec.config, fork_epoch_field) <= epoch
@with_phases(phases=[ALTAIR], other_phases=[BELLATRIX])
@spec_test
@with_config_overrides({
'ALTAIR_FORK_VERSION': '0x11111111',
'BELLATRIX_FORK_EPOCH': 4,
}, emit=False)
@with_state
@with_matching_spec_config(emitted_fork=BELLATRIX)
def test_config_override_across_phases(spec, phases, state):
assert state.fork.current_version == spec.config.ALTAIR_FORK_VERSION
assert spec.config.ALTAIR_FORK_VERSION == spec.Version('0x11111111')
assert spec.config.ALTAIR_FORK_EPOCH == 0
assert not hasattr(spec.config, 'BELLATRIX_FORK_EPOCH')
assert phases[ALTAIR].config.ALTAIR_FORK_VERSION == spec.Version('0x11111111')
assert phases[ALTAIR].config.ALTAIR_FORK_EPOCH == 0
assert not hasattr(phases[ALTAIR].config, 'BELLATRIX_FORK_EPOCH')
assert phases[ALTAIR].config.ALTAIR_FORK_VERSION == spec.Version('0x11111111')
assert phases[BELLATRIX].config.ALTAIR_FORK_EPOCH == 0
assert phases[BELLATRIX].config.BELLATRIX_FORK_EPOCH == 4

View File

@ -1,4 +1,5 @@
import pytest
from copy import deepcopy
from dataclasses import dataclass
import importlib
@ -303,14 +304,18 @@ def config_fork_epoch_overrides(spec, state):
return overrides
def spec_state_test_with_matching_config(fn):
def with_matching_spec_config(emitted_fork=None):
def decorator(fn):
def wrapper(*args, spec: Spec, **kw):
conf = config_fork_epoch_overrides(spec, kw['state'])
overrides = with_config_overrides(conf)
return overrides(fn)(*args, spec=spec, **kw)
overrides = config_fork_epoch_overrides(spec, kw['state'])
deco = with_config_overrides(overrides, emitted_fork)
return deco(fn)(*args, spec=spec, **kw)
return wrapper
return spec_test(with_state(decorator(single_phase(fn))))
return decorator
def spec_state_test_with_matching_config(fn):
return spec_test(with_state(with_matching_spec_config()(single_phase(fn))))
def expect_assertion_error(fn):
@ -551,10 +556,30 @@ def _get_copy_of_spec(spec):
module_spec = importlib.util.find_spec(module_path)
module = importlib.util.module_from_spec(module_spec)
module_spec.loader.exec_module(module)
# Preserve existing config overrides
module.config = deepcopy(spec.config)
return module
def with_config_overrides(config_overrides):
def spec_with_config_overrides(spec, config_overrides):
# apply our overrides to a copy of it, and apply it to the spec
config = spec.config._asdict()
config.update((k, config_overrides[k]) for k in config.keys() & config_overrides.keys())
config_types = spec.Configuration.__annotations__
modified_config = {k: config_types[k](v) for k, v in config.items()}
spec.config = spec.Configuration(**modified_config)
# To output the changed config in a format compatible with yaml test vectors,
# the dict SSZ objects have to be converted into Python built-in types.
output_config = _get_basic_dict(modified_config)
return spec, output_config
def with_config_overrides(config_overrides, emitted_fork=None, emit=True):
"""
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.
@ -564,23 +589,26 @@ def with_config_overrides(config_overrides):
"""
def decorator(fn):
def wrapper(*args, spec: Spec, **kw):
spec = _get_copy_of_spec(spec)
# Apply config overrides to spec
spec, output_config = spec_with_config_overrides(_get_copy_of_spec(spec), config_overrides)
# apply our overrides to a copy of it, and apply it to the spec
config = spec.config._asdict()
config.update(config_overrides)
config_types = spec.Configuration.__annotations__
modified_config = {k: config_types[k](v) for k, v in config.items()}
# To output the changed config to could be serialized with yaml test vectors,
# the dict SSZ objects have to be converted into Python built-in types.
output_config = _get_basic_dict(modified_config)
yield 'config', 'cfg', output_config
spec.config = spec.Configuration(**modified_config)
# Apply config overrides to additional phases, if present
if 'phases' in kw:
phases = {}
for fork in kw['phases']:
phases[fork], output = \
spec_with_config_overrides(_get_copy_of_spec(kw['phases'][fork]), config_overrides)
if emitted_fork == fork:
output_config = output
kw['phases'] = phases
# Run the function
out = fn(*args, spec=spec, **kw)
# Emit requested spec (with overrides)
if emit:
yield 'config', 'cfg', output_config
# 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: