From da33c9fa7bb5f49d261f85db6719c852bfd5846f Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Fri, 18 Oct 2024 15:45:40 -0500 Subject: [PATCH 01/25] Refactor the main Makefile --- .gitignore | 1 + Makefile | 452 +++++++++++++++++++++++++++++------------------------ 2 files changed, 253 insertions(+), 200 deletions(-) diff --git a/.gitignore b/.gitignore index ad62aa177e..18c0c19447 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ venv .venv /.pytest_cache *.swp +.eth2spec build/ output/ diff --git a/Makefile b/Makefile index 39d493645e..1f4880d928 100644 --- a/Makefile +++ b/Makefile @@ -1,135 +1,208 @@ -SPEC_DIR = ./specs -SSZ_DIR = ./ssz -TEST_LIBS_DIR = ./tests/core -TEST_GENERATORS_DIR = ./tests/generators -# The working dir during testing +all: help + +# A list of executable specifications. +# These must pass a strict linter. +ALL_EXECUTABLE_SPEC_NAMES = \ + phase0 \ + altair \ + bellatrix \ + capella \ + deneb \ + electra \ + whisk \ + eip6800 \ + eip7594 \ + eip7732 + +# A list of fake targets. +.PHONY: \ + check_toc \ + clean \ + coverage \ + detect_errors \ + eth2spec \ + gen_all \ + gen_list \ + help \ + lint \ + pyspec \ + serve_docs \ + test + +############################################################################### +# Help +############################################################################### + +BOLD = $(shell tput bold) +NORM = $(shell tput sgr0) + +# Print target descriptions. +help: + @echo "make $(BOLD)check_toc$(NORM) -- check table of contents" + @echo "make $(BOLD)clean$(NORM) -- delete all untracked files" + @echo "make $(BOLD)coverage$(NORM) -- run pyspec tests with coverage" + @echo "make $(BOLD)detect_errors$(NORM) -- detect generator errors" + @echo "make $(BOLD)gen_$(NORM) -- run a single generator" + @echo "make $(BOLD)gen_all$(NORM) -- run all generators" + @echo "make $(BOLD)gen_list$(NORM) -- list all generator targets" + @echo "make $(BOLD)eth2spec$(NORM) -- force rebuild eth2spec package" + @echo "make $(BOLD)lint$(NORM) -- run the linters" + @echo "make $(BOLD)pyspec$(NORM) -- generate python specifications" + @echo "make $(BOLD)serve_docs$(NORM) -- start a local docs web server" + @echo "make $(BOLD)test$(NORM) -- run pyspec tests" + +############################################################################### +# Virtual Environment +############################################################################### + +VENV_DIR = $(CURDIR)/venv +PYTHON_VENV = $(VENV_DIR)/bin/python3 +PIP_VENV = $(VENV_DIR)/bin/pip +VENV = $(VENV_DIR)/.venv_done + +# Make a virtual environment will all of the necessary dependencies. +# This is linked to a hidden file so make's dependency management works. +$(VENV): requirements_preinstallation.txt + @echo "Creating virtual environment" + @python3 -m venv $(VENV_DIR) + @$(PIP_VENV) install -r requirements_preinstallation.txt + @touch $(VENV) + +############################################################################### +# Distribution +############################################################################### + +# The pyspec is rebuilt to enforce the /specs being part of eth2specs source +# distribution. It could be forgotten otherwise. +dist_build: $(VENV) pyspec + @$(PYTHON_VENV) setup.py sdist bdist_wheel + +# Check the distribution for issues. +dist_check: $(VENV) + @$(PYTHON_VENV) -m twine check dist/* + +# Upload the distribution to PyPI. +dist_upload: $(VENV) + @$(PYTHON_VENV) -m twine upload dist/* + +############################################################################### +# Specification +############################################################################### + +TEST_LIBS_DIR = $(CURDIR)/tests/core PY_SPEC_DIR = $(TEST_LIBS_DIR)/pyspec -ETH2SPEC_MODULE_DIR = $(PY_SPEC_DIR)/eth2spec -TEST_REPORT_DIR = $(PY_SPEC_DIR)/test-reports -TEST_VECTOR_DIR = ../consensus-spec-tests/tests -GENERATOR_DIR = ./tests/generators -CONFIGS_DIR = ./configs +ETH2SPEC = $(CURDIR)/.eth2spec + +# Install the eth2spec package. +$(ETH2SPEC): $(VENV) + @$(PIP_VENV) install .[docs,lint,test,generator] + @touch $(ETH2SPEC) + +# Force rebuild/install the eth2spec package. +eth2spec: + $(MAKE) --always-make $(ETH2SPEC) + +# Create the pyspec for all phases. +pyspec: $(VENV) setup.py + @echo "Building all pyspecs" + @$(PYTHON_VENV) setup.py pyspecdev + +############################################################################### +# Testing +############################################################################### + TEST_PRESET_TYPE ?= minimal -# Collect a list of generator names -GENERATORS = $(sort $(dir $(wildcard $(GENERATOR_DIR)/*/.))) -# Map this list of generator paths to "gen_{generator name}" entries -GENERATOR_TARGETS = $(patsubst $(GENERATOR_DIR)/%/, gen_%, $(GENERATORS)) -GENERATOR_VENVS = $(patsubst $(GENERATOR_DIR)/%, $(GENERATOR_DIR)/%venv, $(GENERATORS)) -# Documents +TEST_REPORT_DIR = $(PY_SPEC_DIR)/test-reports + +# Run pyspec tests. +# To only run a specific test, prepend with k=, eg: +# make test k=test_verify_kzg_proof +# To only run tests for a specific fork, prepend with fork=, eg: +# make test fork=deneb +# Or both at the same time, eg: +# make test fork=deneb k=test_verify_kzg_proof +test: MAYBE_TEST := $(if $(k),-k=$(k)) +test: MAYBE_FORK := $(if $(fork),--fork=$(fork)) +test: $(ETH2SPEC) pyspec + @mkdir -p $(TEST_REPORT_DIR) + @$(PYTHON_VENV) -m pytest \ + -n auto \ + $(MAYBE_TEST) \ + $(MAYBE_FORK) \ + --bls-type=fastest \ + --preset=$(TEST_PRESET_TYPE) \ + --junitxml=$(TEST_REPORT_DIR)/test_results.xml \ + $(PY_SPEC_DIR)/eth2spec + +############################################################################### +# Coverage +############################################################################### + +COV_HTML_OUT=$(PY_SPEC_DIR)/.htmlcov +COV_INDEX_FILE=$(COV_HTML_OUT)/index.html +COVERAGE_SCOPE := $(foreach S,$(ALL_EXECUTABLE_SPEC_NAMES), --cov=eth2spec.$S.$(TEST_PRESET_TYPE)) + +# Run pytest with coverage tracking +_test_with_coverage: MAYBE_TEST := $(if $(k),-k=$(k)) +_test_with_coverage: MAYBE_FORK := $(if $(fork),--fork=$(fork)) +_test_with_coverage: $(ETH2SPEC) pyspec + @$(PYTHON_VENV) -m pytest \ + -n auto \ + $(MAYBE_TEST) \ + $(MAYBE_FORK) \ + --disable-bls \ + $(COVERAGE_SCOPE) \ + --cov-report="html:$(COV_HTML_OUT)" \ + --cov-branch \ + $(PY_SPEC_DIR)/eth2spec + +# To only run a specific test, prepend with k=, eg: +# make coverage k=test_verify_kzg_proof +# To only run tests for a specific fork, prepend with fork=, eg: +# make coverage fork=altair +# Or both at the same time, eg: +# make coverage fork=deneb k=test_verify_kzg_proof +coverage: _test_with_coverage + @echo "Opening result: $(COV_INDEX_FILE)" + @((open "$(COV_INDEX_FILE)" || xdg-open "$(COV_INDEX_FILE)") &> /dev/null) & + +############################################################################### +# Documentation +############################################################################### + DOCS_DIR = ./docs +FORK_CHOICE_DIR = ./fork_choice +SPEC_DIR = ./specs SSZ_DIR = ./ssz SYNC_DIR = ./sync -FORK_CHOICE_DIR = ./fork_choice - -# To check generator matching: -#$(info $$GENERATOR_TARGETS is [${GENERATOR_TARGETS}]) +# Copy files to the docs directory. +_copy_docs: + @cp -r $(SPEC_DIR) $(DOCS_DIR) + @cp -r $(SYNC_DIR) $(DOCS_DIR) + @cp -r $(SSZ_DIR) $(DOCS_DIR) + @cp -r $(FORK_CHOICE_DIR) $(DOCS_DIR) + @cp $(CURDIR)/README.md $(DOCS_DIR)/README.md + +# Start a local documentation server. +serve_docs: _copy_docs + @mkdocs build + @mkdocs serve + +############################################################################### +# Checks +############################################################################### + +LINTER_CONFIG_FILE = $(CURDIR)/linter.ini +PYLINT_SCOPE := $(foreach S,$(ALL_EXECUTABLE_SPEC_NAMES), $(PY_SPEC_DIR)/eth2spec/$S) +MYPY_SCOPE := $(foreach S,$(ALL_EXECUTABLE_SPEC_NAMES), -p eth2spec.$S) +TEST_GENERATORS_DIR = ./tests/generators MARKDOWN_FILES = $(wildcard $(SPEC_DIR)/*/*.md) \ $(wildcard $(SPEC_DIR)/*/*/*.md) \ $(wildcard $(SPEC_DIR)/_features/*/*.md) \ $(wildcard $(SPEC_DIR)/_features/*/*/*.md) \ $(wildcard $(SSZ_DIR)/*.md) -ALL_EXECUTABLE_SPEC_NAMES = phase0 altair bellatrix capella deneb electra whisk eip6800 eip7594 eip7732 -# The parameters for commands. Use `foreach` to avoid listing specs again. -COVERAGE_SCOPE := $(foreach S,$(ALL_EXECUTABLE_SPEC_NAMES), --cov=eth2spec.$S.$(TEST_PRESET_TYPE)) -PYLINT_SCOPE := $(foreach S,$(ALL_EXECUTABLE_SPEC_NAMES), ./eth2spec/$S) -MYPY_SCOPE := $(foreach S,$(ALL_EXECUTABLE_SPEC_NAMES), -p eth2spec.$S) - -COV_HTML_OUT=.htmlcov -COV_HTML_OUT_DIR=$(PY_SPEC_DIR)/$(COV_HTML_OUT) -COV_INDEX_FILE=$(COV_HTML_OUT_DIR)/index.html - -CURRENT_DIR = ${CURDIR} -LINTER_CONFIG_FILE = $(CURRENT_DIR)/linter.ini -GENERATOR_ERROR_LOG_FILE = $(CURRENT_DIR)/$(TEST_VECTOR_DIR)/testgen_error_log.txt - -SCRIPTS_DIR = ${CURRENT_DIR}/scripts - -.PHONY: clean partial_clean all test citest lint generate_tests pyspec install_test open_cov \ - check_toc detect_generator_incomplete detect_generator_error_log - -all: $(PY_SPEC_ALL_TARGETS) - -# deletes everything except the venvs -partial_clean: - rm -rf $(TEST_VECTOR_DIR) - rm -rf $(GENERATOR_VENVS) - rm -rf .pytest_cache - rm -f .coverage - rm -rf $(PY_SPEC_DIR)/.pytest_cache - rm -rf $(DEPOSIT_CONTRACT_TESTER_DIR)/.pytest_cache - rm -rf $(COV_HTML_OUT_DIR) - rm -rf $(TEST_REPORT_DIR) - rm -rf eth2spec.egg-info dist build - rm -rf build; - @for spec_name in $(ALL_EXECUTABLE_SPEC_NAMES) ; do \ - echo $$spec_name; \ - rm -rf $(ETH2SPEC_MODULE_DIR)/$$spec_name; \ - done - -clean: partial_clean - rm -rf venv - # legacy cleanup. The pyspec venv should be located at the repository root - rm -rf $(PY_SPEC_DIR)/venv - rm -rf $(DEPOSIT_CONTRACT_COMPILER_DIR)/venv - rm -rf $(DEPOSIT_CONTRACT_TESTER_DIR)/venv - -# The pyspec is rebuilt to enforce the /specs being part of eth2specs source distribution. It could be forgotten otherwise. -dist_build: pyspec - python3 setup.py sdist bdist_wheel - -dist_check: - python3 -m twine check dist/* - -dist_upload: - python3 -m twine upload dist/* - -build_wheel: install_test pyspec - . venv/bin/activate && \ - python3 -m build --no-isolation --outdir ./dist ./ - -# "make generate_tests" to run all generators -generate_tests: $(GENERATOR_TARGETS) - -# "make pyspec" to create the pyspec for all phases. -pyspec: - @python3 -m venv venv; . venv/bin/activate; python3 setup.py pyspecdev - -# check the setup tool requirements -preinstallation: - python3 -m venv venv && \ - . venv/bin/activate && \ - python3 -m pip install -r requirements_preinstallation.txt - -install_test: preinstallation - . venv/bin/activate && \ - python3 -m pip install -e .[lint,test] - -# Testing against `minimal` or `mainnet` config by default -test: pyspec - . venv/bin/activate; cd $(PY_SPEC_DIR); \ - python3 -m pytest -n auto --disable-bls $(COVERAGE_SCOPE) --cov-report="html:$(COV_HTML_OUT)" --cov-branch eth2spec - -# Testing against `minimal` or `mainnet` config by default -find_test: pyspec - . venv/bin/activate; cd $(PY_SPEC_DIR); \ - python3 -m pytest -k=$(K) --disable-bls $(COVERAGE_SCOPE) --cov-report="html:$(COV_HTML_OUT)" --cov-branch eth2spec - -citest: pyspec - mkdir -p $(TEST_REPORT_DIR); -ifdef fork - . venv/bin/activate; cd $(PY_SPEC_DIR); \ - python3 -m pytest -n auto --bls-type=fastest --preset=$(TEST_PRESET_TYPE) --fork=$(fork) --junitxml=test-reports/test_results.xml eth2spec -else - . venv/bin/activate; cd $(PY_SPEC_DIR); \ - python3 -m pytest -n auto --bls-type=fastest --preset=$(TEST_PRESET_TYPE) --junitxml=test-reports/test_results.xml eth2spec -endif - - -open_cov: - ((open "$(COV_INDEX_FILE)" || xdg-open "$(COV_INDEX_FILE)") &> /dev/null) & - # Check all files and error if any ToC were modified. check_toc: $(MARKDOWN_FILES:=.toc) @[ "$$(find . -name '*.md.tmp' -print -quit)" ] && exit 1 || exit 0 @@ -146,83 +219,62 @@ check_toc: $(MARKDOWN_FILES:=.toc) echo "\033[1;34m See $*.tmp\033[0m"; \ fi -codespell: - codespell . --skip "./.git,./venv,$(PY_SPEC_DIR)/.mypy_cache" -I .codespell-whitelist - -lint: pyspec - . venv/bin/activate; cd $(PY_SPEC_DIR); \ - flake8 --config $(LINTER_CONFIG_FILE) ./eth2spec \ - && python -m pylint --rcfile $(LINTER_CONFIG_FILE) $(PYLINT_SCOPE) \ - && python -m mypy --config-file $(LINTER_CONFIG_FILE) $(MYPY_SCOPE) - -lint_generators: pyspec - . venv/bin/activate; cd $(TEST_GENERATORS_DIR); \ - flake8 --config $(LINTER_CONFIG_FILE) - -# Runs a generator, identified by param 1 -define run_generator - # Started! - # Create output directory - # Navigate to the generator - # Create a virtual environment, if it does not exist already - # Activate the venv, this is where dependencies are installed for the generator - # Install all the necessary requirements - # Run the generator. The generator is assumed to have an "main.py" file. - # We output to the tests dir (generator program should accept a "-o " argument. - # `-l minimal general` can be added to the generator call to filter to smaller configs, when testing. - echo "generator $(1) started"; \ - mkdir -p $(TEST_VECTOR_DIR); \ - cd $(GENERATOR_DIR)/$(1); \ - if ! test -d venv; then python3 -m venv venv; fi; \ - . venv/bin/activate; \ - pip3 install ../../../dist/eth2spec-*.whl; \ - pip3 install 'eth2spec[generator]'; \ - python3 main.py -o $(CURRENT_DIR)/$(TEST_VECTOR_DIR); \ - echo "generator $(1) finished" -endef - -# The tests dir itself is simply built by creating the directory (recursively creating deeper directories if necessary) -$(TEST_VECTOR_DIR): - $(info creating test output directory, for generators: ${GENERATOR_TARGETS}) - mkdir -p $@ -$(TEST_VECTOR_DIR)/: - $(info ignoring duplicate tests dir) - -gen_kzg_setups: - cd $(SCRIPTS_DIR); \ - if ! test -d venv; then python3 -m venv venv; fi; \ - . venv/bin/activate; \ - pip3 install -r requirements.txt; \ - python3 ./gen_kzg_trusted_setups.py --secret=1337 --g1-length=4096 --g2-length=65 --output-dir ${CURRENT_DIR}/presets/minimal/trusted_setups; \ - python3 ./gen_kzg_trusted_setups.py --secret=1337 --g1-length=4096 --g2-length=65 --output-dir ${CURRENT_DIR}/presets/mainnet/trusted_setups - -# For any generator, build it using the run_generator function. -# (creation of output dir is a dependency) -gen_%: build_wheel $(TEST_VECTOR_DIR) - $(call run_generator,$*) - -detect_generator_incomplete: $(TEST_VECTOR_DIR) - find $(TEST_VECTOR_DIR) -name "INCOMPLETE" - -detect_generator_error_log: $(TEST_VECTOR_DIR) - [ -f $(GENERATOR_ERROR_LOG_FILE) ] && echo "[ERROR] $(GENERATOR_ERROR_LOG_FILE) file exists" || echo "[PASSED] error log file does not exist" - - -# For docs reader -install_docs: - python3 -m venv venv; . venv/bin/activate; python3 -m pip install -e .[docs]; - -copy_docs: - cp -r $(SPEC_DIR) $(DOCS_DIR); - cp -r $(SYNC_DIR) $(DOCS_DIR); - cp -r $(SSZ_DIR) $(DOCS_DIR); - cp -r $(FORK_CHOICE_DIR) $(DOCS_DIR); - cp $(CURRENT_DIR)/README.md $(DOCS_DIR)/README.md - -build_docs: copy_docs - . venv/bin/activate; - mkdocs build - -serve_docs: - . venv/bin/activate; - mkdocs serve +# Check for mistakes. +lint: $(ETH2SPEC) pyspec check_toc + @codespell . --skip "./.git,./venv,$(PY_SPEC_DIR)/.mypy_cache" -I .codespell-whitelist + @flake8 --config $(LINTER_CONFIG_FILE) $(PY_SPEC_DIR)/eth2spec + @flake8 --config $(LINTER_CONFIG_FILE) $(TEST_GENERATORS_DIR) + @$(PYTHON_VENV) -m pylint --rcfile $(LINTER_CONFIG_FILE) $(PYLINT_SCOPE) + @$(PYTHON_VENV) -m mypy --config-file $(LINTER_CONFIG_FILE) $(MYPY_SCOPE) + +############################################################################### +# Generators +############################################################################### + +TEST_VECTOR_DIR = $(CURDIR)/../consensus-spec-tests/tests +GENERATOR_DIR = $(CURDIR)/tests/generators +SCRIPTS_DIR = $(CURDIR)/scripts +GENERATOR_ERROR_LOG_FILE = $(TEST_VECTOR_DIR)/testgen_error_log.txt +GENERATORS = $(sort $(dir $(wildcard $(GENERATOR_DIR)/*/.))) +GENERATOR_TARGETS = $(patsubst $(GENERATOR_DIR)/%/, gen_%, $(GENERATORS)) gen_kzg_setups + +# List available generators. +gen_list: + @for target in $(shell echo $(GENERATOR_TARGETS) | tr ' ' '\n' | sort -n); do \ + echo $$target; \ + done + +# Run one generator. +gen_%: $(ETH2SPEC) pyspec + @mkdir -p $(TEST_VECTOR_DIR) + @$(PYTHON_VENV) $(GENERATOR_DIR)/$*/main.py -o $(TEST_VECTOR_DIR); \ + +# Generate KZG setups. +gen_kzg_setups: $(ETH2SPEC) + @for preset in minimal mainnet; do \ + $(PYTHON_VENV) $(SCRIPTS_DIR)/gen_kzg_trusted_setups.py \ + --secret=1337 \ + --g1-length=4096 \ + --g2-length=65 \ + --output-dir $(CURDIR)/presets/$$preset/trusted_setups; \ + done + +# Run all generators then check for errors. +gen_all: $(GENERATOR_TARGETS) detect_errors + +# Detect errors in generators. +detect_errors: $(TEST_VECTOR_DIR) + @find $(TEST_VECTOR_DIR) -name "INCOMPLETE" + @if [ -f $(GENERATOR_ERROR_LOG_FILE) ]; then \ + echo "[ERROR] $(GENERATOR_ERROR_LOG_FILE) file exists"; \ + else \ + echo "[PASSED] error log file does not exist"; \ + fi + +############################################################################### +# Cleaning +############################################################################### + +# Delete all untracked files. +clean: + @git clean -fdx \ No newline at end of file From 5d9181afbb17428811da78c1e4ac5192c7f6b96a Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Fri, 18 Oct 2024 16:23:50 -0500 Subject: [PATCH 02/25] Update docs & CI files --- .circleci/config.yml | 33 +++---- .github/workflows/docs.yml | 4 +- .github/workflows/generate_vectors.yml | 11 +-- .github/workflows/run-tests.yml | 21 +--- README.md | 3 +- docker/Dockerfile | 5 +- docker/README.md | 2 +- scripts/build_run_docker_tests.sh | 6 +- tests/README.md | 132 +++++++++++-------------- tests/core/pyspec/README.md | 75 +++----------- tests/generators/README.md | 39 ++------ 11 files changed, 99 insertions(+), 232 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 17db49b3a9..340c4b4a71 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -75,7 +75,7 @@ jobs: - restore_pyspec_cached_venv - run: name: Install pyspec requirements - command: make install_test + command: make eth2spec - save_pyspec_cached_venv test-phase0: docker: @@ -87,7 +87,7 @@ jobs: - restore_pyspec_cached_venv - run: name: Run py-tests - command: make citest fork=phase0 + command: make test fork=phase0 - store_test_results: path: tests/core/pyspec/test-reports test-altair: @@ -100,7 +100,7 @@ jobs: - restore_pyspec_cached_venv - run: name: Run py-tests - command: make citest fork=altair + command: make test fork=altair - store_test_results: path: tests/core/pyspec/test-reports test-bellatrix: @@ -113,7 +113,7 @@ jobs: - restore_pyspec_cached_venv - run: name: Run py-tests - command: make citest fork=bellatrix + command: make test fork=bellatrix - store_test_results: path: tests/core/pyspec/test-reports test-capella: @@ -126,7 +126,7 @@ jobs: - restore_pyspec_cached_venv - run: name: Run py-tests - command: make citest fork=capella + command: make test fork=capella - store_test_results: path: tests/core/pyspec/test-reports test-deneb: @@ -139,7 +139,7 @@ jobs: - restore_pyspec_cached_venv - run: name: Run py-tests - command: make citest fork=deneb + command: make test fork=deneb - store_test_results: path: tests/core/pyspec/test-reports test-electra: @@ -152,7 +152,7 @@ jobs: - restore_pyspec_cached_venv - run: name: Run py-tests - command: make citest fork=electra + command: make test fork=electra - store_test_results: path: tests/core/pyspec/test-reports test-whisk: @@ -165,7 +165,7 @@ jobs: - restore_pyspec_cached_venv - run: name: Run py-tests - command: make citest fork=whisk + command: make test fork=whisk - store_test_results: path: tests/core/pyspec/test-reports test-eip7594: @@ -178,7 +178,7 @@ jobs: - restore_pyspec_cached_venv - run: name: Run py-tests - command: make citest fork=eip7594 + command: make test fork=eip7594 - store_test_results: path: tests/core/pyspec/test-reports table_of_contents: @@ -190,15 +190,6 @@ jobs: - run: name: Check table of contents command: sudo npm install -g doctoc@2.2.0 && make check_toc - codespell: - docker: - - image: cimg/python:3.12.4 - working_directory: ~/specs-repo - steps: - - checkout - - run: - name: Check codespell - command: pip install 'codespell<3.0.0,>=2.0.0' --user && make codespell lint: docker: - image: cimg/python:3.12.4 @@ -207,12 +198,12 @@ jobs: - restore_cache: key: v3-specs-repo-{{ .Branch }}-{{ .Revision }} - restore_pyspec_cached_venv + - run: + name: Install codespell + command: pip install 'codespell<3.0.0,>=2.0.0' --user - run: name: Run linter for pyspec command: make lint - - run: - name: Run linter for test generators - command: make lint_generators workflows: version: 2.1 test_spec: diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 209bb4a800..930781e77c 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -3,7 +3,7 @@ name: Publish docs on: push: branches: - - master + - master permissions: contents: write jobs: @@ -12,7 +12,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: Build docs - run: make copy_docs + run: make _copy_docs - uses: actions/setup-python@v4 with: python-version: 3.x diff --git a/.github/workflows/generate_vectors.yml b/.github/workflows/generate_vectors.yml index 1f14ff9158..128d402776 100644 --- a/.github/workflows/generate_vectors.yml +++ b/.github/workflows/generate_vectors.yml @@ -36,19 +36,10 @@ jobs: with: python-version: '3.12.4' cache: '' - - name: Clean up Spec Repository - run: | - cd consensus-specs - make clean - - name: Install dependencies and generate pyspec - run: | - cd consensus-specs - make install_test - make -B pyspec - name: Generate tests run: | cd consensus-specs - make -j 16 generate_tests 2>&1 | tee ../consensustestgen.log + make -j 16 gen_all 2>&1 | tee ../consensustestgen.log cp -r presets/ ../consensus-spec-tests/presets cp -r configs/ ../consensus-spec-tests/configs find . -type d -empty -delete diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 83926c47c5..cbcb933be2 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -37,19 +37,6 @@ jobs: - name: Check table of contents run: npm install -g doctoc@2.2.0 && make check_toc - codespell: - runs-on: [self-hosted-ghr-custom, size-s-x64, profile-consensusSpecs] - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - name: Setup Python - uses: actions/setup-python@v5 - with: - python-version: '3.12.4' - cache: '' - - name: Check codespell - run: make codespell - lint: runs-on: [self-hosted-ghr-custom, size-l-x64, profile-consensusSpecs] steps: @@ -62,12 +49,8 @@ jobs: with: python-version: '3.12.4' cache: '' - - name: Install pyspec requirements - run: make install_test - name: Run linter for pyspec run: make lint - - name: Run linter for test generators - run: make lint_generators pyspec-tests: runs-on: [self-hosted-ghr-custom, size-xl-x64, profile-consensusSpecs] @@ -101,10 +84,8 @@ jobs: if: github.event.schedule=='0 0 * * *' run: | echo "spec_test_preset_type=mainnet" >> $GITHUB_ENV - - name: Install pyspec requirements - run: make install_test - name: test-${{ matrix.version }} - run: make citest fork=${{ matrix.version }} TEST_PRESET_TYPE=${{env.spec_test_preset_type}} + run: make test fork=${{ matrix.version }} TEST_PRESET_TYPE=${{ env.spec_test_preset_type }} - uses: actions/upload-artifact@v4 if: always() with: diff --git a/README.md b/README.md index ae7e566ba8..58adcba89c 100644 --- a/README.md +++ b/README.md @@ -87,8 +87,7 @@ The consensus-specs repo can be used by running the tests locally or inside a do To run the tests locally: - Clone the repository with `git clone https://github.com/ethereum/consensus-specs.git` - Switch to the directory `cd consensus-specs` -- Install the dependencies with: `make install_test && make preinstallation && make pyspec` -- Run the tests with `make citest` +- Run the tests with `make test` To run the tests inside a docker container: - Switch to the directory with `cd scripts` diff --git a/docker/Dockerfile b/docker/Dockerfile index 8ec384499d..d4b2d3567a 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -16,7 +16,4 @@ RUN apt update && ${INSTALL_CMD} && ${PIP_UPGRADE_CMD} && rm -rf /var/lib/apt/li COPY . . # Inline installation commands -RUN make install_test && \ - make preinstallation && \ - make pyspec - +RUN make pyspec diff --git a/docker/README.md b/docker/README.md index 44dc2b95e5..4824fc283a 100644 --- a/docker/README.md +++ b/docker/README.md @@ -6,7 +6,7 @@ This dockerfile sets up the dependencies required to run consensus-spec tests. T Handy commands: - `docker run -it $IMAGE_NAME /bin/sh` will give you a shell inside the docker container to manually run any tests -- `docker run $IMAGE_NAME make citest` will run the make citest command inside the docker container +- `docker run $IMAGE_NAME make test` will run the make test command inside the docker container Ideally manual running of docker containers is for advanced users, we recommend the script based approach described below for most users. diff --git a/scripts/build_run_docker_tests.sh b/scripts/build_run_docker_tests.sh index 91aa2c8ae1..baafa4d509 100755 --- a/scripts/build_run_docker_tests.sh +++ b/scripts/build_run_docker_tests.sh @@ -82,16 +82,16 @@ else echo "Image $IMAGE_NAME already exists. Skipping build..." fi -# Equivalent to `make citest with the subsequent flags` +# Equivalent to `make test 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 + make test fork=$fork TEST_PRESET_TYPE=$TEST_PRESET_TYPE 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 + make test fork=$FORK_TO_TEST TEST_PRESET_TYPE=$TEST_PRESET_TYPE copy_test_results $FORK_TO_TEST fi diff --git a/tests/README.md b/tests/README.md index 8c281155c5..798627577d 100644 --- a/tests/README.md +++ b/tests/README.md @@ -15,55 +15,36 @@ Use an OS that has Python 3.8 or above. For example, Debian 11 (bullseye) git clone https://github.com/ethereum/consensus-specs.git cd consensus-specs ``` -3. Create the specifications and tests: +3. Create the specifications and tests: ```sh - make install_test - make pyspec + make ``` To read more about creating the environment, [see here](core/pyspec/README.md). ### Running your first test +Use `make` to run the `test_empty_block_transition` tests against the Altair fork like so: -1. Enter the virtual Python environment: - ```sh - cd ~/consensus-specs - . venv/bin/activate - ``` -2. Run a sanity check test against Altair fork: - ```sh - cd tests/core/pyspec - python -m pytest -k test_empty_block_transition --fork altair eth2spec - ``` -3. The output should be similar to: - ``` - ============================= test session starts ============================== - platform linux -- Python 3.9.2, pytest-6.2.5, py-1.10.0, pluggy-1.0.0 - rootdir: /home/qbzzt1/consensus-specs - plugins: cov-2.12.1, forked-1.3.0, xdist-2.3.0 - collected 629 items / 626 deselected / 3 selected - - eth2spec/test/bellatrix/sanity/test_blocks.py . [ 33%] - eth2spec/test/phase0/sanity/test_blocks.py .. [100%] - - =============================== warnings summary =============================== - ../../../venv/lib/python3.9/site-packages/cytoolz/compatibility.py:2 - /home/qbzzt1/consensus-specs/venv/lib/python3.9/site-packages/cytoolz/compatibility.py:2: - DeprecationWarning: The toolz.compatibility module is no longer needed in Python 3 and has - been deprecated. Please import these utilities directly from the standard library. This - module will be removed in a future release. - warnings.warn("The toolz.compatibility module is no longer " - - -- Docs: https://docs.pytest.org/en/stable/warnings.html - ================ 3 passed, 626 deselected, 1 warning in 16.81s ================= - ``` - +``` +$ make test k=test_empty_block_transition fork=altair +Building all pyspecs +... +================================= test session starts ================================== +platform darwin -- Python 3.10.3, pytest-8.3.3, pluggy-1.5.0 +rootdir: /Users/jtraglia/Projects/jtraglia/consensus-specs +plugins: cov-5.0.0, xdist-3.6.1 +20 workers [3 items] +s.. [100%] +=================================== warnings summary =================================== +-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html +====================== 2 passed, 1 skipped, 42 warnings in 7.97s ======================= +``` ## The "Hello, World" of Consensus Spec Tests One of the `test_empty_block_transition` tests is implemented by a function with the same -name located in +name located in [`~/consensus-specs/tests/core/pyspec/eth2spec/test/phase0/sanity/test_blocks.py`](https://github.com/ethereum/consensus-specs/blob/dev/tests/core/pyspec/eth2spec/test/phase0/sanity/test_blocks.py). To learn how consensus spec tests are written, let's go over the code: @@ -94,10 +75,10 @@ This type of test receives two parameters: ```python pre_slot = state.slot -``` +``` A slot is a unit of time (every 12 seconds in mainnet), for which a specific validator (selected randomly but in a -deterministic manner) is a proposer. The proposer can propose a block during that slot. +deterministic manner) is a proposer. The proposer can propose a block during that slot. ```python pre_eth1_votes = len(state.eth1_data_votes) @@ -151,7 +132,7 @@ More `yield` statements. The output of a consensus test is: # Check that the new parent root is correct assert spec.get_block_root_at_slot(state, pre_slot) == signed_block.message.parent_root - + # Random data changed assert spec.get_randao_mix(state, spec.get_current_epoch(state)) != pre_mix ``` @@ -160,16 +141,16 @@ Finally we assertions that test the transition was legitimate. In this case we h 1. One item was added to `eth1_data_votes` 2. The new block's `parent_root` is the same as the block in the previous location -3. The random data that every block includes was changed. +3. The random data that every block includes was changed. ## New Tests The easiest way to write a new test is to copy and modify an existing one. For example, -lets write a test where the first slot of the beacon chain is empty (because the assigned +lets write a test where the first slot of the beacon chain is empty (because the assigned proposer is offline, for example), and then there's an empty block in the second slot. -We already know how to accomplish most of what we need for this test, but the only way we know +We already know how to accomplish most of what we need for this test, but the only way we know to advance the state is `state_transition_and_sign_block`, a function that also puts a block into the slot. So let's see if the function's definition tells us how to advance the state without a block. @@ -180,7 +161,7 @@ First, we need to find out where the function is located. Run: find . -name '*.py' -exec grep 'def state_transition_and_sign_block' {} \; -print ``` -And you'll find that the function is defined in +And you'll find that the function is defined in [`eth2spec/test/helpers/state.py`](https://github.com/ethereum/consensus-specs/blob/dev/tests/core/pyspec/eth2spec/test/helpers/state.py). Looking in that file, we see that the second function is: @@ -209,7 +190,7 @@ This looks like exactly what we need. So we add this call before we create the e . ``` -That's it. Our new test works (copy `test_empty_block_transition`, rename it, add the `next_slot` call, and then run it to +That's it. Our new test works (copy `test_empty_block_transition`, rename it, add the `next_slot` call, and then run it to verify this). @@ -218,7 +199,7 @@ verify this). It is important to make sure that the system rejects invalid input, so our next step is to deal with cases where the protocol is supposed to reject something. To see such a test, look at `test_prev_slot_block_transition` (in the same -file we used previously, +file we used previously, [`~/consensus-specs/tests/core/pyspec/eth2spec/test/phase0/sanity/test_blocks.py`](https://github.com/ethereum/consensus-specs/blob/dev/tests/core/pyspec/eth2spec/test/phase0/sanity/test_blocks.py)). ```python @@ -249,7 +230,7 @@ Transition to the new slot, which naturally has a different proposer. ``` Specify that the function `transition_unsigned_block` will cause an assertion error. -You can see this function in +You can see this function in [`~/consensus-specs/tests/core/pyspec/eth2spec/test/helpers/block.py`](https://github.com/ethereum/consensus-specs/blob/dev/tests/core/pyspec/eth2spec/test/helpers/block.py), and one of the tests is that the block must be for this slot: > ```python @@ -265,14 +246,14 @@ be called later. ``` Set the block's state root to the current state hash tree root, which identifies this block as -belonging to this slot (even though it was created for the previous slot). +belonging to this slot (even though it was created for the previous slot). -```python +```python signed_block = sign_block(spec, state, block, proposer_index=proposer_index) ``` Notice that `proposer_index` is the variable we set earlier, *before* we advanced -the slot with `spec.process_slots(state, state.slot + 1)`. It is not the proposer +the slot with `spec.process_slots(state, state.slot + 1)`. It is not the proposer for the current state. ```python @@ -296,8 +277,8 @@ includes the block hash of the proposed new head of the execution layer. For every slot there is also a randomly selected committee of validators that needs to vote whether the new consensus layer block is valid, which requires the proposed head of the execution chain to -also be a valid block. These votes are called [attestations](https://notes.ethereum.org/@hww/aggregation#112-Attestation), -and they are sent as independent messages. The proposer for a block is able to include attestations from previous slots, +also be a valid block. These votes are called [attestations](https://notes.ethereum.org/@hww/aggregation#112-Attestation), +and they are sent as independent messages. The proposer for a block is able to include attestations from previous slots, which is how they get on chain to form consensus, reward honest validators, etc. [You can see a simple successful attestation test here](https://github.com/ethereum/consensus-specs/blob/926e5a3d722df973b9a12f12c015783de35cafa9/tests/core/pyspec/eth2spec/test/phase0/block_processing/test_process_attestation.py#L26-L30): @@ -326,8 +307,8 @@ To see an attestion "from the inside" we need to follow it. > ``` > > Only two parameters, `spec` and `state` are required. However, there are four other parameters that can affect -> the attestation created by this function. -> +> the attestation created by this function. +> > > ```python > # If filter_participant_set filters everything, the attestation has 0 participants, and cannot be signed. @@ -345,10 +326,10 @@ To see an attestion "from the inside" we need to follow it. > attestation_data = build_attestation_data( > spec, state, slot=slot, index=index > ) -> ``` +> ``` > -> Build the actual attestation. You can see this function -> [here](https://github.com/ethereum/consensus-specs/blob/30fe7ba1107d976100eb0c3252ca7637b791e43a/tests/core/pyspec/eth2spec/test/helpers/attestations.py#L53-L85) +> Build the actual attestation. You can see this function +> [here](https://github.com/ethereum/consensus-specs/blob/30fe7ba1107d976100eb0c3252ca7637b791e43a/tests/core/pyspec/eth2spec/test/helpers/attestations.py#L53-L85) > to see the exact data in an attestation. > > ```python @@ -358,17 +339,17 @@ To see an attestion "from the inside" we need to follow it. > attestation_data.index, > ) > ``` -> +> > This is the committee that is supposed to approve or reject the proposed block. -> -> ```python -> +> +> ```python +> > committee_size = len(beacon_committee) > aggregation_bits = Bitlist[spec.MAX_VALIDATORS_PER_COMMITTEE](*([0] * committee_size)) > ``` -> +> > There's a bit for every committee member to see if it approves or not. -> +> > ```python > attestation = spec.Attestation( > aggregation_bits=aggregation_bits, @@ -376,15 +357,15 @@ To see an attestion "from the inside" we need to follow it. > ) > # fill the attestation with (optionally filtered) participants, and optionally sign it > fill_aggregate_attestation(spec, state, attestation, signed=signed, filter_participant_set=filter_participant_set) -> -> return attestation +> +> return attestation > ``` ```python next_slots(spec, state, spec.MIN_ATTESTATION_INCLUSION_DELAY) ``` -Attestations have to appear after the block they attest for, so we advance +Attestations have to appear after the block they attest for, so we advance `spec.MIN_ATTESTATION_INCLUSION_DELAY` slots before creating the block that includes the attestation. Currently a single block is sufficient, but that may change in the future. @@ -392,7 +373,7 @@ Currently a single block is sufficient, but that may change in the future. yield from run_attestation_processing(spec, state, attestation) ``` -[This function](https://github.com/ethereum/consensus-specs/blob/30fe7ba1107d976100eb0c3252ca7637b791e43a/tests/core/pyspec/eth2spec/test/helpers/attestations.py#L13-L50) +[This function](https://github.com/ethereum/consensus-specs/blob/30fe7ba1107d976100eb0c3252ca7637b791e43a/tests/core/pyspec/eth2spec/test/helpers/attestations.py#L13-L50) processes the attestation and returns the result. @@ -419,15 +400,15 @@ In the last line you can see two conditions being asserted: arrive too early. 2. `state.slot <= data.slot + SLOTS_PER_EPOCH` which verifies that the attestation doesn't arrive too late. - + This is how the consensus layer tests deal with edge cases, by asserting the conditions required for the -values to be legitimate. In the case of these particular conditions, they are tested +values to be legitimate. In the case of these particular conditions, they are tested [here](https://github.com/ethereum/consensus-specs/blob/926e5a3d722df973b9a12f12c015783de35cafa9/tests/core/pyspec/eth2spec/test/phase0/block_processing/test_process_attestation.py#L87-L104). One test checks what happens if the attestation is too early, and another if it is too late. However, it is not enough to ensure we reject invalid blocks. It is also necessary to ensure we accept all valid blocks. You saw earlier -a test (`test_success`) that tested that being `MIN_ATTESTATION_INCLUSION_DELAY` after the data for which we attest is enough. -Now we'll write a similar test that verifies that being `SLOTS_PER_EPOCH` away is still valid. To do this, we modify the +a test (`test_success`) that tested that being `MIN_ATTESTATION_INCLUSION_DELAY` after the data for which we attest is enough. +Now we'll write a similar test that verifies that being `SLOTS_PER_EPOCH` away is still valid. To do this, we modify the `test_after_epoch_slots` function. We need two changes: 1. Call `transition_to_slot_via_block` with one less slot to advance @@ -445,16 +426,13 @@ def test_almost_after_epoch_slots(spec, state): transition_to_slot_via_block(spec, state, state.slot + spec.SLOTS_PER_EPOCH) yield from run_attestation_processing(spec, state, attestation) -``` +``` Add this function to the file `consensus-specs/tests/core/pyspec/eth2spec/test/phase0/block_processing/test_process_attestation.py`, and run the test against Altair fork: ```sh -cd ~/consensus-specs -. venv/bin/activate -cd tests/core/pyspec -python -m pytest -k almost_after --fork altair eth2spec +make test k=almost_after fork=altair ``` You should see it ran successfully (although you might get a warning, you can ignore it) @@ -463,7 +441,7 @@ You should see it ran successfully (although you might get a warning, you can ig So far we've ran tests against the formal specifications. This is a way to check the specifications are what we expect, but it doesn't actually check the beacon chain clients. The way these tests get applied -by clients is that every few weeks +by clients is that every few weeks [new test specifications are released](https://github.com/ethereum/consensus-spec-tests/releases), in a format [documented here](https://github.com/ethereum/consensus-specs/tree/dev/tests/formats). All the consensus layer clients implement test-runners that consume the test vectors in this standard format. diff --git a/tests/core/pyspec/README.md b/tests/core/pyspec/README.md index baa1322771..2fdd107fb1 100644 --- a/tests/core/pyspec/README.md +++ b/tests/core/pyspec/README.md @@ -7,29 +7,6 @@ With this executable spec, test-generators can easily create test-vectors for client implementations, and the spec itself can be verified to be consistent and coherent through sanity tests implemented with pytest. -## Dev Install - -First, create a `venv` and install the developer dependencies (`test` and `lint` extras): - -```shell -make install_test -``` - -All the dynamic parts of the spec are built with: - -```shell -(venv) python setup.py pyspecdev -``` - -Unlike the regular install, this outputs spec files to their intended source location, -to enable debuggers to navigate between packages and generated code, without fragile directory linking. - -By default, when installing the `eth2spec` as package in non-develop mode, -the distutils implementation of the `setup` runs `build`, which is extended to run the same `pyspec` work, -but outputs into the standard `./build/lib` output. -This enables the `consensus-specs` repository to be installed like any other python package. - - ## Py-tests These tests are not intended for client-consumption. @@ -38,61 +15,41 @@ However, most of the tests can be run in generator-mode, to output test vectors ### How to run tests -#### Automated - -Run `make test` from the root of the specs repository (after running `make install_test` if have not before). - -Note that the `make` commands run through the build steps: it runs the `build` output, not the local package source files. - -#### Manual - -See `Dev install` for test pre-requisites. - -Tests are built for `pytest`. - -Caveats: -- Working directory must be `./tests/core/pyspec`. The work-directory is important to locate eth2 configuration files. -- Run `pytest` as module. It avoids environment differences, and the behavior is different too: - `pytest` as module adds the current directory to the `sys.path` +To run all tests: +```shell +make test +``` -Full test usage, with explicit configuration for illustration of options usage: +To run all tests under the minimal preset: ```shell -(venv) python -m pytest --preset=minimal eth2spec +make test preset=minimal ``` -Or, to run a specific test file, specify the full path: +Or, to run a specific test function specify `k=`: ```shell -(venv) python -m pytest --preset=minimal ./eth2spec/test/phase0/block_processing/test_process_attestation.py +make test k=test_verify_kzg_proof ``` -Or, to run a specific test function (specify the `eth2spec` module, or the script path if the keyword is ambiguous): +Or, to run a specific test function under a single fork specify `k=`: ```shell -(venv) python -m pytest --preset=minimal -k test_success_multi_proposer_index_iterations eth2spec +make test fork=phase0 ``` -Options: -- `--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) +Note: these options can be used together, like: -### How to view code coverage report - -Run `make open_cov` from the root of the specs repository after running `make test` to open the html code coverage report. +```shell +make test preset=minimal k=test_verify_kzg_proof fork=deneb +``` -### Advanced +### How to view code coverage report -Building spec files from any markdown sources, to a custom location: -```bash -(venv) python setup.py pyspec --spec-fork=phase0 --md-doc-paths="specs/phase0/beacon-chain.md specs/phase0/fork-choice.md" --out-dir=my_spec_dir -``` +Run `make coverage` to run all tests and open the html code coverage report. ## Contributing Contributions are welcome, but consider implementing your idea as part of the spec itself first. The pyspec is not a replacement. - ## License Same as the spec itself; see [LICENSE](../../../LICENSE) file in the specs repository root. diff --git a/tests/generators/README.md b/tests/generators/README.md index 148415f4de..270d107ea5 100644 --- a/tests/generators/README.md +++ b/tests/generators/README.md @@ -7,7 +7,7 @@ Any issues with the generators and/or generated tests should be filed in the rep On releases, test generators are run by the release manager. Test-generation of mainnet tests can take a significant amount of time, and is better left out of a CI setup. -An automated nightly tests release system, with a config filter applied, is being considered as implementation needs mature. +An automated nightly tests release system, with a config filter applied, is being considered as implementation needs mature. ## Table of contents @@ -39,7 +39,7 @@ Prerequisites: This removes the existing virtual environments (`/tests/generators//venv`) and generated tests (`../consensus-spec-tests/tests`). ```bash -make clean +make clean && rm -rf ../consensus-spec-tests/tests ``` ### Running all test generators @@ -47,7 +47,7 @@ make clean This runs all of the generators. ```bash -make -j 4 generate_tests +make -j 4 gen_all ``` The `-j N` flag makes the generators run in parallel, with `N` being the amount of cores. @@ -63,39 +63,12 @@ make gen_ssz_static ## Developing a generator -Simply open up the generator (not all at once) of choice in your favorite IDE/editor and run: - -```bash -# From the root of the generator directory: -# Create a virtual environment (any venv/.venv/.venvs is git-ignored) -python3 -m venv venv -# Activate the venv, this is where dependencies are installed for the generator -. venv/bin/activate -``` - -Now that you have a virtual environment, write your generator. -It's recommended to extend the base-generator. - -Create a `requirements.txt` in the root of your generator directory: -``` -pytest>=4.4 -../../../[generator] -``` - The config helper and pyspec is optional, but preferred. We encourage generators to derive tests from the spec itself in order to prevent code duplication and outdated tests. Applying configurations to the spec is simple and enables you to create test suites with different contexts. *Note*: Make sure to run `make pyspec` from the root of the specs repository in order to build the pyspec requirement. -Install all the necessary requirements (re-run when you add more): -```bash -pip3 install -r requirements.txt -``` - -Note that you may need `PYTHONPATH` to include the pyspec directory, as with running normal tests, - to run test generators manually. The makefile handles this for you already. - -And write your initial test generator, extending the base generator: +Write your initial test generator, extending the base generator: Write a `main.py` file. The shuffling test generator is a good minimal starting point: @@ -196,9 +169,9 @@ Recommendations: - You can have more than just one test provider. - Your test provider is free to output any configuration and combination of runner/handler/fork/case name. - You can split your test case generators into different Python files/packages; this is good for code organization. -- Use config `minimal` for performance and simplicity, but also implement a suite with the `mainnet` config where necessary. +- Use config `minimal` for performance and simplicity, but also implement a suite with the `mainnet` config where necessary. - You may be able to write your test case provider in a way where it does not make assumptions on constants. - If so, you can generate test cases with different configurations for the same scenario (see example). + If so, you can generate test cases with different configurations for the same scenario (see example). - See [`tests/core/gen_helpers/README.md`](../core/pyspec/eth2spec/gen_helpers/README.md) for command line options for generators. ## How to add a new test generator From d7a81f59476d61d364652b984e8d90341ce9ff1e Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Fri, 18 Oct 2024 16:44:53 -0500 Subject: [PATCH 03/25] Add preset & bls options for make test --- .github/workflows/run-tests.yml | 12 ++++++------ Makefile | 28 +++++++++++++++------------- scripts/build_run_docker_tests.sh | 4 ++-- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index cbcb933be2..40bb558507 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -68,24 +68,24 @@ jobs: with: python-version: '3.12.4' cache: '' - - name: set TEST_PRESET_TYPE + - name: set preset if: github.event.inputs.test_preset_type != '' run: | echo "spec_test_preset_type=${{ github.event.inputs.test_preset_type || env.TEST_PRESET_TYPE }}" >> $GITHUB_ENV - - name: set TEST_PRESET_TYPE + - name: set preset if: ${{ (github.event_name == 'push' && github.ref_name != 'master') || github.event_name == 'pull_request' }} run: | - echo "spec_test_preset_type=${{ env.TEST_PRESET_TYPE}}" >> $GITHUB_ENV - - name: set TEST_PRESET_TYPE + echo "spec_test_preset_type=${{ env.TEST_PRESET_TYPE }}" >> $GITHUB_ENV + - name: set preset if: ${{ github.event_name == 'push' && github.ref_name == 'master' }} run: | echo "spec_test_preset_type=mainnet" >> $GITHUB_ENV - - name: set TEST_PRESET_TYPE + - name: set preset if: github.event.schedule=='0 0 * * *' run: | echo "spec_test_preset_type=mainnet" >> $GITHUB_ENV - name: test-${{ matrix.version }} - run: make test fork=${{ matrix.version }} TEST_PRESET_TYPE=${{ env.spec_test_preset_type }} + run: make test fork=${{ matrix.version }} preset=${{ env.spec_test_preset_type }} - uses: actions/upload-artifact@v4 if: always() with: diff --git a/Makefile b/Makefile index 1f4880d928..3960ed7922 100644 --- a/Makefile +++ b/Makefile @@ -111,26 +111,31 @@ pyspec: $(VENV) setup.py # Testing ############################################################################### -TEST_PRESET_TYPE ?= minimal TEST_REPORT_DIR = $(PY_SPEC_DIR)/test-reports # Run pyspec tests. -# To only run a specific test, prepend with k=, eg: +# To run a specific test, append k=, eg: # make test k=test_verify_kzg_proof -# To only run tests for a specific fork, prepend with fork=, eg: +# To run tests for a specific fork, append fork=, eg: # make test fork=deneb -# Or both at the same time, eg: -# make test fork=deneb k=test_verify_kzg_proof +# To run tests for a specific preset, append preset=, eg: +# make test preset=mainnet +# Or all at the same time, eg: +# make test preset=mainnet fork=deneb k=test_verify_kzg_proof +# To run tests with a specific bls library, append bls=, eg: +# make test bls=arkworks test: MAYBE_TEST := $(if $(k),-k=$(k)) test: MAYBE_FORK := $(if $(fork),--fork=$(fork)) +test: PRESET := --preset=$(if $(preset),$(preset),minimal) +test: BLS := --bls-type=$(if $(bls),$(bls),fastest) test: $(ETH2SPEC) pyspec @mkdir -p $(TEST_REPORT_DIR) @$(PYTHON_VENV) -m pytest \ -n auto \ $(MAYBE_TEST) \ $(MAYBE_FORK) \ - --bls-type=fastest \ - --preset=$(TEST_PRESET_TYPE) \ + $(PRESET) \ + $(BLS) \ --junitxml=$(TEST_REPORT_DIR)/test_results.xml \ $(PY_SPEC_DIR)/eth2spec @@ -138,6 +143,7 @@ test: $(ETH2SPEC) pyspec # Coverage ############################################################################### +TEST_PRESET_TYPE ?= minimal COV_HTML_OUT=$(PY_SPEC_DIR)/.htmlcov COV_INDEX_FILE=$(COV_HTML_OUT)/index.html COVERAGE_SCOPE := $(foreach S,$(ALL_EXECUTABLE_SPEC_NAMES), --cov=eth2spec.$S.$(TEST_PRESET_TYPE)) @@ -156,12 +162,8 @@ _test_with_coverage: $(ETH2SPEC) pyspec --cov-branch \ $(PY_SPEC_DIR)/eth2spec -# To only run a specific test, prepend with k=, eg: -# make coverage k=test_verify_kzg_proof -# To only run tests for a specific fork, prepend with fork=, eg: -# make coverage fork=altair -# Or both at the same time, eg: -# make coverage fork=deneb k=test_verify_kzg_proof +# Run tests with coverage then open the coverage report. +# See `make test` for a list of options. coverage: _test_with_coverage @echo "Opening result: $(COV_INDEX_FILE)" @((open "$(COV_INDEX_FILE)" || xdg-open "$(COV_INDEX_FILE)") &> /dev/null) & diff --git a/scripts/build_run_docker_tests.sh b/scripts/build_run_docker_tests.sh index baafa4d509..30b9eebd14 100755 --- a/scripts/build_run_docker_tests.sh +++ b/scripts/build_run_docker_tests.sh @@ -86,12 +86,12 @@ fi if [ "$FORK_TO_TEST" == "all" ]; then for fork in "${ALL_EXECUTABLE_SPECS[@]}"; do docker run --name $CONTAINER_NAME $IMAGE_NAME \ - make test fork=$fork TEST_PRESET_TYPE=$TEST_PRESET_TYPE + make test fork=$fork preset=$TEST_PRESET_TYPE copy_test_results $fork done else docker run --name $CONTAINER_NAME $IMAGE_NAME \ - make test fork=$FORK_TO_TEST TEST_PRESET_TYPE=$TEST_PRESET_TYPE + make test fork=$FORK_TO_TEST preset=$TEST_PRESET_TYPE copy_test_results $FORK_TO_TEST fi From d4314205e0d8f0e1f905c5db36e736bc950c627a Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Fri, 18 Oct 2024 16:46:49 -0500 Subject: [PATCH 04/25] Remove old reference to codespell rule --- .circleci/config.yml | 1 - .github/workflows/run-tests.yml | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 340c4b4a71..4f434215d3 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -237,7 +237,6 @@ workflows: requires: - install_pyspec_test - table_of_contents - - codespell - lint: requires: - install_pyspec_test diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 40bb558507..0541311e6e 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -54,7 +54,7 @@ jobs: pyspec-tests: runs-on: [self-hosted-ghr-custom, size-xl-x64, profile-consensusSpecs] - needs: [lint,codespell,table_of_contents] + needs: [lint,table_of_contents] strategy: matrix: version: ["phase0", "altair", "bellatrix", "capella", "deneb", "electra", "whisk", "eip7594"] From 788fae89703e997a0460d11ad6cc64df95814fe9 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Fri, 18 Oct 2024 16:57:00 -0500 Subject: [PATCH 05/25] Fix CI linter checks --- .circleci/config.yml | 13 +++---------- .github/workflows/run-tests.yml | 19 +++++-------------- 2 files changed, 8 insertions(+), 24 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 4f434215d3..d66e9bb77c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -181,15 +181,6 @@ jobs: command: make test fork=eip7594 - store_test_results: path: tests/core/pyspec/test-reports - table_of_contents: - docker: - - image: circleci/node:10.16.3 - working_directory: ~/specs-repo - steps: - - checkout - - run: - name: Check table of contents - command: sudo npm install -g doctoc@2.2.0 && make check_toc lint: docker: - image: cimg/python:3.12.4 @@ -198,6 +189,9 @@ jobs: - restore_cache: key: v3-specs-repo-{{ .Branch }}-{{ .Revision }} - restore_pyspec_cached_venv + - run: + name: Install doctoc + command: sudo npm install -g doctoc@2.2.0 - run: name: Install codespell command: pip install 'codespell<3.0.0,>=2.0.0' --user @@ -236,7 +230,6 @@ workflows: - test-eip7594: requires: - install_pyspec_test - - table_of_contents - lint: requires: - install_pyspec_test diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 0541311e6e..cf5cc26db7 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -24,19 +24,6 @@ on: - cron: '0 0 * * *' jobs: - table_of_contents: - runs-on: [self-hosted-ghr-custom, size-s-x64, profile-consensusSpecs] - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '20' - cache: '' - - name: Check table of contents - run: npm install -g doctoc@2.2.0 && make check_toc - lint: runs-on: [self-hosted-ghr-custom, size-l-x64, profile-consensusSpecs] steps: @@ -49,12 +36,16 @@ jobs: with: python-version: '3.12.4' cache: '' + - name: Install doctoc + run: npm install -g doctoc@2.2.0 + - name: Install codespell + run: pip install 'codespell<3.0.0,>=2.0.0' --user - name: Run linter for pyspec run: make lint pyspec-tests: runs-on: [self-hosted-ghr-custom, size-xl-x64, profile-consensusSpecs] - needs: [lint,table_of_contents] + needs: [lint] strategy: matrix: version: ["phase0", "altair", "bellatrix", "capella", "deneb", "electra", "whisk", "eip7594"] From ab59dca3c55788ed3705157ffa8e5f69eb721781 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Fri, 18 Oct 2024 17:22:28 -0500 Subject: [PATCH 06/25] Maybe fix CI --- .circleci/config.yml | 2 +- .github/workflows/run-tests.yml | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index d66e9bb77c..f5c5c2ee69 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -183,7 +183,7 @@ jobs: path: tests/core/pyspec/test-reports lint: docker: - - image: cimg/python:3.12.4 + - image: cimg/python:3.12-node working_directory: ~/specs-repo steps: - restore_cache: diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index cf5cc26db7..f4cb16a307 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -29,8 +29,11 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v4 - - name: Setup Rust for dependencies - uses: actions-rust-lang/setup-rust-toolchain@v1 + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: '' - name: Setup Python uses: actions/setup-python@v5 with: From 27847a7a179d3763bf78747236ceff789db67e6c Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Fri, 18 Oct 2024 17:57:42 -0500 Subject: [PATCH 07/25] Maybe fix CI lint --- .circleci/config.yml | 5 +++-- .github/workflows/run-tests.yml | 2 -- Makefile | 7 ++++--- setup.py | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index f5c5c2ee69..505a822a19 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -193,8 +193,9 @@ jobs: name: Install doctoc command: sudo npm install -g doctoc@2.2.0 - run: - name: Install codespell - command: pip install 'codespell<3.0.0,>=2.0.0' --user + name: Create Python3 alias + command: | + sudo ln -sf $(which python) /usr/bin/python3 - run: name: Run linter for pyspec command: make lint diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index f4cb16a307..52c7760505 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -41,8 +41,6 @@ jobs: cache: '' - name: Install doctoc run: npm install -g doctoc@2.2.0 - - name: Install codespell - run: pip install 'codespell<3.0.0,>=2.0.0' --user - name: Run linter for pyspec run: make lint diff --git a/Makefile b/Makefile index 3960ed7922..833dfccc6f 100644 --- a/Makefile +++ b/Makefile @@ -58,6 +58,7 @@ help: VENV_DIR = $(CURDIR)/venv PYTHON_VENV = $(VENV_DIR)/bin/python3 PIP_VENV = $(VENV_DIR)/bin/pip +CODESPELL_VENV = $(VENV_DIR)/bin/codespell VENV = $(VENV_DIR)/.venv_done # Make a virtual environment will all of the necessary dependencies. @@ -223,9 +224,9 @@ check_toc: $(MARKDOWN_FILES:=.toc) # Check for mistakes. lint: $(ETH2SPEC) pyspec check_toc - @codespell . --skip "./.git,./venv,$(PY_SPEC_DIR)/.mypy_cache" -I .codespell-whitelist - @flake8 --config $(LINTER_CONFIG_FILE) $(PY_SPEC_DIR)/eth2spec - @flake8 --config $(LINTER_CONFIG_FILE) $(TEST_GENERATORS_DIR) + @$(CODESPELL_VENV) . --skip "./.git,./venv,$(PY_SPEC_DIR)/.mypy_cache" -I .codespell-whitelist + @$(PYTHON_VENV) -m flake8 --config $(LINTER_CONFIG_FILE) $(PY_SPEC_DIR)/eth2spec + @$(PYTHON_VENV) -m flake8 --config $(LINTER_CONFIG_FILE) $(TEST_GENERATORS_DIR) @$(PYTHON_VENV) -m pylint --rcfile $(LINTER_CONFIG_FILE) $(PYLINT_SCOPE) @$(PYTHON_VENV) -m mypy --config-file $(LINTER_CONFIG_FILE) $(MYPY_SCOPE) diff --git a/setup.py b/setup.py index f976778dc9..f8d813be31 100644 --- a/setup.py +++ b/setup.py @@ -561,7 +561,7 @@ def run(self): python_requires=">=3.9, <4", extras_require={ "test": ["pytest>=4.4", "pytest-cov", "pytest-xdist"], - "lint": ["flake8==5.0.4", "mypy==0.981", "pylint==2.15.3"], + "lint": ["flake8==5.0.4", "mypy==0.981", "pylint==3.3.1", "codespell<3.0.0,>=2.0.0"], "generator": ["setuptools>=72.0.0", "pytest>4.4", "python-snappy==0.7.3", "filelock", "pathos==0.3.0"], "docs": ["mkdocs==1.4.2", "mkdocs-material==9.1.5", "mdx-truly-sane-lists==1.3", "mkdocs-awesome-pages-plugin==2.8.0"] }, From e64f9517c690b87e4a02ff2707a6d6f110f26391 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Fri, 18 Oct 2024 18:01:48 -0500 Subject: [PATCH 08/25] Change pip to pip3 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 833dfccc6f..996e400b2c 100644 --- a/Makefile +++ b/Makefile @@ -57,7 +57,7 @@ help: VENV_DIR = $(CURDIR)/venv PYTHON_VENV = $(VENV_DIR)/bin/python3 -PIP_VENV = $(VENV_DIR)/bin/pip +PIP_VENV = $(VENV_DIR)/bin/pip3 CODESPELL_VENV = $(VENV_DIR)/bin/codespell VENV = $(VENV_DIR)/.venv_done From 132fad03837f62b93c0f5c570158e4d41a3d031d Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Fri, 18 Oct 2024 18:12:45 -0500 Subject: [PATCH 09/25] Try manually installing python3 --- .circleci/config.yml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 505a822a19..d28c630be8 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -183,19 +183,18 @@ jobs: path: tests/core/pyspec/test-reports lint: docker: - - image: cimg/python:3.12-node + - image: circleci/node:10.16.3 working_directory: ~/specs-repo steps: - restore_cache: key: v3-specs-repo-{{ .Branch }}-{{ .Revision }} - restore_pyspec_cached_venv + - run: + name: Install Python3 + command: sudo apt-get update && sudo apt-get install -y python3.12 - run: name: Install doctoc command: sudo npm install -g doctoc@2.2.0 - - run: - name: Create Python3 alias - command: | - sudo ln -sf $(which python) /usr/bin/python3 - run: name: Run linter for pyspec command: make lint From 05c93996a4b09df4d952b589682e871f8e50f993 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Fri, 18 Oct 2024 18:18:01 -0500 Subject: [PATCH 10/25] Try latest node image --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index d28c630be8..65dc541df3 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -183,7 +183,7 @@ jobs: path: tests/core/pyspec/test-reports lint: docker: - - image: circleci/node:10.16.3 + - image: cimg/node working_directory: ~/specs-repo steps: - restore_cache: From 4b130d82ceba42c31c18565d6e309cbe4bc42c12 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Fri, 18 Oct 2024 18:20:10 -0500 Subject: [PATCH 11/25] Use node 23 --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 65dc541df3..f6d5f6bdbe 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -183,7 +183,7 @@ jobs: path: tests/core/pyspec/test-reports lint: docker: - - image: cimg/node + - image: cimg/node:23.0.0 working_directory: ~/specs-repo steps: - restore_cache: From 8a7adbd745acf0ed3d7c5036b90e7961b6412017 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Fri, 18 Oct 2024 18:22:32 -0500 Subject: [PATCH 12/25] Apt install python3 --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index f6d5f6bdbe..05955e2d91 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -191,7 +191,7 @@ jobs: - restore_pyspec_cached_venv - run: name: Install Python3 - command: sudo apt-get update && sudo apt-get install -y python3.12 + command: sudo apt-get update && sudo apt-get install -y python3 - run: name: Install doctoc command: sudo npm install -g doctoc@2.2.0 From a7519ae34569c2a404be8a2062fd857e2f8f9495 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Fri, 18 Oct 2024 18:34:14 -0500 Subject: [PATCH 13/25] Clean things up --- .circleci/config.yml | 9 +++------ Makefile | 13 +++++-------- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 05955e2d91..d0b06d3230 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -35,13 +35,13 @@ commands: description: "Restore the cache with pyspec keys" steps: - restore_cached_venv: - venv_name: v25-pyspec + venv_name: v26-pyspec reqs_checksum: cache-{{ checksum "setup.py" }}-{{ checksum "requirements_preinstallation.txt" }} save_pyspec_cached_venv: description: Save a venv into a cache with pyspec keys" steps: - save_cached_venv: - venv_name: v25-pyspec + venv_name: v26-pyspec reqs_checksum: cache-{{ checksum "setup.py" }}-{{ checksum "requirements_preinstallation.txt" }} venv_path: ./venv jobs: @@ -183,15 +183,12 @@ jobs: path: tests/core/pyspec/test-reports lint: docker: - - image: cimg/node:23.0.0 + - image: cimg/python:3.12-node working_directory: ~/specs-repo steps: - restore_cache: key: v3-specs-repo-{{ .Branch }}-{{ .Revision }} - restore_pyspec_cached_venv - - run: - name: Install Python3 - command: sudo apt-get update && sudo apt-get install -y python3 - run: name: Install doctoc command: sudo npm install -g doctoc@2.2.0 diff --git a/Makefile b/Makefile index 996e400b2c..4e5ed975cf 100644 --- a/Makefile +++ b/Makefile @@ -55,19 +55,16 @@ help: # Virtual Environment ############################################################################### -VENV_DIR = $(CURDIR)/venv -PYTHON_VENV = $(VENV_DIR)/bin/python3 -PIP_VENV = $(VENV_DIR)/bin/pip3 -CODESPELL_VENV = $(VENV_DIR)/bin/codespell -VENV = $(VENV_DIR)/.venv_done +VENV = $(CURDIR)/venv +PYTHON_VENV = $(VENV)/bin/python3 +PIP_VENV = $(VENV)/bin/pip3 +CODESPELL_VENV = $(VENV)/bin/codespell # Make a virtual environment will all of the necessary dependencies. -# This is linked to a hidden file so make's dependency management works. $(VENV): requirements_preinstallation.txt @echo "Creating virtual environment" - @python3 -m venv $(VENV_DIR) + @python3 -m venv $(VENV) @$(PIP_VENV) install -r requirements_preinstallation.txt - @touch $(VENV) ############################################################################### # Distribution From fc22d815b6f74e256b394b62c5ae5a2b41c680e4 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Fri, 18 Oct 2024 19:26:52 -0500 Subject: [PATCH 14/25] Comment out caching --- .circleci/config.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index d0b06d3230..1f3b9ae0f7 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -186,9 +186,9 @@ jobs: - image: cimg/python:3.12-node working_directory: ~/specs-repo steps: - - restore_cache: - key: v3-specs-repo-{{ .Branch }}-{{ .Revision }} - - restore_pyspec_cached_venv + #- restore_cache: + # key: v3-specs-repo-{{ .Branch }}-{{ .Revision }} + #- restore_pyspec_cached_venv - run: name: Install doctoc command: sudo npm install -g doctoc@2.2.0 From 0a22b757df95ed7cd60ed6f95863a1fb71b2086c Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Fri, 18 Oct 2024 19:29:46 -0500 Subject: [PATCH 15/25] Restore some cache --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1f3b9ae0f7..fc8a038dbf 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -186,8 +186,8 @@ jobs: - image: cimg/python:3.12-node working_directory: ~/specs-repo steps: - #- restore_cache: - # key: v3-specs-repo-{{ .Branch }}-{{ .Revision }} + - restore_cache: + key: v3-specs-repo-{{ .Branch }}-{{ .Revision }} #- restore_pyspec_cached_venv - run: name: Install doctoc From 1e349304a7fd5832a950ca6019977bfb2c4eacb6 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Fri, 18 Oct 2024 19:38:14 -0500 Subject: [PATCH 16/25] Update cache venv name --- .circleci/config.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index fc8a038dbf..199a6e8306 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -35,13 +35,13 @@ commands: description: "Restore the cache with pyspec keys" steps: - restore_cached_venv: - venv_name: v26-pyspec + venv_name: v27-pyspec reqs_checksum: cache-{{ checksum "setup.py" }}-{{ checksum "requirements_preinstallation.txt" }} save_pyspec_cached_venv: description: Save a venv into a cache with pyspec keys" steps: - save_cached_venv: - venv_name: v26-pyspec + venv_name: v27-pyspec reqs_checksum: cache-{{ checksum "setup.py" }}-{{ checksum "requirements_preinstallation.txt" }} venv_path: ./venv jobs: @@ -188,7 +188,7 @@ jobs: steps: - restore_cache: key: v3-specs-repo-{{ .Branch }}-{{ .Revision }} - #- restore_pyspec_cached_venv + - restore_pyspec_cached_venv - run: name: Install doctoc command: sudo npm install -g doctoc@2.2.0 From c01392cf1a083693c24e42ae7f58dd9f74dca55d Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Fri, 18 Oct 2024 19:43:31 -0500 Subject: [PATCH 17/25] Use same image for all tasks --- .circleci/config.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 199a6e8306..0fa03a1335 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -47,7 +47,7 @@ commands: jobs: checkout_specs: docker: - - image: cimg/python:3.12.4 + - image: cimg/python:3.12-node working_directory: ~/specs-repo steps: # Restore git repo at point close to target branch/revision, to speed up checkout @@ -67,7 +67,7 @@ jobs: - ~/specs-repo install_pyspec_test: docker: - - image: cimg/python:3.12.4 + - image: cimg/python:3.12-node working_directory: ~/specs-repo steps: - restore_cache: @@ -79,7 +79,7 @@ jobs: - save_pyspec_cached_venv test-phase0: docker: - - image: cimg/python:3.12.4 + - image: cimg/python:3.12-node working_directory: ~/specs-repo steps: - restore_cache: @@ -92,7 +92,7 @@ jobs: path: tests/core/pyspec/test-reports test-altair: docker: - - image: cimg/python:3.12.4 + - image: cimg/python:3.12-node working_directory: ~/specs-repo steps: - restore_cache: @@ -105,7 +105,7 @@ jobs: path: tests/core/pyspec/test-reports test-bellatrix: docker: - - image: cimg/python:3.12.4 + - image: cimg/python:3.12-node working_directory: ~/specs-repo steps: - restore_cache: @@ -118,7 +118,7 @@ jobs: path: tests/core/pyspec/test-reports test-capella: docker: - - image: cimg/python:3.12.4 + - image: cimg/python:3.12-node working_directory: ~/specs-repo steps: - restore_cache: @@ -131,7 +131,7 @@ jobs: path: tests/core/pyspec/test-reports test-deneb: docker: - - image: cimg/python:3.12.4 + - image: cimg/python:3.12-node working_directory: ~/specs-repo steps: - restore_cache: @@ -144,7 +144,7 @@ jobs: path: tests/core/pyspec/test-reports test-electra: docker: - - image: cimg/python:3.12.4 + - image: cimg/python:3.12-node working_directory: ~/specs-repo steps: - restore_cache: @@ -157,7 +157,7 @@ jobs: path: tests/core/pyspec/test-reports test-whisk: docker: - - image: cimg/python:3.12.4 + - image: cimg/python:3.12-node working_directory: ~/specs-repo steps: - restore_cache: @@ -170,7 +170,7 @@ jobs: path: tests/core/pyspec/test-reports test-eip7594: docker: - - image: cimg/python:3.12.4 + - image: cimg/python:3.12-node working_directory: ~/specs-repo steps: - restore_cache: From f7a860b5e68fed41440b2ac275f34d496fab637d Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Fri, 18 Oct 2024 19:48:14 -0500 Subject: [PATCH 18/25] Update version number --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 0fa03a1335..1ff68a8965 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -35,13 +35,13 @@ commands: description: "Restore the cache with pyspec keys" steps: - restore_cached_venv: - venv_name: v27-pyspec + venv_name: v28-pyspec reqs_checksum: cache-{{ checksum "setup.py" }}-{{ checksum "requirements_preinstallation.txt" }} save_pyspec_cached_venv: description: Save a venv into a cache with pyspec keys" steps: - save_cached_venv: - venv_name: v27-pyspec + venv_name: v28-pyspec reqs_checksum: cache-{{ checksum "setup.py" }}-{{ checksum "requirements_preinstallation.txt" }} venv_path: ./venv jobs: From 2e5cdfdc9d8a6d7d1c0ceab8121118d360e13248 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Sat, 19 Oct 2024 09:39:53 -0500 Subject: [PATCH 19/25] Base eth2spec rule on file in venv --- .circleci/config.yml | 4 ++-- Makefile | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1ff68a8965..f09e77ab37 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -35,13 +35,13 @@ commands: description: "Restore the cache with pyspec keys" steps: - restore_cached_venv: - venv_name: v28-pyspec + venv_name: v29-pyspec reqs_checksum: cache-{{ checksum "setup.py" }}-{{ checksum "requirements_preinstallation.txt" }} save_pyspec_cached_venv: description: Save a venv into a cache with pyspec keys" steps: - save_cached_venv: - venv_name: v28-pyspec + venv_name: v29-pyspec reqs_checksum: cache-{{ checksum "setup.py" }}-{{ checksum "requirements_preinstallation.txt" }} venv_path: ./venv jobs: diff --git a/Makefile b/Makefile index 4e5ed975cf..b4f61cad33 100644 --- a/Makefile +++ b/Makefile @@ -55,7 +55,7 @@ help: # Virtual Environment ############################################################################### -VENV = $(CURDIR)/venv +VENV = venv PYTHON_VENV = $(VENV)/bin/python3 PIP_VENV = $(VENV)/bin/pip3 CODESPELL_VENV = $(VENV)/bin/codespell @@ -89,12 +89,12 @@ dist_upload: $(VENV) TEST_LIBS_DIR = $(CURDIR)/tests/core PY_SPEC_DIR = $(TEST_LIBS_DIR)/pyspec -ETH2SPEC = $(CURDIR)/.eth2spec +SITE_PACKAGES := $(wildcard $(VENV)/lib/python*/site-packages) +ETH2SPEC := $(SITE_PACKAGES)/eth2spec # Install the eth2spec package. $(ETH2SPEC): $(VENV) @$(PIP_VENV) install .[docs,lint,test,generator] - @touch $(ETH2SPEC) # Force rebuild/install the eth2spec package. eth2spec: From f7cf6676d11b772c6941c06837adf163214d1263 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Sat, 19 Oct 2024 09:55:10 -0500 Subject: [PATCH 20/25] Set venv as an order-only prereq --- Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b4f61cad33..7ec07e7179 100644 --- a/Makefile +++ b/Makefile @@ -93,7 +93,9 @@ SITE_PACKAGES := $(wildcard $(VENV)/lib/python*/site-packages) ETH2SPEC := $(SITE_PACKAGES)/eth2spec # Install the eth2spec package. -$(ETH2SPEC): $(VENV) +# The pipe indicates that venv is an order-only prerequisite. +# When restoring venv cache, its timestamp is newer than eth2spec. +$(ETH2SPEC): | $(VENV) @$(PIP_VENV) install .[docs,lint,test,generator] # Force rebuild/install the eth2spec package. From 64f29e3a467f5c160aae75731a5d2a2ce7f3afc7 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Sat, 19 Oct 2024 10:18:06 -0500 Subject: [PATCH 21/25] Split linter config into 3 parts --- Makefile | 27 +++++++++++++++------------ flake8.ini | 3 +++ linter.ini | 18 ------------------ mypy.ini | 9 +++++++++ pylint.ini | 3 +++ 5 files changed, 30 insertions(+), 30 deletions(-) create mode 100644 flake8.ini delete mode 100644 linter.ini create mode 100644 mypy.ini create mode 100644 pylint.ini diff --git a/Makefile b/Makefile index 7ec07e7179..986542a36e 100644 --- a/Makefile +++ b/Makefile @@ -88,7 +88,7 @@ dist_upload: $(VENV) ############################################################################### TEST_LIBS_DIR = $(CURDIR)/tests/core -PY_SPEC_DIR = $(TEST_LIBS_DIR)/pyspec +PYSPEC_DIR = $(TEST_LIBS_DIR)/pyspec SITE_PACKAGES := $(wildcard $(VENV)/lib/python*/site-packages) ETH2SPEC := $(SITE_PACKAGES)/eth2spec @@ -111,7 +111,7 @@ pyspec: $(VENV) setup.py # Testing ############################################################################### -TEST_REPORT_DIR = $(PY_SPEC_DIR)/test-reports +TEST_REPORT_DIR = $(PYSPEC_DIR)/test-reports # Run pyspec tests. # To run a specific test, append k=, eg: @@ -137,14 +137,14 @@ test: $(ETH2SPEC) pyspec $(PRESET) \ $(BLS) \ --junitxml=$(TEST_REPORT_DIR)/test_results.xml \ - $(PY_SPEC_DIR)/eth2spec + $(PYSPEC_DIR)/eth2spec ############################################################################### # Coverage ############################################################################### TEST_PRESET_TYPE ?= minimal -COV_HTML_OUT=$(PY_SPEC_DIR)/.htmlcov +COV_HTML_OUT=$(PYSPEC_DIR)/.htmlcov COV_INDEX_FILE=$(COV_HTML_OUT)/index.html COVERAGE_SCOPE := $(foreach S,$(ALL_EXECUTABLE_SPEC_NAMES), --cov=eth2spec.$S.$(TEST_PRESET_TYPE)) @@ -160,7 +160,7 @@ _test_with_coverage: $(ETH2SPEC) pyspec $(COVERAGE_SCOPE) \ --cov-report="html:$(COV_HTML_OUT)" \ --cov-branch \ - $(PY_SPEC_DIR)/eth2spec + $(PYSPEC_DIR)/eth2spec # Run tests with coverage then open the coverage report. # See `make test` for a list of options. @@ -195,8 +195,11 @@ serve_docs: _copy_docs # Checks ############################################################################### -LINTER_CONFIG_FILE = $(CURDIR)/linter.ini -PYLINT_SCOPE := $(foreach S,$(ALL_EXECUTABLE_SPEC_NAMES), $(PY_SPEC_DIR)/eth2spec/$S) +FLAKE8_CONFIG = $(CURDIR)/flake8.ini +MYPY_CONFIG = $(CURDIR)/mypy.ini +PYLINT_CONFIG = $(CURDIR)/pylint.ini + +PYLINT_SCOPE := $(foreach S,$(ALL_EXECUTABLE_SPEC_NAMES), $(PYSPEC_DIR)/eth2spec/$S) MYPY_SCOPE := $(foreach S,$(ALL_EXECUTABLE_SPEC_NAMES), -p eth2spec.$S) TEST_GENERATORS_DIR = ./tests/generators MARKDOWN_FILES = $(wildcard $(SPEC_DIR)/*/*.md) \ @@ -223,11 +226,11 @@ check_toc: $(MARKDOWN_FILES:=.toc) # Check for mistakes. lint: $(ETH2SPEC) pyspec check_toc - @$(CODESPELL_VENV) . --skip "./.git,./venv,$(PY_SPEC_DIR)/.mypy_cache" -I .codespell-whitelist - @$(PYTHON_VENV) -m flake8 --config $(LINTER_CONFIG_FILE) $(PY_SPEC_DIR)/eth2spec - @$(PYTHON_VENV) -m flake8 --config $(LINTER_CONFIG_FILE) $(TEST_GENERATORS_DIR) - @$(PYTHON_VENV) -m pylint --rcfile $(LINTER_CONFIG_FILE) $(PYLINT_SCOPE) - @$(PYTHON_VENV) -m mypy --config-file $(LINTER_CONFIG_FILE) $(MYPY_SCOPE) + @$(CODESPELL_VENV) . --skip "./.git,$(VENV),$(PYSPEC_DIR)/.mypy_cache" -I .codespell-whitelist + @$(PYTHON_VENV) -m flake8 --config $(FLAKE8_CONFIG) $(PYSPEC_DIR)/eth2spec + @$(PYTHON_VENV) -m flake8 --config $(FLAKE8_CONFIG) $(TEST_GENERATORS_DIR) + @$(PYTHON_VENV) -m pylint --rcfile $(PYLINT_CONFIG) $(PYLINT_SCOPE) + @$(PYTHON_VENV) -m mypy --config-file $(MYPY_CONFIG) $(MYPY_SCOPE) ############################################################################### # Generators diff --git a/flake8.ini b/flake8.ini new file mode 100644 index 0000000000..f94b2ad47a --- /dev/null +++ b/flake8.ini @@ -0,0 +1,3 @@ +[flake8] +ignore = E252,W504,W503 +max-line-length = 120 \ No newline at end of file diff --git a/linter.ini b/linter.ini deleted file mode 100644 index 52a3aec0e0..0000000000 --- a/linter.ini +++ /dev/null @@ -1,18 +0,0 @@ -[flake8] -ignore = E252,W504,W503 -max-line-length = 120 - -[mypy] -disallow_incomplete_defs = True -disallow_untyped_defs = True - -warn_unused_ignores = True -warn_unused_configs = True -warn_redundant_casts = True - -ignore_missing_imports = True - -# pylint -[MESSAGES CONTROL] -disable = all -enable = unused-argument diff --git a/mypy.ini b/mypy.ini new file mode 100644 index 0000000000..e1b43dabab --- /dev/null +++ b/mypy.ini @@ -0,0 +1,9 @@ +[mypy] +disallow_incomplete_defs = True +disallow_untyped_defs = True + +warn_unused_ignores = True +warn_unused_configs = True +warn_redundant_casts = True + +ignore_missing_imports = True \ No newline at end of file diff --git a/pylint.ini b/pylint.ini new file mode 100644 index 0000000000..a8242683a3 --- /dev/null +++ b/pylint.ini @@ -0,0 +1,3 @@ +[MESSAGES CONTROL] +disable = all +enable = unused-argument \ No newline at end of file From c269847ee7f0597cbf9073cbf369bd0f774ea355 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Sat, 19 Oct 2024 10:32:25 -0500 Subject: [PATCH 22/25] Mark setup.py as a dep of eth2spec --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 986542a36e..072a7def9d 100644 --- a/Makefile +++ b/Makefile @@ -95,7 +95,7 @@ ETH2SPEC := $(SITE_PACKAGES)/eth2spec # Install the eth2spec package. # The pipe indicates that venv is an order-only prerequisite. # When restoring venv cache, its timestamp is newer than eth2spec. -$(ETH2SPEC): | $(VENV) +$(ETH2SPEC): setup.py | $(VENV) @$(PIP_VENV) install .[docs,lint,test,generator] # Force rebuild/install the eth2spec package. From acfd9b9d2a567fb3ce87d416cd4619fec28bf879 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Wed, 6 Nov 2024 09:04:11 -0600 Subject: [PATCH 23/25] Move kzg_setups rule outside of gen_* --- Makefile | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index f85ce2eb66..5ba78c0834 100644 --- a/Makefile +++ b/Makefile @@ -24,6 +24,7 @@ ALL_EXECUTABLE_SPEC_NAMES = \ gen_all \ gen_list \ help \ + kzg_setups \ lint \ pyspec \ serve_docs \ @@ -42,10 +43,11 @@ help: @echo "make $(BOLD)clean$(NORM) -- delete all untracked files" @echo "make $(BOLD)coverage$(NORM) -- run pyspec tests with coverage" @echo "make $(BOLD)detect_errors$(NORM) -- detect generator errors" + @echo "make $(BOLD)eth2spec$(NORM) -- force rebuild eth2spec package" @echo "make $(BOLD)gen_$(NORM) -- run a single generator" @echo "make $(BOLD)gen_all$(NORM) -- run all generators" @echo "make $(BOLD)gen_list$(NORM) -- list all generator targets" - @echo "make $(BOLD)eth2spec$(NORM) -- force rebuild eth2spec package" + @echo "make $(BOLD)kzg_setups$(NORM) -- generate trusted setups" @echo "make $(BOLD)lint$(NORM) -- run the linters" @echo "make $(BOLD)pyspec$(NORM) -- generate python specifications" @echo "make $(BOLD)serve_docs$(NORM) -- start a local docs web server" @@ -241,7 +243,7 @@ GENERATOR_DIR = $(CURDIR)/tests/generators SCRIPTS_DIR = $(CURDIR)/scripts GENERATOR_ERROR_LOG_FILE = $(TEST_VECTOR_DIR)/testgen_error_log.txt GENERATORS = $(sort $(dir $(wildcard $(GENERATOR_DIR)/*/.))) -GENERATOR_TARGETS = $(patsubst $(GENERATOR_DIR)/%/, gen_%, $(GENERATORS)) gen_kzg_setups +GENERATOR_TARGETS = $(patsubst $(GENERATOR_DIR)/%/, gen_%, $(GENERATORS)) # List available generators. gen_list: @@ -259,16 +261,6 @@ gen_%: $(ETH2SPEC) pyspec --output $(TEST_VECTOR_DIR) \ $(MAYBE_MODCHECK) -# Generate KZG setups. -gen_kzg_setups: $(ETH2SPEC) - @for preset in minimal mainnet; do \ - $(PYTHON_VENV) $(SCRIPTS_DIR)/gen_kzg_trusted_setups.py \ - --secret=1337 \ - --g1-length=4096 \ - --g2-length=65 \ - --output-dir $(CURDIR)/presets/$$preset/trusted_setups; \ - done - # Run all generators then check for errors. gen_all: $(GENERATOR_TARGETS) detect_errors @@ -281,6 +273,16 @@ detect_errors: $(TEST_VECTOR_DIR) echo "[PASSED] error log file does not exist"; \ fi +# Generate KZG trusted setups for testing. +kzg_setups: $(ETH2SPEC) + @for preset in minimal mainnet; do \ + $(PYTHON_VENV) $(SCRIPTS_DIR)/gen_kzg_trusted_setups.py \ + --secret=1337 \ + --g1-length=4096 \ + --g2-length=65 \ + --output-dir $(CURDIR)/presets/$$preset/trusted_setups; \ + done + ############################################################################### # Cleaning ############################################################################### From 915e9e00d36afaf65e78840f3870bfeb1657fb09 Mon Sep 17 00:00:00 2001 From: Justin Traglia <95511699+jtraglia@users.noreply.github.com> Date: Thu, 12 Dec 2024 13:44:08 -0600 Subject: [PATCH 24/25] Update cached venv version --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 2996250352..1de55179d4 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -35,13 +35,13 @@ commands: description: "Restore the cache with pyspec keys" steps: - restore_cached_venv: - venv_name: v29-pyspec + venv_name: v30-pyspec reqs_checksum: cache-{{ checksum "setup.py" }}-{{ checksum "requirements_preinstallation.txt" }} save_pyspec_cached_venv: description: Save a venv into a cache with pyspec keys" steps: - save_cached_venv: - venv_name: v29-pyspec + venv_name: v30-pyspec reqs_checksum: cache-{{ checksum "setup.py" }}-{{ checksum "requirements_preinstallation.txt" }} venv_path: ./venv jobs: From 46f595da0caebed7f74315d4ff61b3ec3a98f48a Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Thu, 12 Dec 2024 14:02:46 -0600 Subject: [PATCH 25/25] Remove distribution rules --- Makefile | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/Makefile b/Makefile index 105112ee87..a3a3e24288 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ ALL_EXECUTABLE_SPEC_NAMES = \ capella \ deneb \ electra \ - fulu \ + fulu \ whisk \ eip6800 \ eip7732 @@ -68,23 +68,6 @@ $(VENV): requirements_preinstallation.txt @python3 -m venv $(VENV) @$(PIP_VENV) install -r requirements_preinstallation.txt -############################################################################### -# Distribution -############################################################################### - -# The pyspec is rebuilt to enforce the /specs being part of eth2specs source -# distribution. It could be forgotten otherwise. -dist_build: $(VENV) pyspec - @$(PYTHON_VENV) setup.py sdist bdist_wheel - -# Check the distribution for issues. -dist_check: $(VENV) - @$(PYTHON_VENV) -m twine check dist/* - -# Upload the distribution to PyPI. -dist_upload: $(VENV) - @$(PYTHON_VENV) -m twine upload dist/* - ############################################################################### # Specification ###############################################################################