Merge branch 'dev' into lc-branchtypes

This commit is contained in:
Etan Kissling 2024-01-09 14:35:31 +01:00
commit 05c2ce11db
No known key found for this signature in database
GPG Key ID: B21DA824C5A3D03D
16 changed files with 300 additions and 228 deletions

2
.dockerignore Normal file
View File

@ -0,0 +1,2 @@
**/venv
**/.venv

View File

@ -66,6 +66,37 @@ jobs:
- name: Run linter for test generators - name: Run linter for test generators
run: make lint_generators run: make lint_generators
dockerfile-test:
runs-on: self-hosted
needs: preclear
services:
registry:
image: registry:2
ports:
- 5000:5000
steps:
- name: Checkout this repo
uses: actions/checkout@v3.2.0
- name: get git commit hash
id: git_commit_hash
shell: bash
run: |
echo "git_commit_hash=$(echo $(git log --pretty=format:'%h' -n 1))" >> $GITHUB_OUTPUT
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
with:
driver-opts: network=host
- name: Build and push to local registry
uses: docker/build-push-action@v4
with:
context: .
file: ./docker/Dockerfile
push: true
tags: localhost:5000/consensus-specs-dockerfile-test:${{ steps.git_commit_hash.outputs.git_commit_hash }}
- name: Test the image by running the linter
run: |
docker run localhost:5000/consensus-specs-dockerfile-test:${{ steps.git_commit_hash.outputs.git_commit_hash }} make lint
pyspec-tests: pyspec-tests:
runs-on: self-hosted runs-on: self-hosted
needs: [preclear,lint,codespell,table_of_contents] needs: [preclear,lint,codespell,table_of_contents]

3
.gitignore vendored
View File

@ -46,3 +46,6 @@ docs/ssz
docs/fork_choice docs/fork_choice
docs/README.md docs/README.md
site site
# docker test results
testResults

View File

@ -14,6 +14,7 @@ SOLIDITY_FILE_NAME = deposit_contract.json
DEPOSIT_CONTRACT_TESTER_DIR = ${SOLIDITY_DEPOSIT_CONTRACT_DIR}/web3_tester DEPOSIT_CONTRACT_TESTER_DIR = ${SOLIDITY_DEPOSIT_CONTRACT_DIR}/web3_tester
CONFIGS_DIR = ./configs CONFIGS_DIR = ./configs
TEST_PRESET_TYPE ?= minimal TEST_PRESET_TYPE ?= minimal
NUMBER_OF_CORES=16
# Collect a list of generator names # Collect a list of generator names
GENERATORS = $(sort $(dir $(wildcard $(GENERATOR_DIR)/*/.))) GENERATORS = $(sort $(dir $(wildcard $(GENERATOR_DIR)/*/.)))
# Map this list of generator paths to "gen_{generator name}" entries # Map this list of generator paths to "gen_{generator name}" entries
@ -34,11 +35,11 @@ MARKDOWN_FILES = $(wildcard $(SPEC_DIR)/*/*.md) \
$(wildcard $(SPEC_DIR)/_features/*/*/*.md) \ $(wildcard $(SPEC_DIR)/_features/*/*/*.md) \
$(wildcard $(SSZ_DIR)/*.md) $(wildcard $(SSZ_DIR)/*.md)
ALL_EXECUTABLE_SPECS = phase0 altair bellatrix capella deneb eip6110 whisk ALL_EXECUTABLE_SPEC_NAMES = phase0 altair bellatrix capella deneb eip6110 eip7002 whisk
# The parameters for commands. Use `foreach` to avoid listing specs again. # The parameters for commands. Use `foreach` to avoid listing specs again.
COVERAGE_SCOPE := $(foreach S,$(ALL_EXECUTABLE_SPECS), --cov=eth2spec.$S.$(TEST_PRESET_TYPE)) COVERAGE_SCOPE := $(foreach S,$(ALL_EXECUTABLE_SPEC_NAMES), --cov=eth2spec.$S.$(TEST_PRESET_TYPE))
PYLINT_SCOPE := $(foreach S,$(ALL_EXECUTABLE_SPECS), ./eth2spec/$S) PYLINT_SCOPE := $(foreach S,$(ALL_EXECUTABLE_SPEC_NAMES), ./eth2spec/$S)
MYPY_SCOPE := $(foreach S,$(ALL_EXECUTABLE_SPECS), -p eth2spec.$S) MYPY_SCOPE := $(foreach S,$(ALL_EXECUTABLE_SPEC_NAMES), -p eth2spec.$S)
COV_HTML_OUT=.htmlcov COV_HTML_OUT=.htmlcov
COV_HTML_OUT_DIR=$(PY_SPEC_DIR)/$(COV_HTML_OUT) COV_HTML_OUT_DIR=$(PY_SPEC_DIR)/$(COV_HTML_OUT)
@ -74,7 +75,7 @@ partial_clean:
rm -rf $(TEST_REPORT_DIR) rm -rf $(TEST_REPORT_DIR)
rm -rf eth2spec.egg-info dist build rm -rf eth2spec.egg-info dist build
rm -rf build; rm -rf build;
@for spec_name in $(ALL_EXECUTABLE_SPECS) ; do \ @for spec_name in $(ALL_EXECUTABLE_SPEC_NAMES) ; do \
echo $$spec_name; \ echo $$spec_name; \
rm -rf $(ETH2SPEC_MODULE_DIR)/$$spec_name; \ rm -rf $(ETH2SPEC_MODULE_DIR)/$$spec_name; \
done done
@ -128,10 +129,10 @@ citest: pyspec
mkdir -p $(TEST_REPORT_DIR); mkdir -p $(TEST_REPORT_DIR);
ifdef fork ifdef fork
. venv/bin/activate; cd $(PY_SPEC_DIR); \ . venv/bin/activate; cd $(PY_SPEC_DIR); \
python3 -m pytest -n 16 --bls-type=fastest --preset=$(TEST_PRESET_TYPE) --fork=$(fork) --junitxml=test-reports/test_results.xml eth2spec python3 -m pytest -n $(NUMBER_OF_CORES) --bls-type=fastest --preset=$(TEST_PRESET_TYPE) --fork=$(fork) --junitxml=test-reports/test_results.xml eth2spec
else else
. venv/bin/activate; cd $(PY_SPEC_DIR); \ . venv/bin/activate; cd $(PY_SPEC_DIR); \
python3 -m pytest -n 16 --bls-type=fastest --preset=$(TEST_PRESET_TYPE) --junitxml=test-reports/test_results.xml eth2spec python3 -m pytest -n $(NUMBER_OF_CORES) --bls-type=fastest --preset=$(TEST_PRESET_TYPE) --junitxml=test-reports/test_results.xml eth2spec
endif endif

22
docker/Dockerfile Normal file
View File

@ -0,0 +1,22 @@
# Rename the build stage from 'base' to 'builder' for clarification and code readability
FROM python:3.11.0-slim-bullseye as builder
ENV DEBIAN_FRONTEND=noninteractive \
WORKDIR=/consensus-specs \
PIP_UPGRADE_CMD="python -m pip install --upgrade pip" \
INSTALL_CMD="apt install -y git build-essential"
RUN mkdir ${WORKDIR}
WORKDIR ${WORKDIR}
# Chain the commands together
RUN apt update && ${INSTALL_CMD} && ${PIP_UPGRADE_CMD} && rm -rf /var/lib/apt/lists/*
# Copy the current directory contents into the builder
COPY . .
# Inline installation commands
RUN make install_test && \
make preinstallation && \
make pyspec

View File

@ -11,13 +11,12 @@
- [4. Add `fork.md`](#4-add-forkmd) - [4. Add `fork.md`](#4-add-forkmd)
- [5. Make it executable](#5-make-it-executable) - [5. Make it executable](#5-make-it-executable)
- [B: Make it executable for pytest and test generator](#b-make-it-executable-for-pytest-and-test-generator) - [B: Make it executable for pytest and test generator](#b-make-it-executable-for-pytest-and-test-generator)
- [1. Add `light-client/*` docs if you updated the content of `BeaconBlock`](#1-add-light-client-docs-if-you-updated-the-content-of-beaconblock) - [1. [Optional] Add `light-client/*` docs if you updated the content of `BeaconBlock`](#1-optional-add-light-client-docs-if-you-updated-the-content-of-beaconblock)
- [2. Add the mainnet and minimal presets and update the configs](#2-add-the-mainnet-and-minimal-presets-and-update-the-configs) - [2. Add the mainnet and minimal presets and update the configs](#2-add-the-mainnet-and-minimal-presets-and-update-the-configs)
- [3. Update `context.py`](#3-update-contextpy) - [3. Update `context.py`](#3-update-contextpy)
- [4. Update `constants.py`](#4-update-constantspy) - [4. Update `constants.py`](#4-update-constantspy)
- [5. Update `genesis.py`:](#5-update-genesispy) - [5. Update `genesis.py`:](#5-update-genesispy)
- [6. To add fork transition tests, update fork_transition.py](#6-to-add-fork-transition-tests-update-fork_transitionpy) - [6. Update CI configurations](#6-update-ci-configurations)
- [7. Update CI configurations](#7-update-ci-configurations)
- [Others](#others) - [Others](#others)
- [Bonus](#bonus) - [Bonus](#bonus)
- [Need help?](#need-help) - [Need help?](#need-help)
@ -58,6 +57,8 @@ You can refer to the previous fork's `fork.md` file.
- Update [`pysetup/constants.py`](https://github.com/ethereum/consensus-specs/blob/dev/constants.py) with the new feature name as Pyspec `constants.py` defined. - Update [`pysetup/constants.py`](https://github.com/ethereum/consensus-specs/blob/dev/constants.py) with the new feature name as Pyspec `constants.py` defined.
- Update [`pysetup/spec_builders/__init__.py`](https://github.com/ethereum/consensus-specs/blob/dev/pysetup/spec_builders/__init__.py). Implement a new `<FEATURE_NAME>SpecBuilder` in `pysetup/spec_builders/<FEATURE_NAME>.py` with the new feature name. e.g., `EIP9999SpecBuilder`. Append it to the `spec_builders` list. - Update [`pysetup/spec_builders/__init__.py`](https://github.com/ethereum/consensus-specs/blob/dev/pysetup/spec_builders/__init__.py). Implement a new `<FEATURE_NAME>SpecBuilder` in `pysetup/spec_builders/<FEATURE_NAME>.py` with the new feature name. e.g., `EIP9999SpecBuilder`. Append it to the `spec_builders` list.
- Update [`pysetup/md_doc_paths.py`](https://github.com/ethereum/consensus-specs/blob/dev/pysetup/md_doc_paths.py): add the path of the new markdown files in `get_md_doc_paths` function if needed. - Update [`pysetup/md_doc_paths.py`](https://github.com/ethereum/consensus-specs/blob/dev/pysetup/md_doc_paths.py): add the path of the new markdown files in `get_md_doc_paths` function if needed.
- Update `PREVIOUS_FORK_OF` setting in both [`test/helpers/constants.py`](https://github.com/ethereum/consensus-specs/blob/dev/constants.py) and [`pysetup/md_doc_paths.py`](https://github.com/ethereum/consensus-specs/blob/dev/pysetup/md_doc_paths.py).
- NOTE: since these two modules (the pyspec itself and the spec builder tool) must be separate, the fork sequence setting has to be defined again.
## B: Make it executable for pytest and test generator ## B: Make it executable for pytest and test generator
@ -70,24 +71,7 @@ You can refer to the previous fork's `fork.md` file.
- Update configs: `configs/mainnet.yaml` and `configs/minimal.yaml` - Update configs: `configs/mainnet.yaml` and `configs/minimal.yaml`
### 3. Update [`context.py`](https://github.com/ethereum/consensus-specs/blob/dev/tests/core/pyspec/eth2spec/test/context.py) ### 3. Update [`context.py`](https://github.com/ethereum/consensus-specs/blob/dev/tests/core/pyspec/eth2spec/test/context.py)
- Update `spec_targets` by adding `<NEW_FEATURE>` - [Optional] Add `with_<new-feature-name>_and_later` decorator for writing pytest cases. e.g., `with_capella_and_later`.
```python
from eth2spec.eip9999 import mainnet as spec_eip9999_mainnet, minimal as spec_eip9999_minimal
...
spec_targets: Dict[PresetBaseName, Dict[SpecForkName, Spec]] = {
MINIMAL: {
...
EIP9999: spec_eip9999_minimal,
},
MAINNET: {
...
EIP9999: spec_eip9999_mainnet
},
}
```
### 4. Update [`constants.py`](https://github.com/ethereum/consensus-specs/blob/dev/tests/core/pyspec/eth2spec/test/helpers/constants.py) ### 4. Update [`constants.py`](https://github.com/ethereum/consensus-specs/blob/dev/tests/core/pyspec/eth2spec/test/helpers/constants.py)
- Add `<NEW_FEATURE>` to `ALL_PHASES` and `TESTGEN_FORKS` - Add `<NEW_FEATURE>` to `ALL_PHASES` and `TESTGEN_FORKS`
@ -96,20 +80,6 @@ spec_targets: Dict[PresetBaseName, Dict[SpecForkName, Spec]] = {
We use `create_genesis_state` to create the default `state` in tests. We use `create_genesis_state` to create the default `state` in tests.
- Update `create_genesis_state` by adding `fork_version` setting:
```python
def create_genesis_state(spec, validator_balances, activation_threshold):
...
if spec.fork == ALTAIR:
current_version = spec.config.ALTAIR_FORK_VERSION
...
elif spec.fork == EIP9999:
# Add the previous fork version of given fork
previous_version = spec.config.<PREVIOUS_FORK_VERSION>
current_version = spec.config.EIP9999_FORK_VERSION
```
- If the given feature changes `BeaconState` fields, you have to set the initial values by adding: - If the given feature changes `BeaconState` fields, you have to set the initial values by adding:
```python ```python
@ -123,32 +93,7 @@ def create_genesis_state(spec, validator_balances, activation_threshold):
- If the given feature changes `ExecutionPayload` fields, you have to set the initial values by updating `get_sample_genesis_execution_payload_header` helper. - If the given feature changes `ExecutionPayload` fields, you have to set the initial values by updating `get_sample_genesis_execution_payload_header` helper.
### 6. To add fork transition tests, update [fork_transition.py](https://github.com/ethereum/consensus-specs/blob/dev/tests/core/pyspec/eth2spec/test/helpers/fork_transition.py) ### 6. Update CI configurations
```python
def do_fork(state, spec, post_spec, fork_epoch, with_block=True, sync_aggregate=None, operation_dict=None):
...
if post_spec.fork == ALTAIR:
state = post_spec.upgrade_to_altair(state)
...
elif post_spec.fork == EIP9999:
state = post_spec.upgrade_to_eip9999(state)
...
if post_spec.fork == ALTAIR:
assert state.fork.previous_version == post_spec.config.GENESIS_FORK_VERSION
assert state.fork.current_version == post_spec.config.ALTAIR_FORK_VERSION
...
elif post_spec.fork == EIP9999:
assert state.fork.previous_version == post_spec.config.<PREVIOUS_FORK_VERSION>
assert state.fork.current_version == post_spec.config.EIP9999_FORK_VERSION
...
```
### 7. Update CI configurations
- Update [GitHub Actions config](https://github.com/ethereum/consensus-specs/blob/dev/.github/workflows/run-tests.yml) - Update [GitHub Actions config](https://github.com/ethereum/consensus-specs/blob/dev/.github/workflows/run-tests.yml)
- Update `pyspec-tests.strategy.matrix.version` list by adding new feature to it - Update `pyspec-tests.strategy.matrix.version` list by adding new feature to it
- Update [CircleCI config](https://github.com/ethereum/consensus-specs/blob/dev/.circleci/config.yml) - Update [CircleCI config](https://github.com/ethereum/consensus-specs/blob/dev/.circleci/config.yml)

View File

@ -1,3 +1,4 @@
pip>=23.1.2 pip>=23.1.2
wheel>=0.40.0 wheel>=0.40.0
setuptools>=68.0.0 setuptools>=68.0.0
pylint>=3.0.0

103
scripts/build_run_docker_tests.sh Executable file
View File

@ -0,0 +1,103 @@
#! /bin/sh
# Run 'consensus-specs' tests from a docker container instance.
# *Be sure to launch Docker before running this script.*
#
# It does the below:
# 1. Run pytest for consensus-specs in a container.
# 2. Copy and paste the coverage report.
# 3. Remove all exited containers that use the consensus-specs:<TAG> images.
# Set variables
ALL_EXECUTABLE_SPECS=("phase0" "altair" "bellatrix" "capella" "deneb" "eip6110" "whisk")
TEST_PRESET_TYPE=minimal
FORK_TO_TEST=phase0
NUMBER_OF_CORES=4
WORKDIR="//consensus-specs//tests//core//pyspec"
ETH2SPEC_FOLDER_NAME="eth2spec"
CONTAINER_NAME="consensus-specs-tests"
DATE=$(date +"%Y%m%d-%H-%M")
# Default flag values
version=$(git log --pretty=format:'%h' -n 1)
IMAGE_NAME="consensus-specs:$version"
number_of_core=4
# displays the available options
display_help() {
echo "Run 'consensus-specs' tests from a container instance."
echo "Be sure to launch Docker before running this script."
echo
echo "Syntax: build_run_test.sh [--v TAG | --n NUMBER_OF_CORE | --f FORK_TO_TEST | --p PRESET_TYPE | --a | --h HELP]"
echo " --f <fork> Specify the fork to test"
echo " --i <image_name> Specify the docker image to use"
echo " --n <number> Specify the number of cores"
echo " --p <type> Specify the test preset type"
echo " --a Test all forks"
echo " --h Display this help and exit"
}
# Stop and remove the 'consensus-specs-dockerfile-test' container.
# If this container doesn't exist, then a error message is printed
# (but the process is not stopped).
cleanup() {
echo "Stop and remove the 'consensus-specs-tests' container."
docker stop $CONTAINER_NAME || true && docker rm $CONTAINER_NAME || true
}
# Copy the results from the container to a local folder
copy_test_results() {
local fork_name="$1" # Storing the first argument in a variable
docker cp $CONTAINER_NAME:$WORKDIR/test-reports/test_results.xml ./testResults/test-results-$fork_name-$DATE.xml
}
# Function to check if the Docker image already exists
image_exists() {
docker images --format '{{.Repository}}:{{.Tag}}' | grep -q "$1"
}
# Parse command line arguments
while [[ "$#" -gt 0 ]]; do
case $1 in
--f) FORK_TO_TEST="$2"; shift ;;
--v) IMAGE_NAME="$2"; shift ;;
--n) NUMBER_OF_CORES="$2"; shift ;;
--p) TEST_PRESET_TYPE="$2"; shift ;;
--a) FORK_TO_TEST="all" ;;
--h) display_help; exit 0 ;;
*) echo "Unknown parameter: $1"; display_help; exit 1 ;;
esac
shift
done
# initialize a test result directory
mkdir -p ./testResults
# Only clean container after user exit console
trap cleanup SIGINT
# Build Docker container if it doesn't exist
if ! image_exists "$IMAGE_NAME"; then
echo "Image $IMAGE_NAME does not exist. Building Docker image..."
docker build ../ -t $IMAGE_NAME -f ../docker/Dockerfile
else
echo "Image $IMAGE_NAME already exists. Skipping build..."
fi
# Equivalent to `make citest with the subsequent flags`
if [ "$FORK_TO_TEST" == "all" ]; then
for fork in "${ALL_EXECUTABLE_SPECS[@]}"; do
docker run --name $CONTAINER_NAME $IMAGE_NAME \
make citest fork=$fork TEST_PRESET_TYPE=$TEST_PRESET_TYPE NUMBER_OF_CORES=$NUMBER_OF_CORES
copy_test_results $fork
done
else
docker run --name $CONTAINER_NAME $IMAGE_NAME \
make citest fork=$FORK_TO_TEST TEST_PRESET_TYPE=$TEST_PRESET_TYPE NUMBER_OF_CORES=$NUMBER_OF_CORES
copy_test_results $FORK_TO_TEST
fi
# Stop and remove the container
cleanup

View File

@ -3,14 +3,6 @@ from copy import deepcopy
from dataclasses import dataclass from dataclasses import dataclass
import importlib import importlib
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.bellatrix import mainnet as spec_bellatrix_mainnet, minimal as spec_bellatrix_minimal
from eth2spec.capella import mainnet as spec_capella_mainnet, minimal as spec_capella_minimal
from eth2spec.deneb import mainnet as spec_deneb_mainnet, minimal as spec_deneb_minimal
from eth2spec.eip6110 import mainnet as spec_eip6110_mainnet, minimal as spec_eip6110_minimal
from eth2spec.whisk import mainnet as spec_whisk_mainnet, minimal as spec_whisk_minimal
from eth2spec.eip7002 import mainnet as spec_eip7002_mainnet, minimal as spec_eip7002_minimal
from eth2spec.utils import bls from eth2spec.utils import bls
from .exceptions import SkippedTest from .exceptions import SkippedTest
@ -18,22 +10,28 @@ from .helpers.constants import (
PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB,
EIP6110, EIP7002, EIP6110, EIP7002,
WHISK, WHISK,
MINIMAL, MAINNET, MINIMAL,
ALL_PHASES, ALL_PHASES,
ALL_FORK_UPGRADES, POST_FORK_OF,
ALLOWED_TEST_RUNNER_FORKS, ALLOWED_TEST_RUNNER_FORKS,
LIGHT_CLIENT_TESTING_FORKS, LIGHT_CLIENT_TESTING_FORKS,
) )
from .helpers.forks import is_post_fork from .helpers.forks import is_post_fork
from .helpers.typing import SpecForkName, PresetBaseName
from .helpers.genesis import create_genesis_state from .helpers.genesis import create_genesis_state
from .helpers.typing import (
Spec,
SpecForks,
)
from .helpers.specs import (
spec_targets,
)
from .utils import ( from .utils import (
vector_test, vector_test,
with_meta_tags, with_meta_tags,
) )
from random import Random from random import Random
from typing import Any, Callable, Sequence, TypedDict, Protocol, Dict from typing import Any, Callable, Sequence, Dict
from lru import LRU from lru import LRU
@ -44,34 +42,6 @@ DEFAULT_TEST_PRESET = MINIMAL
DEFAULT_PYTEST_FORKS = ALL_PHASES DEFAULT_PYTEST_FORKS = ALL_PHASES
# 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):
fork: str
config: Configuration
class SpecPhase0(Spec):
...
class SpecAltair(Spec):
...
class SpecBellatrix(Spec):
...
class SpecCapella(Spec):
...
@dataclass(frozen=True) @dataclass(frozen=True)
class ForkMeta: class ForkMeta:
pre_fork_name: str pre_fork_name: str
@ -79,37 +49,6 @@ class ForkMeta:
fork_epoch: int fork_epoch: int
spec_targets: Dict[PresetBaseName, Dict[SpecForkName, Spec]] = {
MINIMAL: {
PHASE0: spec_phase0_minimal,
ALTAIR: spec_altair_minimal,
BELLATRIX: spec_bellatrix_minimal,
CAPELLA: spec_capella_minimal,
DENEB: spec_deneb_minimal,
EIP6110: spec_eip6110_minimal,
EIP7002: spec_eip7002_minimal,
WHISK: spec_whisk_minimal,
},
MAINNET: {
PHASE0: spec_phase0_mainnet,
ALTAIR: spec_altair_mainnet,
BELLATRIX: spec_bellatrix_mainnet,
CAPELLA: spec_capella_mainnet,
DENEB: spec_deneb_mainnet,
EIP6110: spec_eip6110_mainnet,
EIP7002: spec_eip7002_mainnet,
WHISK: spec_whisk_mainnet,
},
}
class SpecForks(TypedDict, total=False):
PHASE0: SpecPhase0
ALTAIR: SpecAltair
BELLATRIX: SpecBellatrix
CAPELLA: SpecCapella
def _prepare_state(balances_fn: Callable[[Any], Sequence[int]], threshold_fn: Callable[[Any], int], def _prepare_state(balances_fn: Callable[[Any], Sequence[int]], threshold_fn: Callable[[Any], int],
spec: Spec, phases: SpecForks): spec: Spec, phases: SpecForks):
balances = balances_fn(spec) balances = balances_fn(spec)
@ -530,7 +469,7 @@ def with_phases(phases, other_phases=None):
# When running test generator, it sets specific `phase` # When running test generator, it sets specific `phase`
phase = kw['phase'] phase = kw['phase']
_phases = [phase] _phases = [phase]
_other_phases = [ALL_FORK_UPGRADES[phase]] _other_phases = [POST_FORK_OF[phase]]
ret = _run_test_case_with_phases(fn, _phases, _other_phases, kw, args, is_fork_transition=True) ret = _run_test_case_with_phases(fn, _phases, _other_phases, kw, args, is_fork_transition=True)
else: else:
# When running pytest, go through `fork_metas` instead of using `phases` # When running pytest, go through `fork_metas` instead of using `phases`

View File

@ -45,7 +45,22 @@ TESTGEN_FORKS = (*MAINNET_FORKS, DENEB, EIP6110, WHISK)
# Forks allowed in the test runner `--fork` flag, to fail fast in case of typos # Forks allowed in the test runner `--fork` flag, to fail fast in case of typos
ALLOWED_TEST_RUNNER_FORKS = (*ALL_PHASES, WHISK) ALLOWED_TEST_RUNNER_FORKS = (*ALL_PHASES, WHISK)
ALL_FORK_UPGRADES = { # NOTE: the same definition as in `pysetup/md_doc_paths.py`
PREVIOUS_FORK_OF = {
# post_fork_name: pre_fork_name
PHASE0: None,
ALTAIR: PHASE0,
BELLATRIX: ALTAIR,
CAPELLA: BELLATRIX,
DENEB: CAPELLA,
# Experimental patches
EIP6110: DENEB,
WHISK: CAPELLA,
EIP7002: CAPELLA,
}
# For fork transition tests
POST_FORK_OF = {
# pre_fork_name: post_fork_name # pre_fork_name: post_fork_name
PHASE0: ALTAIR, PHASE0: ALTAIR,
ALTAIR: BELLATRIX, ALTAIR: BELLATRIX,
@ -53,15 +68,11 @@ ALL_FORK_UPGRADES = {
CAPELLA: DENEB, CAPELLA: DENEB,
DENEB: EIP6110, DENEB: EIP6110,
} }
ALL_PRE_POST_FORKS = ALL_FORK_UPGRADES.items()
AFTER_BELLATRIX_UPGRADES = {key: value for key, value in ALL_FORK_UPGRADES.items() if key != PHASE0} ALL_PRE_POST_FORKS = POST_FORK_OF.items()
AFTER_BELLATRIX_PRE_POST_FORKS = AFTER_BELLATRIX_UPGRADES.items() DENEB_TRANSITION_UPGRADES_AND_AFTER = {key: value for key, value in POST_FORK_OF.items()
AFTER_CAPELLA_UPGRADES = {key: value for key, value in ALL_FORK_UPGRADES.items()
if key not in [PHASE0, ALTAIR]}
AFTER_CAPELLA_PRE_POST_FORKS = AFTER_CAPELLA_UPGRADES.items()
AFTER_DENEB_UPGRADES = {key: value for key, value in ALL_FORK_UPGRADES.items()
if key not in [PHASE0, ALTAIR, BELLATRIX]} if key not in [PHASE0, ALTAIR, BELLATRIX]}
AFTER_DENEB_PRE_POST_FORKS = AFTER_DENEB_UPGRADES.items() AFTER_DENEB_PRE_POST_FORKS = DENEB_TRANSITION_UPGRADES_AND_AFTER.items()
# #
# Config and Preset # Config and Preset

View File

@ -11,12 +11,9 @@ from eth2spec.test.helpers.block import (
) )
from eth2spec.test.helpers.bls_to_execution_changes import get_signed_address_change from eth2spec.test.helpers.bls_to_execution_changes import get_signed_address_change
from eth2spec.test.helpers.constants import ( from eth2spec.test.helpers.constants import (
ALTAIR, PHASE0,
BELLATRIX, POST_FORK_OF,
CAPELLA, PREVIOUS_FORK_OF,
DENEB,
EIP6110,
EIP7002,
) )
from eth2spec.test.helpers.deposits import ( from eth2spec.test.helpers.deposits import (
prepare_state_and_deposit, prepare_state_and_deposit,
@ -146,45 +143,37 @@ def state_transition_across_slots_with_ignoring_proposers(spec,
next_slot(spec, state) next_slot(spec, state)
def get_upgrade_fn(spec, fork):
# pylint: disable=unused-argument
# NOTE: `spec` is used for the `eval` call
assert fork in POST_FORK_OF.values()
try:
# TODO: make all upgrade_to_* function names consistent?
fn = eval(f"spec.upgrade_to_{fork}")
return fn
except Exception:
raise ValueError(f"Unknown fork: {fork}")
def do_fork(state, spec, post_spec, fork_epoch, with_block=True, sync_aggregate=None, operation_dict=None): def do_fork(state, spec, post_spec, fork_epoch, with_block=True, sync_aggregate=None, operation_dict=None):
spec.process_slots(state, state.slot + 1) spec.process_slots(state, state.slot + 1)
assert state.slot % spec.SLOTS_PER_EPOCH == 0 assert state.slot % spec.SLOTS_PER_EPOCH == 0
assert spec.get_current_epoch(state) == fork_epoch assert spec.get_current_epoch(state) == fork_epoch
if post_spec.fork == ALTAIR: state = get_upgrade_fn(post_spec, post_spec.fork)(state)
state = post_spec.upgrade_to_altair(state)
elif post_spec.fork == BELLATRIX:
state = post_spec.upgrade_to_bellatrix(state)
elif post_spec.fork == CAPELLA:
state = post_spec.upgrade_to_capella(state)
elif post_spec.fork == DENEB:
state = post_spec.upgrade_to_deneb(state)
elif post_spec.fork == EIP6110:
state = post_spec.upgrade_to_eip6110(state)
elif post_spec.fork == EIP7002:
state = post_spec.upgrade_to_eip7002(state)
assert state.fork.epoch == fork_epoch assert state.fork.epoch == fork_epoch
if post_spec.fork == ALTAIR: previous_fork = PREVIOUS_FORK_OF[post_spec.fork]
assert state.fork.previous_version == post_spec.config.GENESIS_FORK_VERSION if previous_fork == PHASE0:
assert state.fork.current_version == post_spec.config.ALTAIR_FORK_VERSION previous_version = spec.config.GENESIS_FORK_VERSION
elif post_spec.fork == BELLATRIX: else:
assert state.fork.previous_version == post_spec.config.ALTAIR_FORK_VERSION previous_version = getattr(post_spec.config, f"{previous_fork.upper()}_FORK_VERSION")
assert state.fork.current_version == post_spec.config.BELLATRIX_FORK_VERSION current_version = getattr(post_spec.config, f"{post_spec.fork.upper()}_FORK_VERSION")
elif post_spec.fork == CAPELLA:
assert state.fork.previous_version == post_spec.config.BELLATRIX_FORK_VERSION assert state.fork.previous_version == previous_version
assert state.fork.current_version == post_spec.config.CAPELLA_FORK_VERSION assert state.fork.current_version == current_version
elif post_spec.fork == DENEB:
assert state.fork.previous_version == post_spec.config.CAPELLA_FORK_VERSION
assert state.fork.current_version == post_spec.config.DENEB_FORK_VERSION
elif post_spec.fork == EIP6110:
assert state.fork.previous_version == post_spec.config.DENEB_FORK_VERSION
assert state.fork.current_version == post_spec.config.EIP6110_FORK_VERSION
elif post_spec.fork == EIP7002:
assert state.fork.previous_version == post_spec.config.CAPELLA_FORK_VERSION
assert state.fork.current_version == post_spec.config.EIP7002_FORK_VERSION
if with_block: if with_block:
return state, _state_transition_and_sign_block_at_slot( return state, _state_transition_and_sign_block_at_slot(

View File

@ -1,27 +1,24 @@
from .constants import ( from .constants import (
PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, ALTAIR, BELLATRIX, CAPELLA, DENEB,
EIP6110, EIP7002, WHISK, EIP6110, EIP7002, WHISK,
PREVIOUS_FORK_OF,
) )
def is_post_fork(a, b): def is_post_fork(a, b) -> bool:
if a == WHISK: """
return b in [PHASE0, ALTAIR, BELLATRIX, CAPELLA, WHISK] Returns true if fork a is after b, or if a == b
if a == EIP7002: """
return b in [PHASE0, ALTAIR, BELLATRIX, CAPELLA, EIP7002] if a == b:
if a == EIP6110: return True
return b in [PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP6110]
if a == DENEB: prev_fork = PREVIOUS_FORK_OF[a]
return b in [PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB] if prev_fork == b:
if a == CAPELLA: return True
return b in [PHASE0, ALTAIR, BELLATRIX, CAPELLA] elif prev_fork is None:
if a == BELLATRIX: return False
return b in [PHASE0, ALTAIR, BELLATRIX] else:
if a == ALTAIR: return is_post_fork(prev_fork, b)
return b in [PHASE0, ALTAIR]
if a == PHASE0:
return b in [PHASE0]
raise ValueError("Unknown fork name %s" % a)
def is_post_altair(spec): def is_post_altair(spec):

View File

@ -1,5 +1,6 @@
from eth2spec.test.helpers.constants import ( from eth2spec.test.helpers.constants import (
ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP6110, EIP7002, WHISK, PHASE0,
PREVIOUS_FORK_OF,
) )
from eth2spec.test.helpers.execution_payload import ( from eth2spec.test.helpers.execution_payload import (
compute_el_header_block_hash, compute_el_header_block_hash,
@ -77,26 +78,13 @@ def create_genesis_state(spec, validator_balances, activation_threshold):
previous_version = spec.config.GENESIS_FORK_VERSION previous_version = spec.config.GENESIS_FORK_VERSION
current_version = spec.config.GENESIS_FORK_VERSION current_version = spec.config.GENESIS_FORK_VERSION
if spec.fork == ALTAIR: if spec.fork != PHASE0:
current_version = spec.config.ALTAIR_FORK_VERSION previous_fork = PREVIOUS_FORK_OF[spec.fork]
elif spec.fork == BELLATRIX: if previous_fork == PHASE0:
previous_version = spec.config.ALTAIR_FORK_VERSION previous_version = spec.config.GENESIS_FORK_VERSION
current_version = spec.config.BELLATRIX_FORK_VERSION else:
elif spec.fork == CAPELLA: previous_version = getattr(spec.config, f"{previous_fork.upper()}_FORK_VERSION")
previous_version = spec.config.BELLATRIX_FORK_VERSION current_version = getattr(spec.config, f"{spec.fork.upper()}_FORK_VERSION")
current_version = spec.config.CAPELLA_FORK_VERSION
elif spec.fork == DENEB:
previous_version = spec.config.CAPELLA_FORK_VERSION
current_version = spec.config.DENEB_FORK_VERSION
elif spec.fork == EIP6110:
previous_version = spec.config.DENEB_FORK_VERSION
current_version = spec.config.EIP6110_FORK_VERSION
elif spec.fork == EIP7002:
previous_version = spec.config.CAPELLA_FORK_VERSION
current_version = spec.config.EIP7002_FORK_VERSION
elif spec.fork == WHISK:
previous_version = spec.config.CAPELLA_FORK_VERSION
current_version = spec.config.WHISK_FORK_VERSION
state = spec.BeaconState( state = spec.BeaconState(
genesis_time=0, genesis_time=0,

View File

@ -0,0 +1,26 @@
from typing import (
Dict,
)
from .constants import (
MINIMAL, MAINNET,
ALL_PHASES, WHISK,
)
from .typing import (
PresetBaseName,
SpecForkName,
Spec,
)
# NOTE: special case like `ALLOWED_TEST_RUNNER_FORKS`
ALL_EXECUTABLE_SPEC_NAMES = ALL_PHASES + (WHISK,)
# import the spec for each fork and preset
for fork in ALL_EXECUTABLE_SPEC_NAMES:
exec(f"from eth2spec.{fork} import mainnet as spec_{fork}_mainnet, minimal as spec_{fork}_minimal")
# this is the only output of this file
spec_targets: Dict[PresetBaseName, Dict[SpecForkName, Spec]] = {
MINIMAL: {fork: eval(f"spec_{fork}_minimal") for fork in ALL_EXECUTABLE_SPEC_NAMES},
MAINNET: {fork: eval(f"spec_{fork}_mainnet") for fork in ALL_EXECUTABLE_SPEC_NAMES},
}

View File

@ -1,4 +1,18 @@
from typing import NewType from typing import (
NewType,
Protocol,
Sequence,
)
SpecForkName = NewType("SpecForkName", str) SpecForkName = NewType("SpecForkName", str)
PresetBaseName = NewType("PresetBaseName", str) PresetBaseName = NewType("PresetBaseName", str)
SpecForks = Sequence[SpecForkName]
class Configuration(Protocol):
PRESET_BASE: str
class Spec(Protocol):
fork: str
config: Configuration

View File

@ -1,5 +1,4 @@
from eth2spec.test.context import ( from eth2spec.test.context import (
MAINNET,
spec_state_test, spec_state_test,
with_altair_and_later, with_altair_and_later,
with_presets, with_presets,
@ -11,6 +10,7 @@ from eth2spec.test.helpers.attestations import (
from eth2spec.test.helpers.block import ( from eth2spec.test.helpers.block import (
build_empty_block, build_empty_block,
) )
from eth2spec.test.helpers.constants import MAINNET
from eth2spec.test.helpers.fork_choice import ( from eth2spec.test.helpers.fork_choice import (
get_genesis_forkchoice_store_and_block, get_genesis_forkchoice_store_and_block,
on_tick_and_append_step, on_tick_and_append_step,