diff --git a/.circleci/config.yml b/.circleci/config.yml index 38bd6f422d..ba9e79b98b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -35,14 +35,14 @@ commands: description: "Restore the cache with pyspec keys" steps: - restore_cached_venv: - venv_name: v32-pyspec - reqs_checksum: cache-{{ checksum "setup.py" }}-{{ checksum "requirements_preinstallation.txt" }} + venv_name: v33-pyspec + reqs_checksum: cache-{{ checksum "setup.py" }}-{{ checksum "pyproject.toml" }} save_pyspec_cached_venv: description: Save a venv into a cache with pyspec keys" steps: - save_cached_venv: - venv_name: v32-pyspec - reqs_checksum: cache-{{ checksum "setup.py" }}-{{ checksum "requirements_preinstallation.txt" }} + venv_name: v33-pyspec + reqs_checksum: cache-{{ checksum "setup.py" }}-{{ checksum "pyproject.toml" }} venv_path: ./venv jobs: checkout_specs: @@ -75,7 +75,7 @@ jobs: - restore_pyspec_cached_venv - run: name: Install pyspec requirements - command: make eth2spec + command: make pyspec - save_pyspec_cached_venv test-phase0: docker: diff --git a/Makefile b/Makefile index 09e914c3ca..dc9406d9f6 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,6 @@ ALL_EXECUTABLE_SPEC_NAMES = \ clean \ coverage \ detect_errors \ - eth2spec \ gen_all \ gen_list \ help \ @@ -41,7 +40,6 @@ 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" @@ -60,11 +58,11 @@ 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. -$(VENV): requirements_preinstallation.txt +# Make a virtual environment. +$(VENV): @echo "Creating virtual environment" @python3 -m venv $(VENV) - @$(PIP_VENV) install -r requirements_preinstallation.txt + @$(PIP_VENV) install --quiet uv==0.5.24 ############################################################################### # Specification @@ -72,21 +70,11 @@ $(VENV): requirements_preinstallation.txt TEST_LIBS_DIR = $(CURDIR)/tests/core PYSPEC_DIR = $(TEST_LIBS_DIR)/pyspec -SITE_PACKAGES := $(wildcard $(VENV)/lib/python*/site-packages) -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): setup.py | $(VENV) - @$(PIP_VENV) install .[docs,lint,test,generator] - -# Force rebuild/install the eth2spec package. -eth2spec: - @$(MAKE) --always-make $(ETH2SPEC) # Create the pyspec for all phases. -pyspec: $(VENV) setup.py +pyspec: $(VENV) setup.py pyproject.toml + @echo "Building eth2spec" + @$(PYTHON_VENV) -m uv pip install .[docs,lint,test,generator] @echo "Building all pyspecs" @$(PYTHON_VENV) setup.py pyspecdev @@ -113,7 +101,7 @@ 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 +test: pyspec @mkdir -p $(TEST_REPORT_DIR) @$(PYTHON_VENV) -m pytest \ -n auto \ @@ -137,7 +125,7 @@ COVERAGE_SCOPE := $(foreach S,$(ALL_EXECUTABLE_SPEC_NAMES), --cov=eth2spec.$S.$( # 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 +_test_with_coverage: pyspec @$(PYTHON_VENV) -m pytest \ -n auto \ $(MAYBE_TEST) \ @@ -211,7 +199,7 @@ _check_toc: $(MARKDOWN_FILES:=.toc) @[ "$$(find . -name '*.md.tmp' -print -quit)" ] && exit 1 || exit 0 # Check for mistakes. -lint: $(ETH2SPEC) pyspec _check_toc +lint: pyspec _check_toc @$(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) @@ -236,11 +224,11 @@ gen_list: done # Run one generator. -# This will forcibly rebuild eth2spec just in case. +# This will forcibly rebuild pyspec just in case. # To check modules for a generator, append modcheck=true, eg: # make gen_genesis modcheck=true gen_%: MAYBE_MODCHECK := $(if $(filter true,$(modcheck)),--modcheck) -gen_%: eth2spec +gen_%: pyspec @mkdir -p $(TEST_VECTOR_DIR) @$(PYTHON_VENV) $(GENERATOR_DIR)/$*/main.py \ --output $(TEST_VECTOR_DIR) \ @@ -260,7 +248,7 @@ detect_errors: $(TEST_VECTOR_DIR) fi # Generate KZG trusted setups for testing. -kzg_setups: $(ETH2SPEC) +kzg_setups: pyspec @for preset in minimal mainnet; do \ $(PYTHON_VENV) $(SCRIPTS_DIR)/gen_kzg_trusted_setups.py \ --secret=1337 \ diff --git a/README.md b/README.md index e58927ac9e..5749a89506 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,6 @@ Documentation on the different components used during spec writing can be found Conformance tests built from the executable python spec are available in the [Ethereum Proof-of-Stake Consensus Spec Tests](https://github.com/ethereum/consensus-spec-tests) repo. Compressed tarballs are available in [releases](https://github.com/ethereum/consensus-spec-tests/releases). - ## Installation and Usage The consensus-specs repo can be used by running the tests locally or inside a docker container. diff --git a/configs/mainnet.yaml b/configs/mainnet.yaml index e54db49661..7f96d087c9 100644 --- a/configs/mainnet.yaml +++ b/configs/mainnet.yaml @@ -171,8 +171,7 @@ MAX_REQUEST_DATA_COLUMN_SIDECARS: 16384 SAMPLES_PER_SLOT: 8 CUSTODY_REQUIREMENT: 4 MAX_BLOBS_PER_BLOCK_FULU: 12 -# `MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK_FULU` -MAX_REQUEST_BLOB_SIDECARS_FULU: 1536 +MIN_EPOCHS_FOR_DATA_COLUMN_SIDECARS_REQUESTS: 4096 # Whisk # `Epoch(2**8)` diff --git a/configs/minimal.yaml b/configs/minimal.yaml index a15314bb1f..559e04d70e 100644 --- a/configs/minimal.yaml +++ b/configs/minimal.yaml @@ -172,8 +172,7 @@ MAX_REQUEST_DATA_COLUMN_SIDECARS: 16384 SAMPLES_PER_SLOT: 8 CUSTODY_REQUIREMENT: 4 MAX_BLOBS_PER_BLOCK_FULU: 12 -# `MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK_FULU` -MAX_REQUEST_BLOB_SIDECARS_FULU: 1536 +MIN_EPOCHS_FOR_DATA_COLUMN_SIDECARS_REQUESTS: 4096 # Whisk WHISK_EPOCHS_PER_SHUFFLING_PHASE: 4 diff --git a/docker/README.md b/docker/README.md index 34bdd94c51..93a24b4e08 100644 --- a/docker/README.md +++ b/docker/README.md @@ -1,10 +1,11 @@ ## Docker related information This dockerfile sets up the dependencies required to run consensus-spec tests. The docker image can be locally built with: -- `docker build ./ -t $IMAGE_NAME -f ./docker/Dockerfile` +- `docker build ./ -t $IMAGE_NAME -f ./docker/Dockerfile` 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 test` will run the make test command inside the docker container @@ -13,6 +14,7 @@ Ideally manual running of docker containers is for advanced users, we recommend The `scripts/build_run_docker_tests.sh` script will cover most use cases. The script allows the user to configure the fork(altair/bellatrix/capella..), `$IMAGE_NAME` (specifies the container to use), preset type (mainnet/minimal), and test all forks flags. Ideally, this is the main way that users interact with the spec tests instead of running it locally with varying versions of dependencies. E.g: + - `./build_run_docker_tests.sh --p mainnet` will run the mainnet preset tests - `./build_run_docker_tests.sh --a` will run all the tests across all the forks - `./build_run_docker_tests.sh --f deneb` will only run deneb tests diff --git a/docs/docs/new-feature.md b/docs/docs/new-feature.md index 78fd1357fc..4813c8d3fd 100644 --- a/docs/docs/new-feature.md +++ b/docs/docs/new-feature.md @@ -1,8 +1,9 @@ # How to add a new feature proposal in consensus-specs +## Table of contents + -## Table of Contents - [A. Make it executable for linter checks](#a-make-it-executable-for-linter-checks) - [1. Create a folder under `./specs/_features`](#1-create-a-folder-under-specs_features) @@ -23,7 +24,6 @@ - ## A. Make it executable for linter checks ### 1. Create a folder under `./specs/_features` @@ -35,6 +35,7 @@ For example, if it's an `EIP-9999` CL spec, you can create a `./specs/_features/ For example, if the latest fork is Capella, use `./specs/capella` content as your "previous fork". ### 3. Write down your proposed `beacon-chain.md` change + - You can either use [Beacon Chain Spec Template](./templates/beacon-chain-template.md), or make a copy of the latest fork content and then edit it. - Tips: - We use [`doctoc`](https://www.npmjs.com/package/doctoc) tool to generate the table of content. @@ -50,8 +51,11 @@ For example, if the latest fork is Capella, use `./specs/capella` content as you - Use simple Python rather than the fancy Python dark magic. ### 4. Add `fork.md` + You can refer to the previous fork's `fork.md` file. + ### 5. Make it executable + - Update Pyspec [`constants.py`](https://github.com/ethereum/consensus-specs/blob/dev/tests/core/pyspec/eth2spec/test/helpers/constants.py) with the new feature name. - Update helpers for [`setup.py`](https://github.com/ethereum/consensus-specs/blob/dev/setup.py) for building the spec: - Update [`pysetup/constants.py`](https://github.com/ethereum/consensus-specs/blob/dev/pysetup/constants.py) with the new feature name as Pyspec `constants.py` defined. @@ -63,17 +67,21 @@ You can refer to the previous fork's `fork.md` file. ## B: Make it executable for pytest and test generator ### 1. [Optional] Add `light-client/*` docs if you updated the content of `BeaconBlock` + - You can refer to the previous fork's `light-client/*` file. - Add the path of the new markdown files in [`pysetup/md_doc_paths.py`](https://github.com/ethereum/consensus-specs/blob/dev/pysetup/md_doc_paths.py)'s `get_md_doc_paths` function. ### 2. Add the mainnet and minimal presets and update the configs + - Add presets: `presets/mainnet/.yaml` and `presets/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) + - [Optional] Add `with__and_later` decorator for writing pytest cases. e.g., `with_capella_and_later`. ### 4. Update [`constants.py`](https://github.com/ethereum/consensus-specs/blob/dev/tests/core/pyspec/eth2spec/test/helpers/constants.py) + - Add `` to `ALL_PHASES` and `TESTGEN_FORKS` ### 5. Update [`genesis.py`](https://github.com/ethereum/consensus-specs/blob/dev/tests/core/pyspec/eth2spec/test/helpers/genesis.py): @@ -94,6 +102,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. ### 6. Update CI configurations + - 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 [CircleCI config](https://github.com/ethereum/consensus-specs/blob/dev/.circleci/config.yml) @@ -102,7 +111,9 @@ def create_genesis_state(spec, validator_balances, activation_threshold): ## Others ### Bonus + - Add `validator.md` if honest validator behavior changes with the new feature. ### Need help? + You can tag spec elves for cleaning up your PR. 🧚 diff --git a/docs/docs/release.md b/docs/docs/release.md new file mode 100644 index 0000000000..d0d163b79d --- /dev/null +++ b/docs/docs/release.md @@ -0,0 +1,331 @@ +# Release Procedure + +## Table of contents + + + + + +- [Introduction](#introduction) +- [Open a Release Pull Request](#open-a-release-pull-request) +- [Bump the Version](#bump-the-version) +- [Pick a Release Name](#pick-a-release-name) +- [Generate Reference Tests](#generate-reference-tests) + - [Install Git Large File Storage](#install-git-large-file-storage) + - [Prepare Tests Repository](#prepare-tests-repository) + - [Commit Reference Tests](#commit-reference-tests) + - [Bundle Reference Tests](#bundle-reference-tests) +- [Merge the Release Pull Request](#merge-the-release-pull-request) +- [Create Tests Release](#create-tests-release) +- [Create Specs Release](#create-specs-release) +- [Click the Release Buttons](#click-the-release-buttons) +- [Make an Announcement](#make-an-announcement) + + + + +## Introduction + +This document describes the necessary steps to produce a consensus-specs release. + +## Open a Release Pull Request + +> [!NOTE] +> Try to do this at least a few days prior to the release. + +First, create a PR which merges `dev` into `master`. + +> [!TIP] +> Click on the following link to draft a PR: +> * https://github.com/ethereum/consensus-specs/compare/dev...master?expand=1 + +Title this PR "Release <version>" (_e.g._, "Release v1.5.0-alpha.10"). + +In the PR's description, provide a list of items that must be done. At the bottom, list unmerged PRs +which are to be included in the release; this signals to other maintainers and developers that they +should review these PRs soon. + +```markdown +- [ ] testgen +- [ ] version bump +- [ ] #1234 +- [ ] #2345 +- [ ] #3456 +``` + +## Bump the Version + +Next, update the `VERSION.txt` file which contains the eth2spec version. + +> [!TIP] +> Click on the following link to open the GitHub editor for this file: +> * https://github.com/ethereum/consensus-specs/edit/dev/tests/core/pyspec/eth2spec/VERSION.txt + +Next, change the version to the appropriate value and click the "Commit changes..." button. + +For the commit message, put "Bump version to <version>" (_e.g._, "Bump version to 1.5.0-alpha.10"). + +Next, click the "Propose changes" button and proceed to make the PR. + +## Pick a Release Name + +Generally, names are based on some theme. For example, for Electra, releases are named after +Electric-type Pokemon. + +> [!NOTE] +> Please ensure that the name you choose does not have an unwanted meaning in other languages; +use [WordSafety.com](http://wordsafety.com) to check this. + +## Generate Reference Tests + +### Install Git Large File Storage + +The consensus-spec-tests repository uses [Git LFS](https://git-lfs.com) because it contains many +large files. Attempt to install LFS support with the following command. If it does not work, please +refer to the installation directions on their website. + +```bash +git lfs install +``` + +### Prepare Tests Repository + +Next, clone the consensus-spec-tests repository. + +> [!NOTE] +> Only the single latest commit is needed to make the release. Use `--depth=1` to do this. Please +> note that even this may take some time to checkout, as the combined size of the test vectors is +> multiple gigabytes. + +```bash +git clone https://github.com/ethereum/consensus-spec-tests.git --depth=1 +cd consensus-spec-tests +``` + +Next, remove directories which will be overwritten. + +```bash +rm -rf configs presets tests +``` + +### Commit Reference Tests + +Next, change directory to outside of the tests repository. + +```bash +cd .. +``` + +Next, clone the consensus-specs repository. + +```bash +git clone https://github.com/ethereum/consensus-specs.git +cd consensus-specs +``` + +Next, copy the presets and configuration files to the tests repository. + +```bash +cp -r presets ../consensus-spec-tests +cp -r configs ../consensus-spec-tests +``` + +Next, use `make gen_all` to generate all the reference tests. The following command will run all +generators in parallel for maximum speed. The console output is saved to a file so we can check for +errors afterwards. + +> [!TIP] +> Instead of this, another option is to use the test vectors that are automatically generated each +> night. To download these files, click the following link, then click the latest action run, and +> then download all of the artifacts. Please note, if there has been a change to the dev branch +> after the test vectors were generated, you can manually trigger the action with the "Run workflow" +> button. +> +> * https://github.com/ethereum/consensus-specs/actions/workflows/generate_vectors.yml +> +> After downloading these artifacts, move them to the `consensus-spec-tests` directory. Then unzip +> each, then untar each of the `*.tar.gz` files. Use `unzip .zip` and `tar -xvf .tar.gz` +> to do this. Note that the "Bundle Reference Tests" section can be skipped if this route is taken. + +```bash +make --jobs gen_all 2>&1 | tee ../consensustestgen.log +``` + +Next, check for errors by searching for "ERROR" in test logfile. + +```bash +grep "ERROR" ../consensustestgen.log +``` + +> [!WARNING] +> If there is an error: (1) determine what the issue is, (2) create/merge a PR to fix the issue, and +> (3) restart the release process. + +Next, change directory to the consensus-spec-tests repository: + +```bash +cd ../consensus-spec-tests +``` + +Next, check that the differences look sane; that there are no unexpected changes. Sometimes there +are several hundred (if not more) changes per release so use your best judgement when reviewing. One +might ensure that there are no changes to old forks and double check a few reference tests to ensure +they were indeed modified in this release. + +```bash +git lfs status +``` + +Next, after reviewing the changes and are reasonably confident that they are okay, stage the +changes. + +```bash +git add . +``` + +Next, commit the changes. + +> [!IMPORTANT] +> Commits to consensus-spec-tests must be signed. Please refer to [Signing +> Commits](https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits) +> for instructions on setting this up. + +```bash +git commit --gpg-sign --message "release tests" +``` + +Finally, push the changes. + +```bash +git push origin master +``` + +### Bundle Reference Tests + +Next, delete all empty directories. + +```bash +find . -type d -empty -delete +``` + +Finally, tar each group of tests into separate tarballs. + +```bash +tar -czvf general.tar.gz tests/general +tar -czvf minimal.tar.gz tests/minimal +tar -czvf mainnet.tar.gz tests/mainnet +``` + +## Merge the Release Pull Request + +After successfully generating the test vectors, we have confidence that the release is fine. We can +now merge the release pull request which brings changes from the development branch into the master +branch. Releases are made from the master branch. + +## Create Tests Release + +First, begin to draft a new consensus-spec-tests release. + +> [!TIP] +> Click on the following link to draft a new release: +> * https://github.com/ethereum/consensus-spec-tests/releases/new + +Next, click the "Choose a tag" button to create a new tag. Type in the release version (_e.g._, +"v1.5.0-alpha.10") and click the "Create new tag: <version> on publish" button. + +Next, provide a title "Spec tests for <version>" (_e.g._, "Spec tests for v1.5.0-alpha.10"). + +Next, provide a description. Use the following template: + +```markdown +Spec tests for . + +Detailed changelog can be found in [ specs release](https://github.com/ethereum/consensus-specs/releases/tag/). +``` + +Next, upload the tarballs from the [Bundle Reference Tests]() section to the release. + +> [!NOTE] +> This is expected to take a while if your upload speed is below average. The tarballs are at +> least 1 gigabyte in total. There is a progress bar shown for each artifact. + +Next, if this is an alpha/beta release, please select the "Set as a pre-release" checkbox, otherwise +select the "Set as the latest release" checkbox. + +> [!IMPORTANT] +> Do no click the release button just yet. + +## Create Specs Release + +First, begin to draft a new consensus-specs release. + +> [!TIP] +> Click on the following link to draft a new release: +> * https://github.com/ethereum/consensus-specs/releases/new + +Next, click the "Choose a tag" button to create a new tag. Type in the release version (_e.g._, +"v1.5.0-alpha.10") and click the "Create new tag: <version> on publish" button. + +Next, change the target from `dev` to `master`. + +> [!IMPORTANT] +> Do not forget this to change the target branch. + +Next, provide a title "<release-name>" (_e.g._, "Bellibolt"). + +Next, provide a description. Use the following template: + +```markdown + -- -- + +_PR showing full diff can be found here: _ + +## + +* Add new feature #1234 +* Fix problem in old feature #2345 + +## + +* Fix bug related to feature #3456 + +## Testing, repo, etc + +* Add new test for feature #4567 +* Improve documentation #5678 +``` + +If this is an alpha/beta release, please select the "Set as a pre-release" checkbox, otherwise +select the "Set as the latest release" checkbox. + +> [!IMPORTANT] +> Do no click the release button just yet. + +## Click the Release Buttons + +1. First, click the release button for consensus-specs. + +2. Then, click the release button for consensus-spec-tests. + +> [!NOTE] +> It should be done in this order because the tests release references the specs release. Also, +> we wait to push these buttons at the same time so their time/date will be approximately the same. + +## Make an Announcement + +> [!IMPORTANT] +> In order to do this, you must be granted the appropriate access. + +Finally, make an announcement to the Eth R&D server on Discord. This should be posted in the +`#announcements` channel. This will notify client developers of the new release and they will begin +to incorporate the new reference tests into their client. + +Use the following template for your announcement: + +```markdown +Consensus layer specs -- -- released! + +https://github.com/ethereum/consensus-specs/releases/tag/ + +Test vectors: https://github.com/ethereum/consensus-spec-tests/releases/tag/ +``` \ No newline at end of file diff --git a/docs/docs/templates/beacon-chain-template.md b/docs/docs/templates/beacon-chain-template.md index 02e95d4c4f..e1c53a0511 100644 --- a/docs/docs/templates/beacon-chain-template.md +++ b/docs/docs/templates/beacon-chain-template.md @@ -3,6 +3,7 @@ # -- The Beacon Chain ## Table of contents + @@ -10,8 +11,6 @@ - - ## Introduction ## Notation @@ -28,7 +27,6 @@ ## Preset - ### [CATEGORY OF PRESETS] | Name | Value | @@ -64,5 +62,4 @@ class CONTAINER_NAME(Container): ### Epoch processing - ### Block processing diff --git a/fork_choice/safe-block.md b/fork_choice/safe-block.md index d4af9060d0..404c05f4cf 100644 --- a/fork_choice/safe-block.md +++ b/fork_choice/safe-block.md @@ -1,6 +1,7 @@ # Fork Choice -- Safe Block ## Table of contents + diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000000..d9485f2e8c --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,55 @@ +[build-system] +requires = [ + "marko==1.0.2", + "ruamel.yaml==0.17.21", + "setuptools==75.8.0", + "wheel==0.45.1", +] + +[project] +name = "eth2spec" +dynamic = ["version"] +authors = [{ name = "ethereum" }] +description = "Ethereum consensus layer specifications package" +readme = { file = "README.md", content-type = "text/markdown" } +requires-python = ">=3.9,<4.0" +dependencies = [ + "curdleproofs==0.1.2", + "eth-typing==3.5.2", + "eth-utils==2.3.2", + "lru-dict==1.2.0", + "marko==1.0.2", + "milagro_bls_binding==1.9.0", + "py_arkworks_bls12381==0.3.8", + "py_ecc==6.0.0", + "pycryptodome==3.21.0", + "remerkleable==0.1.28", + "ruamel.yaml==0.17.21", + "setuptools==75.8.0", + "trie==3.0.1", +] + +[project.optional-dependencies] +test = [ + "pytest-cov==6.0.0", + "pytest-xdist==3.6.1", + "pytest==8.3.4", +] +lint = [ + "codespell==2.4.0", + "flake8==5.0.4", + "mypy==0.981", + "pylint==3.3.1", +] +generator = [ + "filelock==3.17.0", + "pathos==0.3.0", + "pytest==8.3.4", + "python-snappy==0.7.3", +] +docs = [ + "mdx-truly-sane-lists==1.3", + "mkdocs-awesome-pages-plugin==2.8.0", + "mkdocs-material==9.1.5", + "mkdocs==1.4.2", +] diff --git a/setup.py b/setup.py index 55f1d0e344..8bfcbed222 100644 --- a/setup.py +++ b/setup.py @@ -1,74 +1,62 @@ -from setuptools import setup, find_packages, Command -from setuptools.command.build_py import build_py -from distutils import dir_util -from distutils.util import convert_path -from pathlib import Path +import ast +import copy +import json +import logging import os import string -from typing import Dict, List, Sequence, Optional, Tuple -import ast -import subprocess import sys -import copy +import warnings + from collections import OrderedDict -import json +from distutils import dir_util +from distutils.util import convert_path from functools import lru_cache +from marko.block import Heading, FencedCode, LinkRefDef, BlankLine +from marko.ext.gfm import gfm +from marko.ext.gfm.elements import Table +from marko.inline import CodeSpan +from pathlib import Path +from ruamel.yaml import YAML +from setuptools import setup, find_packages, Command +from setuptools.command.build_py import build_py +from typing import Dict, List, Sequence, Optional, Tuple + +pysetup_path = os.path.abspath(os.path.dirname(__file__)) +sys.path.insert(0, pysetup_path) from pysetup.constants import ( - # code names PHASE0, - # misc ETH2_SPEC_COMMENT_PREFIX, ) -from pysetup.spec_builders import spec_builders -from pysetup.typing import ( - BuildTarget, - ProtocolDefinition, - SpecObject, - VariableDefinition, -) from pysetup.helpers import ( combine_spec_objects, dependency_order_class_objects, objects_to_spec, parse_config_vars, ) -from pysetup.md_doc_paths import get_md_doc_paths +from pysetup.md_doc_paths import ( + get_md_doc_paths +) +from pysetup.spec_builders import ( + spec_builders +) +from pysetup.typing import ( + BuildTarget, + ProtocolDefinition, + SpecObject, + VariableDefinition, +) + # Ignore '1.5.0-alpha.*' to '1.5.0a*' messages. -import warnings warnings.filterwarnings('ignore', message='Normalizing .* to .*') # Ignore 'running' and 'creating' messages -import logging class PyspecFilter(logging.Filter): def filter(self, record): return not record.getMessage().startswith(('running ', 'creating ')) logging.getLogger().addFilter(PyspecFilter()) -# NOTE: have to programmatically include third-party dependencies in `setup.py`. -def installPackage(package: str): - subprocess.check_call([sys.executable, '-m', 'pip', 'install', package]) - -RUAMEL_YAML_VERSION = "ruamel.yaml==0.17.21" -try: - import ruamel.yaml -except ImportError: - installPackage(RUAMEL_YAML_VERSION) - -from ruamel.yaml import YAML - -MARKO_VERSION = "marko==1.0.2" -try: - import marko -except ImportError: - installPackage(MARKO_VERSION) - -from marko.block import Heading, FencedCode, LinkRefDef, BlankLine -from marko.inline import CodeSpan -from marko.ext.gfm import gfm -from marko.ext.gfm.elements import Table - @lru_cache(maxsize=None) def _get_name_from_heading(heading: Heading) -> Optional[str]: @@ -550,12 +538,9 @@ def run(self): spec_version = f.read().strip() setup( - name='eth2spec', version=spec_version, - description="Eth2 spec, provided as Python package for tooling and testing", long_description=readme, long_description_content_type="text/markdown", - author="ethereum", url="https://github.com/ethereum/consensus-specs", include_package_data=False, package_data={ @@ -575,25 +560,4 @@ def run(self): packages=find_packages(where='tests/core/pyspec') + ['configs', 'presets', 'specs', 'presets', 'sync'], py_modules=["eth2spec"], cmdclass=commands, - python_requires=">=3.9, <4", - extras_require={ - "test": ["pytest>=4.4", "pytest-cov", "pytest-xdist"], - "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"] - }, - install_requires=[ - "eth-utils>=2.0.0,<3", - "eth-typing>=3.2.0,<4.0.0", - "pycryptodome>=3.19.1", - "py_ecc==6.0.0", - "milagro_bls_binding==1.9.0", - "remerkleable==0.1.28", - "trie>=3,<4", - RUAMEL_YAML_VERSION, - "lru-dict==1.2.0", - MARKO_VERSION, - "py_arkworks_bls12381==0.3.8", - "curdleproofs==0.1.2", - ] ) diff --git a/solidity_deposit_contract/Makefile b/solidity_deposit_contract/Makefile index a353d931bb..60d45ede49 100644 --- a/solidity_deposit_contract/Makefile +++ b/solidity_deposit_contract/Makefile @@ -30,7 +30,7 @@ install_deposit_contract_web3_tester: @cd $(DEPOSIT_CONTRACT_TESTER_DIR); \ python3 -m venv venv; \ source venv/bin/activate; \ - python3 -m pip install -r ../../requirements_preinstallation.txt; \ + python3 -m pip install -r requirements_preinstallation.txt; \ python3 -m pip install -r requirements.txt test_deposit_contract_web3_tests: diff --git a/solidity_deposit_contract/README.md b/solidity_deposit_contract/README.md index 298ea92fef..bff544f268 100644 --- a/solidity_deposit_contract/README.md +++ b/solidity_deposit_contract/README.md @@ -14,6 +14,7 @@ In August 2020, version `r2` was released with metadata modifications and relice ## Compiling solidity deposit contract In this directory run: + ```sh make compile_deposit_contract ``` diff --git a/requirements_preinstallation.txt b/solidity_deposit_contract/web3_tester/requirements_preinstallation.txt similarity index 100% rename from requirements_preinstallation.txt rename to solidity_deposit_contract/web3_tester/requirements_preinstallation.txt diff --git a/specs/_features/custody_game/beacon-chain.md b/specs/_features/custody_game/beacon-chain.md index 66aea773a7..9a1c00940d 100644 --- a/specs/_features/custody_game/beacon-chain.md +++ b/specs/_features/custody_game/beacon-chain.md @@ -55,7 +55,6 @@ - ## Introduction This document details the beacon chain additions and changes of to support the shard data custody game, @@ -101,7 +100,6 @@ building upon the [Sharding](../sharding/beacon-chain.md) specification. | `MAX_CUSTODY_CHUNK_CHALLENGE_RESPONSES` | `uint64(2**4)` (= 16) | | `MAX_CUSTODY_SLASHINGS` | `uint64(2**0)` (= 1) | - ### Size parameters | Name | Value | Unit | @@ -355,7 +353,6 @@ def get_custody_period_for_validator(validator_index: ValidatorIndex, epoch: Epo return (epoch + validator_index % EPOCHS_PER_CUSTODY_PERIOD) // EPOCHS_PER_CUSTODY_PERIOD ``` - ## Per-block processing ### Block processing diff --git a/specs/_features/custody_game/validator.md b/specs/_features/custody_game/validator.md index e711d92a1c..c4eb8c7e5b 100644 --- a/specs/_features/custody_game/validator.md +++ b/specs/_features/custody_game/validator.md @@ -1,8 +1,6 @@ # Custody Game -- Honest Validator **Notice**: This document is a work-in-progress for researchers and implementers. -This is an accompanying document to [Custody Game -- The Beacon Chain](./beacon-chain.md), which describes the expected actions of a "validator" -participating in the shard data Custody Game. ## Table of contents @@ -24,9 +22,11 @@ participating in the shard data Custody Game. - ## Introduction +This is an accompanying document to [Custody Game -- The Beacon Chain](./beacon-chain.md), which describes the expected actions of a "validator" +participating in the shard data Custody Game. + ## Prerequisites This document is an extension of the [Sharding -- Validator](../sharding/validator.md). All behaviors and definitions defined in the Sharding doc carry over unless explicitly noted or overridden. @@ -58,7 +58,6 @@ Up to `MAX_EARLY_DERIVED_SECRET_REVEALS`, [`EarlyDerivedSecretReveal`](./beacon- `attestation.data`, `attestation.aggregation_bits`, and `attestation.signature` are unchanged from Phase 0. But safety/validity in signing the message is premised upon calculation of the "custody bit" [TODO]. - ## How to avoid slashing Proposer and Attester slashings described in Phase 0 remain in place with the addition of the following. diff --git a/specs/_features/das/das-core.md b/specs/_features/das/das-core.md index f683cbbe13..b4173d6550 100644 --- a/specs/_features/das/das-core.md +++ b/specs/_features/das/das-core.md @@ -24,7 +24,6 @@ - ## Custom types We define the following Python custom types for type hinting and readability: @@ -33,7 +32,6 @@ We define the following Python custom types for type hinting and readability: | - | - | - | | `SampleIndex` | `uint64` | A sample index, corresponding to chunk of extended data | - ## Configuration ### Misc @@ -42,7 +40,6 @@ We define the following Python custom types for type hinting and readability: | - | - | - | | `MAX_RESAMPLE_TIME` | `TODO` (= TODO) | Time window to sample a shard blob and put it on vertical subnets | - ## New containers ### `DASSample` diff --git a/specs/_features/das/fork-choice.md b/specs/_features/das/fork-choice.md index f8ee68eabe..fbd28eb679 100644 --- a/specs/_features/das/fork-choice.md +++ b/specs/_features/das/fork-choice.md @@ -14,7 +14,6 @@ - ## Introduction This document is the beacon chain fork choice spec for Data Availability Sampling. The only change that we add from phase 0 is that we add a concept of "data dependencies"; diff --git a/specs/_features/das/p2p-interface.md b/specs/_features/das/p2p-interface.md index 2c165078d2..491e1fe8f6 100644 --- a/specs/_features/das/p2p-interface.md +++ b/specs/_features/das/p2p-interface.md @@ -95,7 +95,6 @@ Since the messages are content-addressed (instead of origin-stamped), multiple publishers of the same samples on a vertical subnet do not hurt performance, but actually improve it by shortcutting regular propagation on the vertical subnet, and thus lowering the latency to a sample. - ### Vertical subnets Vertical subnets propagate the samples to every peer that is interested. @@ -161,7 +160,6 @@ Take `blob = signed_blob.blob`: The [DAS participation spec](sampling.md#horizontal-subnets) outlines when and where to participate in DAS on horizontal subnets. - #### Vertical subnets: `das_sample_{subnet_index}` Shard blob samples can be verified with just a 48 byte KZG proof (commitment quotient polynomial), @@ -185,7 +183,6 @@ The following validations MUST pass before forwarding the `sample` on the vertic Upon receiving a valid sample, it SHOULD be retained for a buffer period if the local node is part of the backbone that covers this sample. This is to serve other peers that may have missed it. - ## DAS in the Req-Resp domain: Pull To pull samples from nodes, in case of network instability when samples are unavailable, a new query method is added to the Req-Resp domain. @@ -201,6 +198,7 @@ Note that DAS networking uses a different protocol prefix: `/eth2/das/req` **Protocol ID:** `/eth2/das/req/query/1/` Request Content: + ``` ( sample_index: SampleIndex @@ -208,6 +206,7 @@ Request Content: ``` Response Content: + ``` ( DASSample diff --git a/specs/_features/das/sampling.md b/specs/_features/das/sampling.md index 53685c6509..1f6eaf6378 100644 --- a/specs/_features/das/sampling.md +++ b/specs/_features/das/sampling.md @@ -22,7 +22,6 @@ - ## Data Availability Sampling TODO: Summary of Data Availability problem @@ -45,7 +44,6 @@ TODO TODO - ### DAS during network instability The GossipSub based retrieval of samples may not always work. diff --git a/specs/_features/eip6800/beacon-chain.md b/specs/_features/eip6800/beacon-chain.md index ab935cb870..a5134eda61 100644 --- a/specs/_features/eip6800/beacon-chain.md +++ b/specs/_features/eip6800/beacon-chain.md @@ -1,5 +1,7 @@ # EIP6800 -- The Beacon Chain +**Notice**: This document is a work-in-progress for researchers and implementers. + ## Table of contents diff --git a/specs/_features/eip6800/fork.md b/specs/_features/eip6800/fork.md index 14172c9f3e..ed8f9071e8 100644 --- a/specs/_features/eip6800/fork.md +++ b/specs/_features/eip6800/fork.md @@ -1,7 +1,10 @@ # EIP-6800 -- Fork Logic +**Notice**: This document is a work-in-progress for researchers and implementers. + ## Table of contents + @@ -15,6 +18,7 @@ - [Upgrading the state](#upgrading-the-state) + ## Introduction @@ -29,7 +33,6 @@ Warning: this configuration is not definitive. | `EIP6800_FORK_VERSION` | `Version('0x05000000')` | | `EIP6800_FORK_EPOCH` | `Epoch(18446744073709551615)` **TBD** | - ## Helper functions ### Misc diff --git a/specs/_features/eip6914/beacon-chain.md b/specs/_features/eip6914/beacon-chain.md index fcb7716f7e..c95d70fb33 100644 --- a/specs/_features/eip6914/beacon-chain.md +++ b/specs/_features/eip6914/beacon-chain.md @@ -1,5 +1,7 @@ # EIP-6914 -- The Beacon Chain +**Notice**: This document is a work-in-progress for researchers and implementers. + ## Table of contents diff --git a/specs/_features/eip6914/fork-choice.md b/specs/_features/eip6914/fork-choice.md index 25adc82d61..254d0c398c 100644 --- a/specs/_features/eip6914/fork-choice.md +++ b/specs/_features/eip6914/fork-choice.md @@ -1,5 +1,7 @@ # EIP-6914 -- Fork Choice +**Notice**: This document is a work-in-progress for researchers and implementers. + ## Table of contents diff --git a/specs/_features/eip7732/beacon-chain.md b/specs/_features/eip7732/beacon-chain.md index 2303e33d40..461a1f01a0 100644 --- a/specs/_features/eip7732/beacon-chain.md +++ b/specs/_features/eip7732/beacon-chain.md @@ -1,5 +1,7 @@ # EIP-7732 -- The Beacon Chain +**Notice**: This document is a work-in-progress for researchers and implementers. + ## Table of contents diff --git a/specs/_features/eip7732/builder.md b/specs/_features/eip7732/builder.md index 7c793b07e6..be60332ec8 100644 --- a/specs/_features/eip7732/builder.md +++ b/specs/_features/eip7732/builder.md @@ -1,7 +1,10 @@ # EIP-7732 -- Honest Builder -This is an accompanying document which describes the expected actions of a "builder" participating in the Ethereum proof-of-stake protocol. +**Notice**: This document is a work-in-progress for researchers and implementers. + +## Table of contents + @@ -13,9 +16,12 @@ This is an accompanying document which describes the expected actions of a "buil - [Honest payload withheld messages](#honest-payload-withheld-messages) + ## Introduction +This is an accompanying document which describes the expected actions of a "builder" participating in the Ethereum proof-of-stake protocol. + With the EIP-7732 Fork, the protocol includes new staked participants of the protocol called *Builders*. While Builders are a subset of the validator set, they have extra attributions that are optional. Validators may opt to not be builders and as such we collect the set of guidelines for those validators that want to act as builders in this document. ## Builders attributions @@ -113,7 +119,9 @@ To construct the `execution_payload_envelope` the builder must perform the follo After setting these parameters, the builder should run `process_execution_payload(state, signed_envelope, verify=False)` and this function should not trigger an exception. 6. Set `state_root` to `hash_tree_root(state)`. + After preparing the `envelope` the builder should sign the envelope using: + ```python def get_execution_payload_envelope_signature( state: BeaconState, envelope: ExecutionPayloadEnvelope, privkey: int) -> BLSSignature: @@ -121,6 +129,7 @@ def get_execution_payload_envelope_signature( signing_root = compute_signing_root(envelope, domain) return bls.Sign(privkey, signing_root) ``` + The builder assembles then `signed_execution_payload_envelope = SignedExecutionPayloadEnvelope(message=envelope, signature=signature)` and broadcasts it on the `execution_payload` global gossip topic. ### Honest payload withheld messages diff --git a/specs/_features/eip7732/fork-choice.md b/specs/_features/eip7732/fork-choice.md index a52e959cba..779b6e7009 100644 --- a/specs/_features/eip7732/fork-choice.md +++ b/specs/_features/eip7732/fork-choice.md @@ -1,6 +1,9 @@ # EIP-7732 -- Fork Choice +**Notice**: This document is a work-in-progress for researchers and implementers. + ## Table of contents + @@ -53,6 +56,7 @@ This is the modification of the fork choice accompanying the EIP-7732 upgrade. ## Containers ### New `ChildNode` + Auxiliary class to consider `(block, slot, bool)` LMD voting ```python @@ -65,6 +69,7 @@ class ChildNode(Container): ## Helpers ### Modified `LatestMessage` + **Note:** The class is modified to keep track of the slot instead of the epoch. ```python @@ -75,6 +80,7 @@ class LatestMessage(object): ``` ### Modified `update_latest_messages` + **Note:** the function `update_latest_messages` is updated to use the attestation slot instead of target. Notice that this function is only called on validated attestations and validators cannot attest twice in the same epoch without equivocating. Notice also that target epoch number and slot number are validated on `validate_on_attestation`. ```python @@ -88,6 +94,7 @@ def update_latest_messages(store: Store, attesting_indices: Sequence[ValidatorIn ``` ### Modified `Store` + **Note:** `Store` is modified to track the intermediate states of "empty" consensus blocks, that is, those consensus blocks for which the corresponding execution payload has not been revealed or has not been included on chain. ```python @@ -193,6 +200,7 @@ def is_parent_node_full(store: Store, block: BeaconBlock) -> bool: ``` ### Modified `get_ancestor` + **Note:** `get_ancestor` is modified to return whether the chain is based on an *empty* or *full* block. ```python @@ -213,6 +221,7 @@ def get_ancestor(store: Store, root: Root, slot: Slot) -> ChildNode: ``` ### Modified `get_checkpoint_block` + **Note:** `get_checkpoint_block` is modified to use the new `get_ancestor` ```python @@ -224,7 +233,6 @@ def get_checkpoint_block(store: Store, root: Root, epoch: Epoch) -> Root: return get_ancestor(store, root, epoch_first_slot).root ``` - ### `is_supporting_vote` ```python @@ -245,7 +253,9 @@ def is_supporting_vote(store: Store, node: ChildNode, message: LatestMessage) -> ``` ### New `compute_proposer_boost` + This is a helper to compute the proposer boost. It applies the proposer boost to any ancestor of the proposer boost root taking into account the payload presence. There is one exception: if the requested node has the same root and slot as the block with the proposer boost root, then the proposer boost is applied to both empty and full versions of the node. + ```python def compute_proposer_boost(store: Store, state: BeaconState, node: ChildNode) -> Gwei: if store.proposer_boost_root == Root(): @@ -264,6 +274,7 @@ def compute_proposer_boost(store: Store, state: BeaconState, node: ChildNode) -> ``` ### New `compute_withhold_boost` + This is a similar helper that applies for the withhold boost. In this case this always takes into account the reveal status. ```python @@ -283,6 +294,7 @@ def compute_withhold_boost(store: Store, state: BeaconState, node: ChildNode) -> ``` ### New `compute_reveal_boost` + This is a similar helper to the last two, the only difference is that the reveal boost is only applied to the full version of the node when querying for the same slot as the revealed payload. ```python diff --git a/specs/_features/eip7732/fork.md b/specs/_features/eip7732/fork.md index fa03eb6886..dc61b22160 100644 --- a/specs/_features/eip7732/fork.md +++ b/specs/_features/eip7732/fork.md @@ -4,6 +4,7 @@ ## Table of contents + @@ -17,6 +18,7 @@ - [Upgrading the state](#upgrading-the-state) + ## Introduction diff --git a/specs/_features/eip7732/p2p-interface.md b/specs/_features/eip7732/p2p-interface.md index a2716933cd..d29c4d153c 100644 --- a/specs/_features/eip7732/p2p-interface.md +++ b/specs/_features/eip7732/p2p-interface.md @@ -1,5 +1,10 @@ # EIP-7732 -- Networking +**Notice**: This document is a work-in-progress for researchers and implementers. + +## Table of contents + + @@ -26,6 +31,7 @@ - [ExecutionPayloadEnvelopesByRoot v1](#executionpayloadenvelopesbyroot-v1) + ## Introduction @@ -39,9 +45,9 @@ The specification of these changes continues in the same format as the network s *[Modified in EIP-7732]* -| Name | Value | Description | -|------------------------------------------|-----------------------------------|---------------------------------------------------------------------| -| `KZG_COMMITMENT_INCLUSION_PROOF_DEPTH_EIP7732` | `13` # TODO: Compute it when the spec stabilizes | Merkle proof depth for the `blob_kzg_commitments` list item | +| Name | Value | Description | +|------------------------------------------------|--------------|-------------------------------------------------------------| +| `KZG_COMMITMENT_INCLUSION_PROOF_DEPTH_EIP7732` | `13` **TBD** | Merkle proof depth for the `blob_kzg_commitments` list item | ### Configuration @@ -51,7 +57,6 @@ The specification of these changes continues in the same format as the network s |------------------------|----------------|-------------------------------------------------------------------| | `MAX_REQUEST_PAYLOADS` | `2**7` (= 128) | Maximum number of execution payload envelopes in a single request | - ### Containers #### `BlobSidecar` @@ -227,7 +232,6 @@ Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: | `DENEB_FORK_VERSION` | `deneb.SignedBeaconBlock` | | `EIP7732_FORK_VERSION` | `eip7732.SignedBeaconBlock` | - ##### BlobSidecarsByRoot v2 **Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_root/2/` @@ -239,7 +243,6 @@ Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: | `DENEB_FORK_VERSION` | `deneb.BlobSidecar` | | `EIP7732_FORK_VERSION` | `eip7732.BlobSidecar` | - ##### ExecutionPayloadEnvelopesByRoot v1 **Protocol ID:** `/eth2/beacon_chain/req/execution_payload_envelopes_by_root/1/` @@ -267,6 +270,7 @@ Response Content: List[SignedExecutionPayloadEnvelope, MAX_REQUEST_PAYLOADS] ) ``` + Requests execution payload envelopes by `signed_execution_payload_envelope.message.block_root`. The response is a list of `SignedExecutionPayloadEnvelope` whose length is less than or equal to the number of requested execution payload envelopes. It may be less in the case that the responding peer is missing payload envelopes. No more than `MAX_REQUEST_PAYLOADS` may be requested at a time. diff --git a/specs/_features/eip7732/validator.md b/specs/_features/eip7732/validator.md index 3a4d4e93ea..b4ebe0e510 100644 --- a/specs/_features/eip7732/validator.md +++ b/specs/_features/eip7732/validator.md @@ -1,11 +1,14 @@ # EIP-7732 -- Honest Validator -This document represents the changes and additions to the Honest validator guide included in the EIP-7732 fork. +**Notice**: This document is a work-in-progress for researchers and implementers. + +## Table of contents + -**Table of Contents** +- [Introduction](#introduction) - [Validator assignment](#validator-assignment) - [Lookahead](#lookahead) - [Beacon chain responsibilities](#beacon-chain-responsibilities) @@ -19,6 +22,11 @@ This document represents the changes and additions to the Honest validator guide - [Constructing a payload attestation](#constructing-a-payload-attestation) + + +## Introduction + +This document represents the changes and additions to the Honest validator guide included in the EIP-7732 fork. ## Validator assignment @@ -66,7 +74,6 @@ Attestation duties are not changed for validators, however the attestation deadl Sync committee duties are not changed for validators, however the submission deadline is implicitly changed by the change in `INTERVALS_PER_SLOT`. - ### Block proposal Validators are still expected to propose `SignedBeaconBlock` at the beginning of any slot during which `is_proposer(state, validator_index)` returns `true`. The mechanism to prepare this beacon block and related sidecars differs from previous forks as follows @@ -130,5 +137,3 @@ def get_payload_attestation_message_signature( ``` **Remark** Validators do not need to check the full validity of the `ExecutionPayload` contained in within the envelope, but the checks in the [P2P guide](./p2p-interface.md) should pass for the `SignedExecutionPayloadEnvelope`. - - diff --git a/specs/_features/sharding/beacon-chain.md b/specs/_features/sharding/beacon-chain.md index 35b6776028..c7a8fb5fe4 100644 --- a/specs/_features/sharding/beacon-chain.md +++ b/specs/_features/sharding/beacon-chain.md @@ -45,7 +45,6 @@ - ## Introduction This document describes the extensions made to the Phase 0 design of The Beacon Chain to support data sharding, @@ -57,7 +56,6 @@ using KZG10 commitments to commit to data to remove any need for fraud proofs (a - **Data**: A list of KZG points, to translate a byte string into - **Blob**: Data with commitments and meta-data, like a flattened bundle of L2 transactions. - ## Constants The following values are (non-configurable) constants used throughout the specification. @@ -72,7 +70,7 @@ The following values are (non-configurable) constants used throughout the specif | Name | Value | | - | - | -| `DOMAIN_SHARD_SAMPLE` | `DomainType('0x10000000')` | +| `DOMAIN_SHARD_SAMPLE` | `DomainType('0x10000000')` | ## Preset diff --git a/specs/_features/sharding/polynomial-commitments.md b/specs/_features/sharding/polynomial-commitments.md index 865328597e..7dc756acc0 100644 --- a/specs/_features/sharding/polynomial-commitments.md +++ b/specs/_features/sharding/polynomial-commitments.md @@ -44,7 +44,6 @@ - ## Introduction This document specifies basic polynomial operations and KZG polynomial commitment operations as they are needed for the sharding specification. The implementations are not optimized for performance, but readability. All practical implementations should optimize the polynomial operations, and hints what the best known algorithms for these implementations are included below. @@ -58,7 +57,6 @@ This document specifies basic polynomial operations and KZG polynomial commitmen | `BLS_MODULUS` | `0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001` (curve order of BLS12_381) | | `PRIMITIVE_ROOT_OF_UNITY` | `7` | Primitive root of unity of the BLS12_381 (inner) BLS_MODULUS | - ### KZG Trusted setup | Name | Value | @@ -259,7 +257,6 @@ def multiply_polynomials(a: BLSPolynomialByCoefficients, b: BLSPolynomialByCoeff return r ``` - #### `interpolate_polynomial` ```python diff --git a/specs/_features/whisk/fork.md b/specs/_features/whisk/fork.md index 300d191296..46bb5ca07f 100644 --- a/specs/_features/whisk/fork.md +++ b/specs/_features/whisk/fork.md @@ -19,7 +19,6 @@ This document describes the process of Whisk upgrade. - ``` """ WHISK_FORK_EPOCH diff --git a/specs/altair/fork.md b/specs/altair/fork.md index a25050a17a..17b0b79c80 100644 --- a/specs/altair/fork.md +++ b/specs/altair/fork.md @@ -2,6 +2,7 @@ ## Table of contents + @@ -15,6 +16,7 @@ - [Upgrading the state](#upgrading-the-state) + ## Introduction diff --git a/specs/altair/light-client/full-node.md b/specs/altair/light-client/full-node.md index b3b65b83fa..2cda350878 100644 --- a/specs/altair/light-client/full-node.md +++ b/specs/altair/light-client/full-node.md @@ -1,7 +1,5 @@ # Altair Light Client -- Full Node -**Notice**: This document is a work-in-progress for researchers and implementers. - ## Table of contents diff --git a/specs/altair/light-client/light-client.md b/specs/altair/light-client/light-client.md index 545c36a755..bd240af3da 100644 --- a/specs/altair/light-client/light-client.md +++ b/specs/altair/light-client/light-client.md @@ -1,7 +1,5 @@ # Altair Light Client -- Light Client -**Notice**: This document is a work-in-progress for researchers and implementers. - ## Table of contents diff --git a/specs/altair/light-client/p2p-interface.md b/specs/altair/light-client/p2p-interface.md index e1fe7487db..c8734bb71c 100644 --- a/specs/altair/light-client/p2p-interface.md +++ b/specs/altair/light-client/p2p-interface.md @@ -1,7 +1,5 @@ # Altair Light Client -- Networking -**Notice**: This document is a work-in-progress for researchers and implementers. - ## Table of contents @@ -158,6 +156,7 @@ Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: **Protocol ID:** `/eth2/beacon_chain/req/light_client_updates_by_range/1/` Request Content: + ``` ( start_period: uint64 @@ -166,6 +165,7 @@ Request Content: ``` Response Content: + ``` ( List[LightClientUpdate, MAX_REQUEST_LIGHT_CLIENT_UPDATES] diff --git a/specs/altair/light-client/sync-protocol.md b/specs/altair/light-client/sync-protocol.md index 8cb5543bf3..f85c55258d 100644 --- a/specs/altair/light-client/sync-protocol.md +++ b/specs/altair/light-client/sync-protocol.md @@ -1,7 +1,5 @@ # Altair Light Client -- Sync Protocol -**Notice**: This document is a work-in-progress for researchers and implementers. - ## Table of contents diff --git a/specs/bellatrix/fork-choice.md b/specs/bellatrix/fork-choice.md index 17fb8e024d..b64b214a8c 100644 --- a/specs/bellatrix/fork-choice.md +++ b/specs/bellatrix/fork-choice.md @@ -1,6 +1,7 @@ # Bellatrix -- Fork Choice ## Table of contents + diff --git a/specs/bellatrix/fork.md b/specs/bellatrix/fork.md index 569dccdc66..a00d8b32cc 100644 --- a/specs/bellatrix/fork.md +++ b/specs/bellatrix/fork.md @@ -2,6 +2,7 @@ ## Table of contents + @@ -15,6 +16,7 @@ - [Upgrading the state](#upgrading-the-state) + ## Introduction diff --git a/specs/bellatrix/validator.md b/specs/bellatrix/validator.md index cb9dda05d6..3de1e807f0 100644 --- a/specs/bellatrix/validator.md +++ b/specs/bellatrix/validator.md @@ -124,7 +124,6 @@ To obtain an execution payload, a block proposer building a block on top of a `s * `finalized_block_hash` is the block hash of the latest finalized execution payload (`Hash32()` if none yet finalized) * `suggested_fee_recipient` is the value suggested to be used for the `fee_recipient` field of the execution payload - ```python def prepare_execution_payload(state: BeaconState, safe_block_hash: Hash32, diff --git a/specs/capella/fork-choice.md b/specs/capella/fork-choice.md index a66410cf0b..3300a5c950 100644 --- a/specs/capella/fork-choice.md +++ b/specs/capella/fork-choice.md @@ -1,6 +1,7 @@ # Capella -- Fork Choice ## Table of contents + diff --git a/specs/capella/fork.md b/specs/capella/fork.md index 73d4ba2b71..867f26dfba 100644 --- a/specs/capella/fork.md +++ b/specs/capella/fork.md @@ -2,6 +2,7 @@ ## Table of contents + @@ -15,6 +16,7 @@ - [Upgrading the state](#upgrading-the-state) + ## Introduction @@ -27,7 +29,6 @@ This document describes the process of the Capella upgrade. | `CAPELLA_FORK_VERSION` | `Version('0x03000000')` | | `CAPELLA_FORK_EPOCH` | `Epoch(194048)` (April 12, 2023, 10:27:35pm UTC) | - ## Helper functions ### Misc diff --git a/specs/capella/light-client/full-node.md b/specs/capella/light-client/full-node.md index 319fb1c944..61e03e8ae6 100644 --- a/specs/capella/light-client/full-node.md +++ b/specs/capella/light-client/full-node.md @@ -1,7 +1,5 @@ # Capella Light Client -- Full Node -**Notice**: This document is a work-in-progress for researchers and implementers. - ## Table of contents diff --git a/specs/capella/light-client/p2p-interface.md b/specs/capella/light-client/p2p-interface.md index b6c1ec0808..98a5e5fe0f 100644 --- a/specs/capella/light-client/p2p-interface.md +++ b/specs/capella/light-client/p2p-interface.md @@ -1,7 +1,5 @@ # Capella Light Client -- Networking -**Notice**: This document is a work-in-progress for researchers and implementers. - ## Table of contents diff --git a/specs/capella/light-client/sync-protocol.md b/specs/capella/light-client/sync-protocol.md index b241b21378..abf44051c4 100644 --- a/specs/capella/light-client/sync-protocol.md +++ b/specs/capella/light-client/sync-protocol.md @@ -1,7 +1,5 @@ # Capella Light Client -- Sync Protocol -**Notice**: This document is a work-in-progress for researchers and implementers. - ## Table of contents diff --git a/specs/deneb/fork-choice.md b/specs/deneb/fork-choice.md index 836fe61743..3fce780efd 100644 --- a/specs/deneb/fork-choice.md +++ b/specs/deneb/fork-choice.md @@ -1,6 +1,7 @@ # Deneb -- Fork Choice ## Table of contents + diff --git a/specs/deneb/fork.md b/specs/deneb/fork.md index 94168dbc7b..ff28c94186 100644 --- a/specs/deneb/fork.md +++ b/specs/deneb/fork.md @@ -2,6 +2,7 @@ ## Table of contents + @@ -15,6 +16,7 @@ - [Upgrading the state](#upgrading-the-state) + ## Introduction diff --git a/specs/deneb/light-client/full-node.md b/specs/deneb/light-client/full-node.md index 424723667c..17f4c50071 100644 --- a/specs/deneb/light-client/full-node.md +++ b/specs/deneb/light-client/full-node.md @@ -1,7 +1,5 @@ # Deneb Light Client -- Full Node -**Notice**: This document is a work-in-progress for researchers and implementers. - ## Table of contents diff --git a/specs/deneb/light-client/p2p-interface.md b/specs/deneb/light-client/p2p-interface.md index 0ca53056a9..ee49981231 100644 --- a/specs/deneb/light-client/p2p-interface.md +++ b/specs/deneb/light-client/p2p-interface.md @@ -1,7 +1,5 @@ # Deneb Light Client -- Networking -**Notice**: This document is a work-in-progress for researchers and implementers. - ## Table of contents diff --git a/specs/deneb/light-client/sync-protocol.md b/specs/deneb/light-client/sync-protocol.md index 38aa3897b3..53fb6e975f 100644 --- a/specs/deneb/light-client/sync-protocol.md +++ b/specs/deneb/light-client/sync-protocol.md @@ -1,7 +1,5 @@ # Deneb Light Client -- Sync Protocol -**Notice**: This document is a work-in-progress for researchers and implementers. - ## Table of contents diff --git a/specs/deneb/p2p-interface.md b/specs/deneb/p2p-interface.md index e38a50ba2e..14a457e203 100644 --- a/specs/deneb/p2p-interface.md +++ b/specs/deneb/p2p-interface.md @@ -30,9 +30,9 @@ - [Messages](#messages) - [BeaconBlocksByRange v2](#beaconblocksbyrange-v2) - [BeaconBlocksByRoot v2](#beaconblocksbyroot-v2) + - [BlobSidecarsByRange v1](#blobsidecarsbyrange-v1) - [BlobSidecarsByRoot v1](#blobsidecarsbyroot-v1) - [Blob retrieval via local execution layer client](#blob-retrieval-via-local-execution-layer-client) - - [BlobSidecarsByRange v1](#blobsidecarsbyrange-v1) - [Design decision rationale](#design-decision-rationale) - [Why are blobs relayed as a sidecar, separate from beacon blocks?](#why-are-blobs-relayed-as-a-sidecar-separate-from-beacon-blocks) @@ -271,69 +271,6 @@ No more than `MAX_REQUEST_BLOCKS_DENEB` may be requested at a time. Clients SHOULD include a block in the response as soon as it passes the gossip validation rules. Clients SHOULD NOT respond with blocks that fail the beacon chain state transition. -##### BlobSidecarsByRoot v1 - -**Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_root/1/` - -*[New in Deneb:EIP4844]* - -Request Content: - -``` -( - List[BlobIdentifier, MAX_REQUEST_BLOB_SIDECARS] -) -``` - -Response Content: - -``` -( - List[BlobSidecar, MAX_REQUEST_BLOB_SIDECARS] -) -``` - -Requests sidecars by block root and index. -The response is a list of `BlobSidecar` whose length is less than or equal to the number of requests. -It may be less in the case that the responding peer is missing blocks or sidecars. - -Before consuming the next response chunk, the response reader SHOULD verify the blob sidecar is well-formatted, has valid inclusion proof, and is correct w.r.t. the expected KZG commitments through `verify_blob_kzg_proof`. - -No more than `MAX_REQUEST_BLOB_SIDECARS` may be requested at a time. - -`BlobSidecarsByRoot` is primarily used to recover recent blobs (e.g. when receiving a block with a transaction whose corresponding blob is missing). - -The response MUST consist of zero or more `response_chunk`. -Each _successful_ `response_chunk` MUST contain a single `BlobSidecar` payload. - -Clients MUST support requesting sidecars since `minimum_request_epoch`, where `minimum_request_epoch = max(finalized_epoch, current_epoch - MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS, DENEB_FORK_EPOCH)`. If any root in the request content references a block earlier than `minimum_request_epoch`, peers MAY respond with error code `3: ResourceUnavailable` or not include the blob sidecar in the response. - -Clients MUST respond with at least one sidecar, if they have it. -Clients MAY limit the number of blocks and sidecars in the response. - -Clients SHOULD include a sidecar in the response as soon as it passes the gossip validation rules. -Clients SHOULD NOT respond with sidecars related to blocks that fail gossip validation rules. -Clients SHOULD NOT respond with sidecars related to blocks that fail the beacon chain state transition - -For each `response_chunk`, a `ForkDigest`-context based on `compute_fork_version(compute_epoch_at_slot(blob_sidecar.signed_block_header.message.slot))` is used to select the fork namespace of the Response type. - -Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: - -[0]: # (eth2spec: skip) - -| `fork_version` | Chunk SSZ type | -|--------------------------------|---------------------| -| `DENEB_FORK_VERSION` and later | `deneb.BlobSidecar` | - -###### Blob retrieval via local execution layer client - -In addition to `BlobSidecarsByRoot` requests, recent blobs MAY be retrieved by querying the Execution Layer (i.e. via `engine_getBlobsV1`). -Implementers are encouraged to leverage this method to increase the likelihood of incorporating and attesting to the last block when its proposer is not able to publish blobs on time. - -When clients use the local execution layer to retrieve blobs, they MUST behave as if the corresponding `blob_sidecar` had been received via gossip. In particular they MUST: -* publish the corresponding `blob_sidecar` on the `blob_sidecar_{subnet_id}` subnet. -* update gossip rule related data structures (i.e. update the anti-equivocation cache). - ##### BlobSidecarsByRange v1 **Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_range/1/` @@ -341,6 +278,7 @@ When clients use the local execution layer to retrieve blobs, they MUST behave a *[New in Deneb:EIP4844]* Request Content: + ``` ( start_slot: Slot @@ -349,6 +287,7 @@ Request Content: ``` Response Content: + ``` ( List[BlobSidecar, MAX_REQUEST_BLOB_SIDECARS] @@ -416,6 +355,69 @@ Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: |--------------------------------|---------------------| | `DENEB_FORK_VERSION` and later | `deneb.BlobSidecar` | +##### BlobSidecarsByRoot v1 + +**Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_root/1/` + +*[New in Deneb:EIP4844]* + +Request Content: + +``` +( + List[BlobIdentifier, MAX_REQUEST_BLOB_SIDECARS] +) +``` + +Response Content: + +``` +( + List[BlobSidecar, MAX_REQUEST_BLOB_SIDECARS] +) +``` + +Requests sidecars by block root and index. +The response is a list of `BlobSidecar` whose length is less than or equal to the number of requests. +It may be less in the case that the responding peer is missing blocks or sidecars. + +Before consuming the next response chunk, the response reader SHOULD verify the blob sidecar is well-formatted, has valid inclusion proof, and is correct w.r.t. the expected KZG commitments through `verify_blob_kzg_proof`. + +No more than `MAX_REQUEST_BLOB_SIDECARS` may be requested at a time. + +`BlobSidecarsByRoot` is primarily used to recover recent blobs (e.g. when receiving a block with a transaction whose corresponding blob is missing). + +The response MUST consist of zero or more `response_chunk`. +Each _successful_ `response_chunk` MUST contain a single `BlobSidecar` payload. + +Clients MUST support requesting sidecars since `minimum_request_epoch`, where `minimum_request_epoch = max(finalized_epoch, current_epoch - MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS, DENEB_FORK_EPOCH)`. If any root in the request content references a block earlier than `minimum_request_epoch`, peers MAY respond with error code `3: ResourceUnavailable` or not include the blob sidecar in the response. + +Clients MUST respond with at least one sidecar, if they have it. +Clients MAY limit the number of blocks and sidecars in the response. + +Clients SHOULD include a sidecar in the response as soon as it passes the gossip validation rules. +Clients SHOULD NOT respond with sidecars related to blocks that fail gossip validation rules. +Clients SHOULD NOT respond with sidecars related to blocks that fail the beacon chain state transition + +For each `response_chunk`, a `ForkDigest`-context based on `compute_fork_version(compute_epoch_at_slot(blob_sidecar.signed_block_header.message.slot))` is used to select the fork namespace of the Response type. + +Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: + +[0]: # (eth2spec: skip) + +| `fork_version` | Chunk SSZ type | +|--------------------------------|---------------------| +| `DENEB_FORK_VERSION` and later | `deneb.BlobSidecar` | + +###### Blob retrieval via local execution layer client + +In addition to `BlobSidecarsByRoot` requests, recent blobs MAY be retrieved by querying the Execution Layer (i.e. via `engine_getBlobsV1`). +Implementers are encouraged to leverage this method to increase the likelihood of incorporating and attesting to the last block when its proposer is not able to publish blobs on time. + +When clients use the local execution layer to retrieve blobs, they MUST behave as if the corresponding `blob_sidecar` had been received via gossip. In particular they MUST: +* publish the corresponding `blob_sidecar` on the `blob_sidecar_{subnet_id}` subnet. +* update gossip rule related data structures (i.e. update the anti-equivocation cache). + ## Design decision rationale ### Why are blobs relayed as a sidecar, separate from beacon blocks? diff --git a/specs/deneb/polynomial-commitments.md b/specs/deneb/polynomial-commitments.md index f73b17309b..24f4e471c8 100644 --- a/specs/deneb/polynomial-commitments.md +++ b/specs/deneb/polynomial-commitments.md @@ -150,7 +150,6 @@ def bit_reversal_permutation(sequence: Sequence[T]) -> Sequence[T]: ### BLS12-381 helpers - #### `multi_exp` This function performs a multi-scalar multiplication between `points` and `integers`. `points` can either be in G1 or G2. @@ -381,7 +380,6 @@ def verify_kzg_proof(commitment_bytes: Bytes48, bytes_to_kzg_proof(proof_bytes)) ``` - #### `verify_kzg_proof_impl` ```python diff --git a/specs/deneb/validator.md b/specs/deneb/validator.md index fa2bfb5d1a..948ba1b664 100644 --- a/specs/deneb/validator.md +++ b/specs/deneb/validator.md @@ -153,6 +153,7 @@ To construct a `BlobSidecar`, a `blob_sidecar` is defined with the necessary con Blobs associated with a block are packaged into sidecar objects for distribution to the associated sidecar topic, the `blob_sidecar_{subnet_id}` pubsub topic. Each `sidecar` is obtained from: + ```python def get_blob_sidecars(signed_block: SignedBeaconBlock, blobs: Sequence[Blob], diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index c366b9c3f9..d6854e5e7a 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -168,7 +168,7 @@ The following values are (non-configurable) constants used throughout the specif ### State list lengths | Name | Value | Unit | -| - | - | :-: | +| - | - | - | | `PENDING_DEPOSITS_LIMIT` | `uint64(2**27)` (= 134,217,728) | pending deposits | | `PENDING_PARTIAL_WITHDRAWALS_LIMIT` | `uint64(2**27)` (= 134,217,728) | pending partial withdrawals | | `PENDING_CONSOLIDATIONS_LIMIT` | `uint64(2**18)` (= 262,144) | pending consolidations | @@ -816,27 +816,24 @@ def process_epoch(state: BeaconState) -> None: #### Modified `process_registry_updates` -*Note*: The function `process_registry_updates` is modified to -use the updated definitions of `initiate_validator_exit` and `is_eligible_for_activation_queue` -and changes how the activation epochs are computed for eligible validators. +*Note*: The function `process_registry_updates` is modified to use the updated definitions of +`initiate_validator_exit` and `is_eligible_for_activation_queue`, changes how the activation epochs +are computed for eligible validators, and processes activations in the same loop as activation +eligibility updates and ejections. ```python def process_registry_updates(state: BeaconState) -> None: - # Process activation eligibility and ejections + current_epoch = get_current_epoch(state) + activation_epoch = compute_activation_exit_epoch(current_epoch) + + # Process activation eligibility, ejections, and activations for index, validator in enumerate(state.validators): if is_eligible_for_activation_queue(validator): # [Modified in Electra:EIP7251] - validator.activation_eligibility_epoch = get_current_epoch(state) + 1 + validator.activation_eligibility_epoch = current_epoch + 1 - if ( - is_active_validator(validator, get_current_epoch(state)) - and validator.effective_balance <= EJECTION_BALANCE - ): + if is_active_validator(validator, current_epoch) and validator.effective_balance <= EJECTION_BALANCE: initiate_validator_exit(state, ValidatorIndex(index)) # [Modified in Electra:EIP7251] - # Activate all eligible validators - # [Modified in Electra:EIP7251] - activation_epoch = compute_activation_exit_epoch(get_current_epoch(state)) - for validator in state.validators: if is_eligible_for_activation(state, validator): validator.activation_epoch = activation_epoch ``` diff --git a/specs/electra/fork.md b/specs/electra/fork.md index b908c542ea..879e548853 100644 --- a/specs/electra/fork.md +++ b/specs/electra/fork.md @@ -4,6 +4,7 @@ ## Table of contents + @@ -17,6 +18,7 @@ - [Upgrading the state](#upgrading-the-state) + ## Introduction diff --git a/specs/electra/light-client/fork.md b/specs/electra/light-client/fork.md index 902c1d6bf3..da44ee4e40 100644 --- a/specs/electra/light-client/fork.md +++ b/specs/electra/light-client/fork.md @@ -1,5 +1,7 @@ # Electra Light Client -- Fork Logic +**Notice**: This document is a work-in-progress for researchers and implementers. + ## Table of contents diff --git a/specs/electra/p2p-interface.md b/specs/electra/p2p-interface.md index 5064676f18..a0b0b28422 100644 --- a/specs/electra/p2p-interface.md +++ b/specs/electra/p2p-interface.md @@ -1,5 +1,7 @@ # Electra -- Networking +**Notice**: This document is a work-in-progress for researchers and implementers. + ## Table of contents @@ -19,8 +21,10 @@ - [`beacon_attestation_{subnet_id}`](#beacon_attestation_subnet_id) - [The Req/Resp domain](#the-reqresp-domain) - [Messages](#messages) - - [BlobSidecarsByRoot v1](#blobsidecarsbyroot-v1) + - [BeaconBlocksByRange v2](#beaconblocksbyrange-v2) + - [BeaconBlocksByRoot v2](#beaconblocksbyroot-v2) - [BlobSidecarsByRange v1](#blobsidecarsbyrange-v1) + - [BlobSidecarsByRoot v1](#blobsidecarsbyroot-v1) @@ -110,9 +114,45 @@ The following validations are removed: #### Messages -##### BlobSidecarsByRoot v1 +##### BeaconBlocksByRange v2 -**Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_root/1/` +**Protocol ID:** `/eth2/beacon_chain/req/beacon_blocks_by_range/2/` + +The Electra fork-digest is introduced to the `context` enum to specify Electra beacon block type. + +Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: + +[0]: # (eth2spec: skip) + +| `fork_version` | Chunk SSZ type | +|--------------------------|-------------------------------| +| `GENESIS_FORK_VERSION` | `phase0.SignedBeaconBlock` | +| `ALTAIR_FORK_VERSION` | `altair.SignedBeaconBlock` | +| `BELLATRIX_FORK_VERSION` | `bellatrix.SignedBeaconBlock` | +| `CAPELLA_FORK_VERSION` | `capella.SignedBeaconBlock` | +| `DENEB_FORK_VERSION` | `deneb.SignedBeaconBlock` | +| `ELECTRA_FORK_VERSION` | `electra.SignedBeaconBlock` | + +##### BeaconBlocksByRoot v2 + +**Protocol ID:** `/eth2/beacon_chain/req/beacon_blocks_by_root/2/` + +Per `context = compute_fork_digest(fork_version, genesis_validators_root)`: + +[0]: # (eth2spec: skip) + +| `fork_version` | Chunk SSZ type | +|--------------------------|-------------------------------| +| `GENESIS_FORK_VERSION` | `phase0.SignedBeaconBlock` | +| `ALTAIR_FORK_VERSION` | `altair.SignedBeaconBlock` | +| `BELLATRIX_FORK_VERSION` | `bellatrix.SignedBeaconBlock` | +| `CAPELLA_FORK_VERSION` | `capella.SignedBeaconBlock` | +| `DENEB_FORK_VERSION` | `deneb.SignedBeaconBlock` | +| `ELECTRA_FORK_VERSION` | `electra.SignedBeaconBlock` | + +##### BlobSidecarsByRange v1 + +**Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_range/1/` *[Modified in Electra:EIP7691]* @@ -120,7 +160,8 @@ Request Content: ``` ( - List[BlobIdentifier, MAX_REQUEST_BLOB_SIDECARS_ELECTRA] + start_slot: Slot + count: uint64 ) ``` @@ -134,11 +175,11 @@ Response Content: *Updated validation* -No more than `MAX_REQUEST_BLOB_SIDECARS_ELECTRA` may be requested at a time. +Clients MUST respond with at least the blob sidecars of the first blob-carrying block that exists in the range, if they have it, and no more than `MAX_REQUEST_BLOB_SIDECARS_ELECTRA` sidecars. -##### BlobSidecarsByRange v1 +##### BlobSidecarsByRoot v1 -**Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_range/1/` +**Protocol ID:** `/eth2/beacon_chain/req/blob_sidecars_by_root/1/` *[Modified in Electra:EIP7691]* @@ -146,8 +187,7 @@ Request Content: ``` ( - start_slot: Slot - count: uint64 + List[BlobIdentifier, MAX_REQUEST_BLOB_SIDECARS_ELECTRA] ) ``` @@ -161,4 +201,4 @@ Response Content: *Updated validation* -Clients MUST respond with at least the blob sidecars of the first blob-carrying block that exists in the range, if they have it, and no more than `MAX_REQUEST_BLOB_SIDECARS_ELECTRA` sidecars. +No more than `MAX_REQUEST_BLOB_SIDECARS_ELECTRA` may be requested at a time. diff --git a/specs/electra/validator.md b/specs/electra/validator.md index 3620c30790..ee59a278cd 100644 --- a/specs/electra/validator.md +++ b/specs/electra/validator.md @@ -1,5 +1,7 @@ # Electra -- Honest Validator +**Notice**: This document is a work-in-progress for researchers and implementers. + ## Table of contents diff --git a/specs/fulu/fork-choice.md b/specs/fulu/fork-choice.md index 4a20906804..ff2014eba9 100644 --- a/specs/fulu/fork-choice.md +++ b/specs/fulu/fork-choice.md @@ -1,6 +1,9 @@ # Fulu -- Fork Choice +**Notice**: This document is a work-in-progress for researchers and implementers. + ## Table of contents + diff --git a/specs/fulu/fork.md b/specs/fulu/fork.md index e496467212..009bb6c943 100644 --- a/specs/fulu/fork.md +++ b/specs/fulu/fork.md @@ -4,6 +4,7 @@ ## Table of contents + @@ -17,6 +18,7 @@ - [Upgrading the state](#upgrading-the-state) + ## Introduction diff --git a/specs/fulu/p2p-interface.md b/specs/fulu/p2p-interface.md index 73d96192ff..b721847b02 100644 --- a/specs/fulu/p2p-interface.md +++ b/specs/fulu/p2p-interface.md @@ -29,8 +29,8 @@ - [`data_column_sidecar_{subnet_id}`](#data_column_sidecar_subnet_id) - [The Req/Resp domain](#the-reqresp-domain) - [Messages](#messages) - - [DataColumnSidecarsByRoot v1](#datacolumnsidecarsbyroot-v1) - [DataColumnSidecarsByRange v1](#datacolumnsidecarsbyrange-v1) + - [DataColumnSidecarsByRoot v1](#datacolumnsidecarsbyroot-v1) - [GetMetaData v3](#getmetadata-v3) - [The discovery domain: discv5](#the-discovery-domain-discv5) - [ENR structure](#enr-structure) @@ -208,56 +208,6 @@ The following validations MUST pass before forwarding the `sidecar: DataColumnSi #### Messages -##### DataColumnSidecarsByRoot v1 - -**Protocol ID:** `/eth2/beacon_chain/req/data_column_sidecars_by_root/1/` - -*[New in Fulu:EIP7594]* - -The `` field is calculated as `context = compute_fork_digest(fork_version, genesis_validators_root)`: - -[1]: # (eth2spec: skip) - -| `fork_version` | Chunk SSZ type | -|---------------------|--------------------------| -| `FULU_FORK_VERSION` | `fulu.DataColumnSidecar` | - -Request Content: - -``` -( - List[DataColumnIdentifier, MAX_REQUEST_DATA_COLUMN_SIDECARS] -) -``` - -Response Content: - -``` -( - List[DataColumnSidecar, MAX_REQUEST_DATA_COLUMN_SIDECARS] -) -``` - -Requests sidecars by block root and index. -The response is a list of `DataColumnIdentifier` whose length is less than or equal to the number of requests. -It may be less in the case that the responding peer is missing blocks or sidecars. - -Before consuming the next response chunk, the response reader SHOULD verify the data column sidecar is well-formatted through `verify_data_column_sidecar`, has valid inclusion proof through `verify_data_column_sidecar_inclusion_proof`, and is correct w.r.t. the expected KZG commitments through `verify_data_column_sidecar_kzg_proofs`. - -No more than `MAX_REQUEST_DATA_COLUMN_SIDECARS` may be requested at a time. - -The response MUST consist of zero or more `response_chunk`. -Each _successful_ `response_chunk` MUST contain a single `DataColumnSidecar` payload. - -Clients MUST support requesting sidecars since `minimum_request_epoch`, where `minimum_request_epoch = max(finalized_epoch, current_epoch - MIN_EPOCHS_FOR_DATA_COLUMN_SIDECARS_REQUESTS, FULU_FORK_EPOCH)`. If any root in the request content references a block earlier than `minimum_request_epoch`, peers MAY respond with error code `3: ResourceUnavailable` or not include the data column sidecar in the response. - -Clients MUST respond with at least one sidecar, if they have it. -Clients MAY limit the number of blocks and sidecars in the response. - -Clients SHOULD include a sidecar in the response as soon as it passes the gossip validation rules. -Clients SHOULD NOT respond with sidecars related to blocks that fail gossip validation rules. -Clients SHOULD NOT respond with sidecars related to blocks that fail the beacon chain state transition - ##### DataColumnSidecarsByRange v1 **Protocol ID:** `/eth2/beacon_chain/req/data_column_sidecars_by_range/1/` @@ -339,6 +289,56 @@ Clients MUST respond with data column sidecars that are consistent from a single After the initial data column sidecar, clients MAY stop in the process of responding if their fork choice changes the view of the chain in the context of the request. +##### DataColumnSidecarsByRoot v1 + +**Protocol ID:** `/eth2/beacon_chain/req/data_column_sidecars_by_root/1/` + +*[New in Fulu:EIP7594]* + +The `` field is calculated as `context = compute_fork_digest(fork_version, genesis_validators_root)`: + +[1]: # (eth2spec: skip) + +| `fork_version` | Chunk SSZ type | +|---------------------|--------------------------| +| `FULU_FORK_VERSION` | `fulu.DataColumnSidecar` | + +Request Content: + +``` +( + List[DataColumnIdentifier, MAX_REQUEST_DATA_COLUMN_SIDECARS] +) +``` + +Response Content: + +``` +( + List[DataColumnSidecar, MAX_REQUEST_DATA_COLUMN_SIDECARS] +) +``` + +Requests sidecars by block root and index. +The response is a list of `DataColumnIdentifier` whose length is less than or equal to the number of requests. +It may be less in the case that the responding peer is missing blocks or sidecars. + +Before consuming the next response chunk, the response reader SHOULD verify the data column sidecar is well-formatted through `verify_data_column_sidecar`, has valid inclusion proof through `verify_data_column_sidecar_inclusion_proof`, and is correct w.r.t. the expected KZG commitments through `verify_data_column_sidecar_kzg_proofs`. + +No more than `MAX_REQUEST_DATA_COLUMN_SIDECARS` may be requested at a time. + +The response MUST consist of zero or more `response_chunk`. +Each _successful_ `response_chunk` MUST contain a single `DataColumnSidecar` payload. + +Clients MUST support requesting sidecars since `minimum_request_epoch`, where `minimum_request_epoch = max(finalized_epoch, current_epoch - MIN_EPOCHS_FOR_DATA_COLUMN_SIDECARS_REQUESTS, FULU_FORK_EPOCH)`. If any root in the request content references a block earlier than `minimum_request_epoch`, peers MAY respond with error code `3: ResourceUnavailable` or not include the data column sidecar in the response. + +Clients MUST respond with at least one sidecar, if they have it. +Clients MAY limit the number of blocks and sidecars in the response. + +Clients SHOULD include a sidecar in the response as soon as it passes the gossip validation rules. +Clients SHOULD NOT respond with sidecars related to blocks that fail gossip validation rules. +Clients SHOULD NOT respond with sidecars related to blocks that fail the beacon chain state transition + ##### GetMetaData v3 **Protocol ID:** `/eth2/beacon_chain/req/metadata/3/` diff --git a/specs/fulu/polynomial-commitments-sampling.md b/specs/fulu/polynomial-commitments-sampling.md index c85e870896..4ef9f40cdd 100644 --- a/specs/fulu/polynomial-commitments-sampling.md +++ b/specs/fulu/polynomial-commitments-sampling.md @@ -1,5 +1,7 @@ # Fulu -- Polynomial Commitments Sampling +**Notice**: This document is a work-in-progress for researchers and implementers. + ## Table of contents diff --git a/specs/phase0/beacon-chain.md b/specs/phase0/beacon-chain.md index 3d860d4a3e..926e0fdd7e 100644 --- a/specs/phase0/beacon-chain.md +++ b/specs/phase0/beacon-chain.md @@ -1,6 +1,7 @@ # Phase 0 -- The Beacon Chain ## Table of contents + @@ -1420,25 +1421,21 @@ def get_base_reward(state: BeaconState, index: ValidatorIndex) -> Gwei: return Gwei(effective_balance * BASE_REWARD_FACTOR // integer_squareroot(total_balance) // BASE_REWARDS_PER_EPOCH) ``` - ```python def get_proposer_reward(state: BeaconState, attesting_index: ValidatorIndex) -> Gwei: return Gwei(get_base_reward(state, attesting_index) // PROPOSER_REWARD_QUOTIENT) ``` - ```python def get_finality_delay(state: BeaconState) -> uint64: return get_previous_epoch(state) - state.finalized_checkpoint.epoch ``` - ```python def is_in_inactivity_leak(state: BeaconState) -> bool: return get_finality_delay(state) > MIN_EPOCHS_TO_INACTIVITY_PENALTY ``` - ```python def get_eligible_validator_indices(state: BeaconState) -> Sequence[ValidatorIndex]: previous_epoch = get_previous_epoch(state) diff --git a/specs/phase0/deposit-contract.md b/specs/phase0/deposit-contract.md index 039b5998b9..29346034a9 100644 --- a/specs/phase0/deposit-contract.md +++ b/specs/phase0/deposit-contract.md @@ -1,6 +1,7 @@ # Phase 0 -- Deposit Contract ## Table of contents + diff --git a/specs/phase0/fork-choice.md b/specs/phase0/fork-choice.md index e7b4d1c28c..8b3066a65d 100644 --- a/specs/phase0/fork-choice.md +++ b/specs/phase0/fork-choice.md @@ -1,6 +1,7 @@ # Phase 0 -- Beacon Chain Fork Choice ## Table of contents + @@ -79,7 +80,6 @@ Any of the above handlers that trigger an unhandled exception (e.g. a failed ass 4) **Manual forks**: Manual forks may arbitrarily change the fork choice rule but are expected to be enacted at epoch transitions, with the fork details reflected in `state.fork`. 5) **Implementation**: The implementation found in this specification is constructed for ease of understanding rather than for optimization in computation, space, or any other resource. A number of optimized alternatives can be found [here](https://github.com/protolambda/lmd-ghost). - ### Constant | Name | Value | @@ -559,7 +559,6 @@ def on_tick_per_slot(store: Store, time: uint64) -> None: #### `on_attestation` helpers - ##### `validate_target_epoch_against_current_time` ```python @@ -627,7 +626,6 @@ def update_latest_messages(store: Store, attesting_indices: Sequence[ValidatorIn store.latest_messages[i] = LatestMessage(epoch=target.epoch, root=beacon_block_root) ``` - ### Handlers #### `on_tick` diff --git a/specs/phase0/p2p-interface.md b/specs/phase0/p2p-interface.md index 240b3ad2cf..71829525c6 100644 --- a/specs/phase0/p2p-interface.md +++ b/specs/phase0/p2p-interface.md @@ -1,6 +1,7 @@ # Phase 0 -- Networking ## Table of contents + @@ -40,12 +41,12 @@ - [Encoding strategies](#encoding-strategies) - [SSZ-snappy encoding strategy](#ssz-snappy-encoding-strategy) - [Messages](#messages) - - [Status](#status) - - [Goodbye](#goodbye) - - [BeaconBlocksByRange](#beaconblocksbyrange) - - [BeaconBlocksByRoot](#beaconblocksbyroot) - - [Ping](#ping) - - [GetMetaData](#getmetadata) + - [Status v1](#status-v1) + - [Goodbye v1](#goodbye-v1) + - [BeaconBlocksByRange v1](#beaconblocksbyrange-v1) + - [BeaconBlocksByRoot v1](#beaconblocksbyroot-v1) + - [Ping v1](#ping-v1) + - [GetMetaData v1](#getmetadata-v1) - [The discovery domain: discv5](#the-discovery-domain-discv5) - [Integration into libp2p stacks](#integration-into-libp2p-stacks) - [ENR structure](#enr-structure) @@ -184,8 +185,8 @@ We define the following Python custom types for type hinting and readability: | Name | SSZ equivalent | Description | | - | - | - | -| `NodeID` | `uint256` | node identifier | -| `SubnetID` | `uint64` | subnet identifier | +| `NodeID` | `uint256` | node identifier | +| `SubnetID` | `uint64` | subnet identifier | ### Constants @@ -198,16 +199,16 @@ We define the following Python custom types for type hinting and readability: This section outlines configurations that are used in this spec. | Name | Value | Description | -|---|---|---| +| - | - | - | | `MAX_PAYLOAD_SIZE` | `10 * 2**20` (= 10485760, 10 MiB) | The maximum allowed size of uncompressed payload in gossipsub messages and RPC chunks | | `MAX_REQUEST_BLOCKS` | `2**10` (= 1024) | Maximum number of blocks in a single request | | `EPOCHS_PER_SUBNET_SUBSCRIPTION` | `2**8` (= 256) | Number of epochs on a subnet subscription (~27 hours) | | `MIN_EPOCHS_FOR_BLOCK_REQUESTS` | `MIN_VALIDATOR_WITHDRAWABILITY_DELAY + CHURN_LIMIT_QUOTIENT // 2` (= 33024, ~5 months) | The minimum epoch range over which a node must serve blocks | -| `ATTESTATION_PROPAGATION_SLOT_RANGE` | `32` | The maximum number of slots during which an attestation can be propagated. | -| `MAXIMUM_GOSSIP_CLOCK_DISPARITY` | `500` | The maximum **milliseconds** of clock disparity assumed between honest nodes. | +| `ATTESTATION_PROPAGATION_SLOT_RANGE` | `32` | The maximum number of slots during which an attestation can be propagated | +| `MAXIMUM_GOSSIP_CLOCK_DISPARITY` | `500` | The maximum **milliseconds** of clock disparity assumed between honest nodes | | `MESSAGE_DOMAIN_INVALID_SNAPPY` | `DomainType('0x00000000')` | 4-byte domain for gossip message-id isolation of *invalid* snappy messages | | `MESSAGE_DOMAIN_VALID_SNAPPY` | `DomainType('0x01000000')` | 4-byte domain for gossip message-id isolation of *valid* snappy messages | -| `SUBNETS_PER_NODE` | `2` | The number of long-lived subnets a beacon node should be subscribed to. | +| `SUBNETS_PER_NODE` | `2` | The number of long-lived subnets a beacon node should be subscribed to | | `ATTESTATION_SUBNET_COUNT` | `2**6` (= 64) | The number of attestation subnets used in the gossipsub protocol. | | `ATTESTATION_SUBNET_EXTRA_BITS` | `0` | The number of extra bits of a NodeId to use when mapping to a subscribed subnet | | `ATTESTATION_SUBNET_PREFIX_BITS` | `int(ceillog2(ATTESTATION_SUBNET_COUNT) + ATTESTATION_SUBNET_EXTRA_BITS)` | | @@ -422,7 +423,6 @@ The following validations MUST pass before forwarding the `signed_aggregate_and_ `get_checkpoint_block(store, aggregate.data.beacon_block_root, finalized_checkpoint.epoch) == store.finalized_checkpoint.root` - ###### `voluntary_exit` The `voluntary_exit` topic is used solely for propagating signed voluntary validator exits to proposers on the network. @@ -497,8 +497,6 @@ The following validations MUST pass before forwarding the `attestation` on the s `get_checkpoint_block(store, attestation.data.beacon_block_root, store.finalized_checkpoint.epoch) == store.finalized_checkpoint.root` - - ##### Attestations and Aggregation Attestation broadcasting is grouped into subnets defined by a topic. @@ -724,11 +722,12 @@ Each _successful_ `response_chunk` contains a single `SignedBeaconBlock` payload #### Messages -##### Status +##### Status v1 **Protocol ID:** ``/eth2/beacon_chain/req/status/1/`` Request, Response Content: + ``` ( fork_digest: ForkDigest @@ -738,6 +737,7 @@ Request, Response Content: head_slot: Slot ) ``` + The fields are, as seen by the client at the time of sending the message: - `fork_digest`: The node's `ForkDigest` (`compute_fork_digest(current_fork_version, genesis_validators_root)`) where @@ -770,16 +770,18 @@ SHOULD request beacon blocks from its counterparty via the `BeaconBlocksByRange` the client might need to send `Status` request again to learn if the peer has a higher head. Implementers are free to implement such behavior in their own way. -##### Goodbye +##### Goodbye v1 **Protocol ID:** ``/eth2/beacon_chain/req/goodbye/1/`` Request, Response Content: + ``` ( uint64 ) ``` + Client MAY send goodbye messages upon disconnection. The reason field MAY be one of the following values: - 1: Client shut down. @@ -794,11 +796,12 @@ The request/response MUST be encoded as a single SSZ-field. The response MUST consist of a single `response_chunk`. -##### BeaconBlocksByRange +##### BeaconBlocksByRange v1 **Protocol ID:** `/eth2/beacon_chain/req/beacon_blocks_by_range/1/` Request Content: + ``` ( start_slot: Slot @@ -808,6 +811,7 @@ Request Content: ``` Response Content: + ``` ( List[SignedBeaconBlock, MAX_REQUEST_BLOCKS] @@ -871,7 +875,7 @@ In particular when `step == 1`, each `parent_root` MUST match the `hash_tree_roo After the initial block, clients MAY stop in the process of responding if their fork choice changes the view of the chain in the context of the request. -##### BeaconBlocksByRoot +##### BeaconBlocksByRoot v1 **Protocol ID:** `/eth2/beacon_chain/req/beacon_blocks_by_root/1/` @@ -914,7 +918,7 @@ Clients SHOULD NOT respond with blocks that fail the beacon chain state transiti `/eth2/beacon_chain/req/beacon_blocks_by_root/1/` is deprecated. Clients MAY respond with an empty list during the deprecation transition period. -##### Ping +##### Ping v1 **Protocol ID:** `/eth2/beacon_chain/req/ping/1/` @@ -946,7 +950,7 @@ The request MUST be encoded as an SSZ-field. The response MUST consist of a single `response_chunk`. -##### GetMetaData +##### GetMetaData v1 **Protocol ID:** `/eth2/beacon_chain/req/metadata/1/` @@ -1008,9 +1012,9 @@ Specifications of these parameters can be found in the [ENR Specification](http: The ENR `attnets` entry signifies the attestation subnet bitfield with the following form to more easily discover peers participating in particular attestation gossip subnets. -| Key | Value | -|:-------------|:-------------------------------------------------| -| `attnets` | SSZ `Bitvector[ATTESTATION_SUBNET_COUNT]` | +| Key | Value | +|:----------|:------------------------------------------| +| `attnets` | SSZ `Bitvector[ATTESTATION_SUBNET_COUNT]` | If a node's `MetaData.attnets` has any non-zero bit, the ENR MUST include the `attnets` entry with the same value as `MetaData.attnets`. @@ -1021,17 +1025,17 @@ If a node's `MetaData.attnets` is composed of all zeros, the ENR MAY optionally ENRs MUST carry a generic `eth2` key with an 16-byte value of the node's current fork digest, next fork version, and next fork epoch to ensure connections are made with peers on the intended Ethereum network. -| Key | Value | -|:-------------|:--------------------| -| `eth2` | SSZ `ENRForkID` | +| Key | Value | +|:-------|:----------------| +| `eth2` | SSZ `ENRForkID` | Specifically, the value of the `eth2` key MUST be the following SSZ encoded object (`ENRForkID`) ``` ( - fork_digest: ForkDigest - next_fork_version: Version - next_fork_epoch: Epoch + fork_digest: ForkDigest + next_fork_version: Version + next_fork_epoch: Epoch ) ``` @@ -1340,7 +1344,6 @@ Some examples of where messages could be duplicated: - `seen_ttl`: `SLOTS_PER_EPOCH * SECONDS_PER_SLOT / heartbeat_interval = approx. 550`. Attestation gossip validity is bounded by an epoch, so this is the safe max bound. - #### Why is there `MAXIMUM_GOSSIP_CLOCK_DISPARITY` when validating slot ranges of messages in gossip subnets? For some gossip channels (e.g. those for Attestations and BeaconBlocks), diff --git a/specs/phase0/weak-subjectivity.md b/specs/phase0/weak-subjectivity.md index 00ab559b32..9d20b6e41e 100644 --- a/specs/phase0/weak-subjectivity.md +++ b/specs/phase0/weak-subjectivity.md @@ -41,19 +41,19 @@ This document uses data structures, constants, functions, and terminology from ## Custom Types | Name | SSZ Equivalent | Description | -|---|---|---| +| - | - | - | | `Ether` | `uint64` | an amount in Ether | ## Constants | Name | Value | -|---|---| +| - | - | | `ETH_TO_GWEI` | `uint64(10**9)` | ## Configuration | Name | Value | -|---|---| +| - | - | | `SAFETY_DECAY` | `uint64(10)` | ## Weak Subjectivity Checkpoint diff --git a/ssz/merkle-proofs.md b/ssz/merkle-proofs.md index 36d0b83ac1..eb1fcaf343 100644 --- a/ssz/merkle-proofs.md +++ b/ssz/merkle-proofs.md @@ -1,8 +1,7 @@ # Merkle proof formats -**Notice**: This document is a work-in-progress for researchers and implementers. - ## Table of contents + diff --git a/ssz/simple-serialize.md b/ssz/simple-serialize.md index b4dedfd0e2..1275904685 100644 --- a/ssz/simple-serialize.md +++ b/ssz/simple-serialize.md @@ -1,6 +1,7 @@ # SimpleSerialize (SSZ) ## Table of contents + @@ -34,7 +35,7 @@ ## Constants | Name | Value | Description | -|-|-|-| +| - | - | - | | `BYTES_PER_CHUNK` | `32` | Number of bytes per chunk. | | `BYTES_PER_LENGTH_OFFSET` | `4` | Number of bytes per serialized length offset. | | `BITS_PER_BYTE` | `8` | Number of bits per byte. | diff --git a/sync/optimistic.md b/sync/optimistic.md index fd83f9a691..f29b29b3d7 100644 --- a/sync/optimistic.md +++ b/sync/optimistic.md @@ -1,6 +1,7 @@ # Optimistic Sync ## Table of contents + diff --git a/tests/README.md b/tests/README.md index dc2e02439d..261dcff177 100644 --- a/tests/README.md +++ b/tests/README.md @@ -123,8 +123,6 @@ More `yield` statements. The output of a consensus test is: 5. `'post'` 6. The state after the test - - ```python # One vote for the eth1 assert len(state.eth1_data_votes) == pre_eth1_votes + 1 @@ -142,7 +140,6 @@ Finally we assertions that test the transition was legitimate. In this case we h 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. - ## New Tests The easiest way to write a new test is to copy and modify an existing one. For example, @@ -173,7 +170,6 @@ def next_slot(spec, state): This looks like exactly what we need. So we add this call before we create the empty block: - ```python . . @@ -191,8 +187,6 @@ 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 verify this). - - ## Tests Designed to Fail It is important to make sure that the system rejects invalid input, so our next step is to deal with cases where the protocol @@ -260,7 +254,6 @@ for the current state. This is the way we specify that a test is designed to fail - failed tests have no post state, because the processing mechanism errors out before creating it. - ## Attestation Tests The consensus layer doesn't provide any direct functionality to end users. It does @@ -280,7 +273,6 @@ 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): Lets go over it line by line. - ```python @with_all_phases @spec_state_test @@ -292,7 +284,6 @@ def test_success(spec, state): creates a valid attestation (which can then be modified to make it invalid if needed). To see an attestion "from the inside" we need to follow it. - > ```python > def get_valid_attestation(spec, > state, @@ -372,7 +363,6 @@ Currently a single block is sufficient, but that may change in the future. [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. - ### Adding an Attestation Test Attestations can't happen in the same block as the one about which they are attesting, or in a block that is @@ -380,7 +370,6 @@ after the block is finalized. This is specified as part of the specs, in the `pr (which is created from the spec by the `make pyspec` command you ran earlier). Here is the relevant code fragment: - ```python def process_attestation(state: BeaconState, attestation: Attestation) -> None: data = attestation.data diff --git a/tests/core/pyspec/README.md b/tests/core/pyspec/README.md index 2fdd107fb1..1b20176a42 100644 --- a/tests/core/pyspec/README.md +++ b/tests/core/pyspec/README.md @@ -16,21 +16,25 @@ However, most of the tests can be run in generator-mode, to output test vectors ### How to run tests To run all tests: + ```shell make test ``` To run all tests under the minimal preset: + ```shell make test preset=minimal ``` Or, to run a specific test function specify `k=`: + ```shell make test k=test_verify_kzg_proof ``` Or, to run a specific test function under a single fork specify `k=`: + ```shell make test fork=phase0 ``` diff --git a/tests/core/pyspec/eth2spec/VERSION.txt b/tests/core/pyspec/eth2spec/VERSION.txt index ba25d3754e..591650acef 100644 --- a/tests/core/pyspec/eth2spec/VERSION.txt +++ b/tests/core/pyspec/eth2spec/VERSION.txt @@ -1 +1 @@ -1.5.0-beta.0 +1.5.0-beta.1 diff --git a/tests/core/pyspec/eth2spec/test/deneb/block_processing/test_process_execution_payload.py b/tests/core/pyspec/eth2spec/test/deneb/block_processing/test_process_execution_payload.py index e8ac314e10..e9405e84f9 100644 --- a/tests/core/pyspec/eth2spec/test/deneb/block_processing/test_process_execution_payload.py +++ b/tests/core/pyspec/eth2spec/test/deneb/block_processing/test_process_execution_payload.py @@ -185,6 +185,23 @@ def test_incorrect_commitment(spec, state): yield from run_execution_payload_processing(spec, state, execution_payload, blob_kzg_commitments) +@with_deneb_and_later +@spec_state_test +def test_no_commitments_for_transactions(spec, state): + """ + The versioned hashes are wrong, but the testing ExecutionEngine returns VALID by default. + """ + execution_payload = build_empty_execution_payload(spec, state) + + opaque_tx, _, blob_kzg_commitments, _ = get_sample_blob_tx(spec, blob_count=2, rng=Random(1111)) + blob_kzg_commitments = [] # incorrect count + + execution_payload.transactions = [opaque_tx] + execution_payload.block_hash = compute_el_block_hash(spec, execution_payload, state) + + yield from run_execution_payload_processing(spec, state, execution_payload, blob_kzg_commitments) + + @with_deneb_and_later @spec_state_test def test_incorrect_commitments_order(spec, state): @@ -202,6 +219,26 @@ def test_incorrect_commitments_order(spec, state): yield from run_execution_payload_processing(spec, state, execution_payload, blob_kzg_commitments) +@with_deneb_and_later +@spec_state_test +def test_incorrect_transaction_no_blobs_but_with_commitments(spec, state): + """ + The versioned hashes are wrong, but the testing ExecutionEngine returns VALID by default. + """ + execution_payload = build_empty_execution_payload(spec, state) + + # the blob transaction is invalid, because the EL verifies that the tx contains at least one blob + # therefore the EL should reject it, but the CL should not reject the block regardless + opaque_tx, _, _, _ = get_sample_blob_tx(spec, blob_count=0, rng=Random(1111)) + _, _, blob_kzg_commitments, _ = get_sample_blob_tx(spec, blob_count=2, rng=Random(1112)) + + execution_payload.transactions = [opaque_tx] + execution_payload.block_hash = compute_el_block_hash(spec, execution_payload, state) + + # the transaction doesn't contain any blob, but commitments are provided + yield from run_execution_payload_processing(spec, state, execution_payload, blob_kzg_commitments) + + @with_deneb_and_later @spec_state_test def test_incorrect_block_hash(spec, state): diff --git a/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/test_blocks.py b/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/test_blocks.py index 5a4b98c3c8..e5b07cd3dd 100644 --- a/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/test_blocks.py +++ b/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/test_blocks.py @@ -19,6 +19,7 @@ ) from eth2spec.test.helpers.withdrawals import ( set_eth1_withdrawal_credential_with_balance, + set_compounding_withdrawal_credential_with_balance, ) @@ -172,3 +173,81 @@ def test_cl_exit_and_el_withdrawal_request_in_same_block(spec, state): yield 'post', state assert state.validators[validator_index].exit_epoch < spec.FAR_FUTURE_EPOCH + + +@with_electra_and_later +@spec_state_test +def test_multiple_el_partial_withdrawal_requests_same_validator(spec, state): + # move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit + state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH + + validator_index = 0 + address = b'\x22' * 20 + balance = spec.MIN_ACTIVATION_BALANCE + 2000000000 + set_compounding_withdrawal_credential_with_balance(spec, state, validator_index, balance, balance, address) + + assert state.validators[validator_index].exit_epoch == spec.FAR_FUTURE_EPOCH + + yield 'pre', state + + validator_pubkey = state.validators[validator_index].pubkey + withdrawal_request_1 = spec.WithdrawalRequest( + source_address=address, + validator_pubkey=validator_pubkey, + amount=spec.Gwei(1), + ) + withdrawal_request_2 = spec.WithdrawalRequest( + source_address=address, + validator_pubkey=validator_pubkey, + amount=spec.Gwei(2), + ) + block = build_empty_block_for_next_slot(spec, state) + block.body.execution_requests.withdrawals = [withdrawal_request_1, withdrawal_request_2] + block.body.execution_payload.block_hash = compute_el_block_hash_for_block(spec, block) + signed_block = state_transition_and_sign_block(spec, state, block) + + yield 'blocks', [signed_block] + yield 'post', state + + assert len(state.pending_partial_withdrawals) == 2 + assert state.validators[validator_index].exit_epoch == spec.FAR_FUTURE_EPOCH + + +@with_electra_and_later +@spec_state_test +def test_multiple_el_partial_withdrawal_requests_different_validator(spec, state): + # move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit + state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH + + validator_indices = [1, 2] + addresses = [bytes([v * 0x11]) * 20 for v in validator_indices] + balances = [spec.MIN_ACTIVATION_BALANCE + v * 2000000000 for v in validator_indices] + + for validator_index, address, balance in zip(validator_indices, addresses, balances): + set_compounding_withdrawal_credential_with_balance(spec, state, validator_index, balance, balance, address) + assert state.validators[validator_index].exit_epoch == spec.FAR_FUTURE_EPOCH + + yield 'pre', state + + withdrawal_requests = [] + + for validator_index, address in zip(validator_indices, addresses): + validator_pubkey = state.validators[validator_index].pubkey + withdrawal_request = spec.WithdrawalRequest( + source_address=address, + validator_pubkey=validator_pubkey, + amount=spec.Gwei(validator_index), + ) + withdrawal_requests.append(withdrawal_request) + + block = build_empty_block_for_next_slot(spec, state) + block.body.execution_requests.withdrawals = withdrawal_requests + block.body.execution_payload.block_hash = compute_el_block_hash_for_block(spec, block) + signed_block = state_transition_and_sign_block(spec, state, block) + + yield 'blocks', [signed_block] + yield 'post', state + + assert len(state.pending_partial_withdrawals) == 2 + for validator_index in validator_indices: + assert state.validators[validator_index].exit_epoch == spec.FAR_FUTURE_EPOCH diff --git a/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/test_deposit_transition.py b/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/test_deposit_transition.py index a9c2c62814..f2d9a6f11a 100644 --- a/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/test_deposit_transition.py +++ b/tests/core/pyspec/eth2spec/test/electra/sanity/blocks/test_deposit_transition.py @@ -262,3 +262,35 @@ def test_deposit_transition__deposit_and_top_up_same_block(spec, state): assert state.pending_deposits[pre_pending_deposits].amount == block.body.deposits[0].data.amount amount_from_deposit = block.body.execution_requests.deposits[0].amount assert state.pending_deposits[pre_pending_deposits + 1].amount == amount_from_deposit + + +@with_phases([ELECTRA]) +@spec_state_test +def test_deposit_transition__deposit_with_same_pubkey_different_withdrawal_credentials(spec, state): + deposit_count = 1 + deposit_request_count = 4 + + state, block = prepare_state_and_block(spec, state, + deposit_cnt=deposit_count, + deposit_request_cnt=deposit_request_count) + + # pick 2 indices among deposit requests to have the same pubkey as the deposit + indices_with_same_pubkey = [1, 3] + for index in indices_with_same_pubkey: + block.body.execution_requests.deposits[index].pubkey = block.body.deposits[0].data.pubkey + # ensure top-up deposit request withdrawal credentials are different than the deposit + assert (block.body.execution_requests.deposits[index].withdrawal_credentials + != block.body.deposits[0].data.withdrawal_credentials) + + block.body.execution_payload.block_hash = compute_el_block_hash_for_block(spec, block) + + deposit_requests = block.body.execution_requests.deposits.copy() + + yield from run_deposit_transition_block(spec, state, block) + + assert len(state.pending_deposits) == deposit_request_count + deposit_count + for index in indices_with_same_pubkey: + assert state.pending_deposits[deposit_count + index].pubkey == deposit_requests[index].pubkey + # ensure withdrawal credentials are retained, rather than being made the same + assert (state.pending_deposits[deposit_count + index].withdrawal_credentials + == deposit_requests[index].withdrawal_credentials) diff --git a/tests/formats/README.md b/tests/formats/README.md index 4811595ba8..b19a6ecdca 100644 --- a/tests/formats/README.md +++ b/tests/formats/README.md @@ -3,6 +3,7 @@ This document defines the YAML format and structure used for consensus spec testing. ## Table of contents + * [About](#about) @@ -46,7 +47,6 @@ Test formats: - [`ssz_static`](./ssz_static/README.md) - More formats are planned, see tracking issues for CI/testing - ## Glossary - `generator`: a program that outputs one or more test-cases, each organized into a `config > runner > handler > suite` hierarchy. @@ -93,7 +93,6 @@ The aim is to provide clients with a well-defined scope of work to run a particu - Clients that are not complete in functionality can choose to ignore suites that use certain test-runners, or specific handlers of these test-runners. - Clients that are on older versions can test their work based on older releases of the generated tests, and catch up with newer releases when possible. - ## Test structure ``` @@ -152,7 +151,6 @@ Between all types of tests, a few formats are common: - **`.ssz_snappy`**: Like `.ssz`, but compressed with Snappy block compression. Snappy block compression is already applied to SSZ in consensus-layer gossip, available in client implementations, and thus chosen as compression method. - #### Special output parts ##### `meta.yaml` @@ -181,7 +179,6 @@ The format matches that of the `mainnet_config.yaml` and `minimal_config.yaml`, see the [`/configs`](../../configs/README.md#format) documentation. Config values that are introduced at a later fork may be omitted from tests of previous forks. - ## Config sourcing The constants configurations are located in: @@ -198,7 +195,6 @@ And copied by CI for testing purposes to: The first `` is a directory, which contains exactly all tests that make use of the given config. - ## Note for implementers The basic pattern for test-suite loading and running is: diff --git a/tests/formats/finality/README.md b/tests/formats/finality/README.md index af39f5c8ca..70d27dbe18 100644 --- a/tests/formats/finality/README.md +++ b/tests/formats/finality/README.md @@ -20,7 +20,6 @@ An SSZ-snappy encoded `BeaconState`, the state before running the block transiti Also available as `pre.ssz_snappy`. - ### `blocks_.yaml` A series of files, with `` in range `[0, blocks_count)`. Blocks need to be processed in order, @@ -34,7 +33,6 @@ Each block is also available as `blocks_.ssz_snappy` An SSZ-snappy encoded `BeaconState`, the state after applying the block transitions. - ## Condition The resulting state should match the expected `post` state, or if the `post` state is left blank, diff --git a/tests/formats/fork_choice/README.md b/tests/formats/fork_choice/README.md index 37d09f4787..9915df90db 100644 --- a/tests/formats/fork_choice/README.md +++ b/tests/formats/fork_choice/README.md @@ -3,6 +3,7 @@ The aim of the fork choice tests is to provide test coverage of the various components of the fork choice. ## Table of contents + @@ -190,6 +191,7 @@ should_override_forkchoice_update: { -- [New in Bellatrix] ``` For example: + ```yaml - checks: time: 192 diff --git a/tests/formats/genesis/initialization.md b/tests/formats/genesis/initialization.md index 9848e157d9..008b30ef07 100644 --- a/tests/formats/genesis/initialization.md +++ b/tests/formats/genesis/initialization.md @@ -11,7 +11,6 @@ eth1_block_hash: Bytes32 -- A `Bytes32` hex encoded, with prefix 0x. The root o eth1_timestamp: int -- An integer. The timestamp of the block, in seconds. ``` - ### `meta.yaml` A yaml file to help read the deposit count: diff --git a/tests/formats/genesis/validity.md b/tests/formats/genesis/validity.md index 15236c3ba3..a1bde295db 100644 --- a/tests/formats/genesis/validity.md +++ b/tests/formats/genesis/validity.md @@ -16,17 +16,14 @@ description: string -- Optional. Description of test case, purely for debuggi An SSZ-snappy encoded `BeaconState`, the state to validate as genesis candidate. - ### `is_valid.yaml` A boolean, true if the genesis state is deemed valid as to launch with, false otherwise. - ## Processing To process the data, call `is_valid_genesis_state(genesis)`. - ## Condition The result of calling `is_valid_genesis_state(genesis)` should match the expected `is_valid` boolean. diff --git a/tests/formats/operations/README.md b/tests/formats/operations/README.md index 7c3281e2c6..4734b55de1 100644 --- a/tests/formats/operations/README.md +++ b/tests/formats/operations/README.md @@ -24,7 +24,6 @@ An SSZ-snappy encoded operation object, e.g. a `ProposerSlashing`, or `Deposit`. An SSZ-snappy encoded `BeaconState`, the state after applying the operation. No value if operation processing is aborted. - ## Condition A handler of the `operations` test-runner should process these cases, diff --git a/tests/formats/rewards/README.md b/tests/formats/rewards/README.md index c7f3a9581b..47dc7e2b8d 100644 --- a/tests/formats/rewards/README.md +++ b/tests/formats/rewards/README.md @@ -5,6 +5,7 @@ There is no "change" factor, the rewards/penalties outputs are pure functions wi (See test condition documentation on how to run the tests.) `Deltas` is defined as: + ```python class Deltas(Container): rewards: List[Gwei, VALIDATOR_REGISTRY_LIMIT] diff --git a/tests/formats/sanity/blocks.md b/tests/formats/sanity/blocks.md index 7ea646b9e0..480adb1b3c 100644 --- a/tests/formats/sanity/blocks.md +++ b/tests/formats/sanity/blocks.md @@ -13,12 +13,10 @@ reveal_deadlines_setting: int -- see general test-format spec. blocks_count: int -- the number of blocks processed in this test. ``` - ### `pre.ssz_snappy` An SSZ-snappy encoded `BeaconState`, the state before running the block transitions. - ### `blocks_.ssz_snappy` A series of files, with `` in range `[0, blocks_count)`. Blocks need to be processed in order, @@ -30,7 +28,6 @@ Each file is a SSZ-snappy encoded `SignedBeaconBlock`. An SSZ-snappy encoded `BeaconState`, the state after applying the block transitions. - ## Condition The resulting state should match the expected `post` state, or if the `post` state is left blank, diff --git a/tests/formats/sanity/slots.md b/tests/formats/sanity/slots.md index f1b8a13219..953d2566b6 100644 --- a/tests/formats/sanity/slots.md +++ b/tests/formats/sanity/slots.md @@ -11,14 +11,12 @@ description: string -- Optional. Description of test case, purely for debuggi bls_setting: int -- see general test-format spec. ``` - ### `pre.ssz_snappy` An SSZ-snappy `BeaconState`, the state before running the transitions. Also available as `pre.ssz_snappy`. - ### `slots.yaml` An integer. The amount of slots to process (i.e. the difference in slots between pre and post), always a positive number. @@ -29,7 +27,6 @@ An SSZ-snappy `BeaconState`, the state after applying the transitions. Also available as `post.ssz_snappy`. - ### Processing The transition with pure time, no blocks, is known as `process_slots(state, slot)` in the spec. diff --git a/tests/formats/ssz_generic/README.md b/tests/formats/ssz_generic/README.md index 3545ab28c9..9e624f1ae1 100644 --- a/tests/formats/ssz_generic/README.md +++ b/tests/formats/ssz_generic/README.md @@ -23,7 +23,6 @@ The `ssz_generic` tests are split up into different handler, each specialized in - Containers - `containers` - ## Format For each type, a `valid` and an `invalid` suite is implemented. @@ -74,7 +73,6 @@ The `serialized` data should simply not be decoded without raising an error. Note that for some type declarations in the invalid suite, the type itself may technically be invalid. This is a valid way of detecting `invalid` data too. E.g. a 0-length basic vector. - ## Type declarations Most types are not as static, and can reasonably be constructed during test runtime from the test case name. @@ -97,7 +95,6 @@ Data: {length}: an unsigned integer ``` - ### `bitlist` ``` @@ -110,7 +107,6 @@ Data: {limit}: the list limit, in bits, of the bitlist. Does not include the length-delimiting bit in the serialized form. ``` - ### `bitvector` ``` diff --git a/tests/formats/ssz_static/core.md b/tests/formats/ssz_static/core.md index a198bbcaff..dd969c3f54 100644 --- a/tests/formats/ssz_static/core.md +++ b/tests/formats/ssz_static/core.md @@ -34,7 +34,6 @@ The SSZ-snappy encoded bytes. The same value as `serialized.ssz_snappy`, represented as YAML. - ## Condition A test-runner can implement the following assertions: @@ -46,7 +45,6 @@ A test-runner can implement the following assertions: and verify if the bytes match the original `serialized`. - Hash-tree-root: After parsing the `value` (or deserializing `serialized`), Hash-tree-root it: the output should match `root` - ## References **`serialized`**—[SSZ serialization](../../../ssz/simple-serialize.md#serialization) diff --git a/tests/formats/sync/README.md b/tests/formats/sync/README.md index ff9f8168cb..511900e815 100644 --- a/tests/formats/sync/README.md +++ b/tests/formats/sync/README.md @@ -1,3 +1,3 @@ # Sync tests -It re-uses the [fork choice test format](../fork_choice/README.md) to apply the test script. +It reuses the [fork choice test format](../fork_choice/README.md) to apply the test script. diff --git a/tests/generators/README.md b/tests/generators/README.md index 270d107ea5..f595a31043 100644 --- a/tests/generators/README.md +++ b/tests/generators/README.md @@ -14,7 +14,6 @@ An automated nightly tests release system, with a config filter applied, is bein - - [How to run generators](#how-to-run-generators) - [Cleaning](#cleaning) - [Running all test generators](#running-all-test-generators) @@ -25,8 +24,6 @@ An automated nightly tests release system, with a config filter applied, is bein - - ## How to run generators Prerequisites: @@ -52,7 +49,6 @@ make -j 4 gen_all The `-j N` flag makes the generators run in parallel, with `N` being the amount of cores. - ### Running a single generator The makefile auto-detects generators in the `tests/generators` directory and provides a tests-gen target (gen_) for each generator. See example: @@ -194,7 +190,6 @@ To add a new test generator that builds `New Tests`: However, if necessary (e.g. not using Python, or mixing in other languages), submit an issue, and it can be a special case. Do note that generators should be easy to maintain, lean, and based on the spec. - ## How to remove a test generator If a test generator is not needed anymore, undo the steps described above and make a new release: diff --git a/tests/generators/epoch_processing/README.md b/tests/generators/epoch_processing/README.md index c572993d23..203f93ec10 100644 --- a/tests/generators/epoch_processing/README.md +++ b/tests/generators/epoch_processing/README.md @@ -6,6 +6,3 @@ An epoch-processing test-runner can consume these sub-transition test-suites, and handle different kinds of epoch sub-transitions by processing the cases using the specified test handler. Information on the format of the tests can be found in the [epoch-processing test formats documentation](../../formats/epoch_processing/README.md). - - - diff --git a/tests/generators/operations/README.md b/tests/generators/operations/README.md index 234bb92a82..29f64295e0 100644 --- a/tests/generators/operations/README.md +++ b/tests/generators/operations/README.md @@ -7,6 +7,3 @@ An operation test-runner can consume these operation test-suites, and handle different kinds of operations by processing the cases using the specified test handler. Information on the format of the tests can be found in the [operations test formats documentation](../../formats/operations/README.md). - - - diff --git a/tests/generators/sanity/README.md b/tests/generators/sanity/README.md index 61979976db..9a5f5b25d6 100644 --- a/tests/generators/sanity/README.md +++ b/tests/generators/sanity/README.md @@ -3,6 +3,3 @@ Sanity tests cover regular state-transitions in a common block-list format, to ensure the basics work. Information on the format of the tests can be found in the [sanity test formats documentation](../../formats/sanity/README.md). - - -