diff --git a/.circleci/config.yml b/.circleci/config.yml index 33eb5edbb50..cbdf7256a4f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -5,7 +5,7 @@ orbs: executors: small_executor: docker: - - image: cimg/openjdk:17.0.7 + - image: cimg/openjdk:21.0.2 auth: &docker-auth # Don't panic, throw away account to avoid Docker rate limits when downloading. # Second reason we're doing this is so that forked PRs from external contributors works ie env vars aren't visible to forked PRs from within contexts @@ -27,7 +27,7 @@ executors: medium_executor: docker: - - image: cimg/openjdk:17.0.7 + - image: cimg/openjdk:21.0.2 auth: <<: *docker-auth resource_class: medium @@ -39,7 +39,7 @@ executors: medium_plus_executor: docker: - - image: cimg/openjdk:17.0.7 + - image: cimg/openjdk:21.0.2 auth: <<: *docker-auth resource_class: "medium+" @@ -50,7 +50,7 @@ executors: large_executor: docker: - - image: cimg/openjdk:17.0.7 + - image: cimg/openjdk:21.0.2 auth: <<: *docker-auth resource_class: large @@ -61,7 +61,7 @@ executors: machine_executor_amd64: machine: - image: ubuntu-2204:2023.07.2 # https://circleci.com/developer/machine/image/ubuntu-2204 + image: ubuntu-2204:2024.01.1 # https://circleci.com/developer/machine/image/ubuntu-2204 docker_layer_caching: true working_directory: ~/project environment: @@ -70,7 +70,7 @@ executors: machine_executor_arm64: machine: - image: ubuntu-2204:2023.07.2 # https://circleci.com/developer/machine/image/ubuntu-2204 + image: ubuntu-2204:2024.01.1 # https://circleci.com/developer/machine/image/ubuntu-2204 resource_class: arm.medium environment: architecture: "arm64" @@ -83,6 +83,21 @@ executors: <<: *docker-auth commands: + install_java_21: + description: "Install Java 21" + steps: + - run: + name: "Install Java 21" + command: | + sudo apt update + sudo apt install -y openjdk-21-jdk + if [ "$(uname -m)" = "aarch64" ]; then + ARCH="arm64" + else + ARCH="amd64" + fi + sudo update-alternatives --set java /usr/lib/jvm/java-21-openjdk-$ARCH/bin/java + sudo update-alternatives --set javac /usr/lib/jvm/java-21-openjdk-$ARCH/bin/javac prepare: description: "Prepare" steps: @@ -148,7 +163,7 @@ commands: name: "Publish Docker Images" command: | docker login --username "${DOCKER_USER_RW}" --password "${DOCKER_PASSWORD_RW}" - ./gradlew --no-daemon --parallel "-Pbranch=${CIRCLE_BRANCH}" uploadDocker + ./gradlew --no-daemon --parallel -Pbranch=${CIRCLE_BRANCH} -PincludeCommitHashInDockerTag=<< pipeline.parameters.include_commit_hash_in_docker_tag >> uploadDocker notify: description: "Notify Slack" @@ -157,6 +172,12 @@ commands: mentions: "team-centaur" fail_only: true only_for_branches: 'master' + +parameters: + include_commit_hash_in_docker_tag: + type: boolean + default: false + jobs: assemble: executor: large_executor @@ -204,7 +225,7 @@ jobs: no_output_timeout: 20m command: | $Env:JAVA_TOOL_OPTIONS = "-Xmx2g" - $Env:GRADLE_OPTS = "-Dorg.gradle.daemon=false -Dorg.gradle.parallel=true" + $Env:GRADLE_OPTS = "-Dorg.gradle.daemon=false -Dorg.gradle.parallel=true -Dorg.gradle.vfs.watch=false" cmd.exe /c gradlew.bat --no-daemon --parallel --build-cache - run: name: "Gather test artifacts" @@ -325,6 +346,7 @@ jobs: parallelism: 5 executor: machine_executor_amd64 steps: + - install_java_21 - prepare - attach_workspace: at: ~/project @@ -433,6 +455,7 @@ jobs: publishDockerAmd64: executor: machine_executor_amd64 steps: + - install_java_21 - prepare - attach_workspace: at: ~/project @@ -443,6 +466,7 @@ jobs: publishDockerArm64: executor: machine_executor_arm64 steps: + - install_java_21 - prepare - attach_workspace: at: ~/project @@ -458,7 +482,7 @@ jobs: - run: name: Create and publish docker manifest command: | - ./gradlew --no-daemon --parallel manifestDocker + ./gradlew --no-daemon --parallel -PincludeCommitHashInDockerTag=<< pipeline.parameters.include_commit_hash_in_docker_tag >> manifestDocker - notify extractAPISpec: @@ -497,7 +521,7 @@ jobs: paths: - .openapidoc/spec/teku.json - # longish story here: we store the openapi json spec in the `gh-pages` branch of teku on Github + # longish story here: we store the openapi json spec in the `gh-pages` branch of teku on Github # The reason we don't use GHA and instead use Circle to push to GHA is: # 1. We need assemble -> extractAPISpec -> publishAPISpec and this takes circa 10 mins to build in GHA, # 2. We publish artifacts (openapi, docker, binaries etc) only after ALL tests and we can't check for all the jobs passing to kick this one off @@ -543,6 +567,8 @@ workflows: tags: <<: *filters-release-tags - windowsBuild: + requires: + - spotless filters: tags: <<: *filters-release-tags diff --git a/.codespell/.codespellrc b/.codespell/.codespellrc new file mode 100644 index 00000000000..5255128dffb --- /dev/null +++ b/.codespell/.codespellrc @@ -0,0 +1,5 @@ +[codespell] +skip = .git,package-lock.json,LOG.old.* +count = +quiet-level = 3 +ignore-words = ./.codespell/wordlist.txt \ No newline at end of file diff --git a/.codespell/wordlist.txt b/.codespell/wordlist.txt new file mode 100644 index 00000000000..230f1dedcd0 --- /dev/null +++ b/.codespell/wordlist.txt @@ -0,0 +1,7 @@ +afterall +errorprone +vertx +dout +interruptors +bu +socio-economic diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 2c92efc4f4b..22a7cd32594 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -33,47 +33,50 @@ jobs: fail-fast: false matrix: language: [ 'java' ] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] + # CodeQL supports [ 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' ] + # Use only 'java-kotlin' to analyze code written in Java, Kotlin or both + # Use only 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Java - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: adopt - java-version: 17 + java-version: 21 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. # By default, queries listed here will override any specified in a config file. # Prefix the list here with "+" to use these queries and those in the config file. - # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs queries: security-extended,security-and-quality - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v2 + uses: github/codeql-action/autobuild@v3 # ℹ️ Command-line programs to run using the OS shell. # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun - # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language + # If the Autobuild fails above, remove it and uncomment the following three lines. + # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. - #- run: | - # make bootstrap - # make release + # - run: | + # echo "Run, Build Application using script" + # ./location_of_script_within_repo/buildscript.sh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 + with: + category: "/language:${{matrix.language}}" diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml new file mode 100644 index 00000000000..1511fd18304 --- /dev/null +++ b/.github/workflows/codespell.yml @@ -0,0 +1,23 @@ +# A Github action that uses codespell to check spell. +# .codespell/.codespellrc is a config file. +# .codespell/wordlist.txt is a list of words that will ignore word checks. +# More details please check the following link: +# https://github.com/codespell-project/codespell + +name: Codespell + +on: pull_request + +jobs: + codespell: + runs-on: ubuntu-latest + + steps: + - name: Checkout the repository + uses: actions/checkout@v4 + + - name: Install prerequisites + run: pip install codespell + + - name: Spell check + run: codespell --config=./.codespell/.codespellrc \ No newline at end of file diff --git a/.github/workflows/gradle-wrapper-validation.yml b/.github/workflows/gradle-wrapper-validation.yml index c354d462148..5ba3b4e2ee2 100644 --- a/.github/workflows/gradle-wrapper-validation.yml +++ b/.github/workflows/gradle-wrapper-validation.yml @@ -6,5 +6,5 @@ jobs: name: "Validation" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: gradle/wrapper-validation-action@v1 \ No newline at end of file + - uses: actions/checkout@v4 + - uses: gradle/wrapper-validation-action@v2 \ No newline at end of file diff --git a/.github/workflows/test-path-check.yml b/.github/workflows/test-path-check.yml index 3a81ac72b1b..c6764be6185 100644 --- a/.github/workflows/test-path-check.yml +++ b/.github/workflows/test-path-check.yml @@ -6,6 +6,6 @@ jobs: name: "Check" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Check test paths run: ./scripts/testcheck.sh \ No newline at end of file diff --git a/.gitignore b/.gitignore index 6699b1f4ca1..fbdc1449e64 100644 --- a/.gitignore +++ b/.gitignore @@ -58,9 +58,4 @@ eth-reference-tests/src/referenceTest/resources/consensus-spec-tests/ .jqwik-database /teku.db -node_modules - -/test-network/grafana/data -/test-network/grafana/logs -/test-network/grafana/provisioning/dashboards/teku-dashboard-grafana.json -/test-network/data/ \ No newline at end of file +node_modules \ No newline at end of file diff --git a/.openapidoc/README.md b/.openapidoc/README.md index f2af72784c3..94c89918883 100644 --- a/.openapidoc/README.md +++ b/.openapidoc/README.md @@ -4,7 +4,7 @@ This directory contains NodeJS project which publishes Teku OpenAPI specificatio [`gh-pages`](https://github.com/Consensys/teku/tree/gh-pages) branch via CI job after tests are green. See `publishOpenApiSpec` job in `.circleci/config.yml`. -The actual up to date generated doc is available at https://consensys.github.io/teku/ +The actual up-to-date generated doc is available at https://consensys.github.io/teku/ ## Procedure diff --git a/.openapidoc/package-lock.json b/.openapidoc/package-lock.json index 6add7a2bd8b..48abe734450 100644 --- a/.openapidoc/package-lock.json +++ b/.openapidoc/package-lock.json @@ -9,7 +9,7 @@ "version": "1.0.0", "license": "Apache-2.0", "dependencies": { - "gh-pages": "^3.1.0", + "gh-pages": "^5.0.0", "git-url-parse": "^13.1.0", "js-yaml": "^4.1.0", "node-fetch": "^3.3.1" @@ -296,12 +296,9 @@ } }, "node_modules/async": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", - "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", - "dependencies": { - "lodash": "^4.17.14" - } + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" }, "node_modules/balanced-match": { "version": "1.0.2", @@ -433,9 +430,9 @@ } }, "node_modules/email-addresses": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-3.1.0.tgz", - "integrity": "sha512-k0/r7GrWVL32kZlGwfPNgB2Y/mMXVTq/decgLczm/j34whdaspNrZO8CnXPf1laaHxI6ptUlsnAxN+UAPw+fzg==" + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-5.0.0.tgz", + "integrity": "sha512-4OIPYlA6JXqtVn8zpHpGiI7vE6EQOAg16aGnDMIAlZVinnoZ8208tW1hAbjWydgN/4PLTT9q+O1K6AH/vALJGw==" }, "node_modules/emoji-regex": { "version": "8.0.0", @@ -847,13 +844,13 @@ "dev": true }, "node_modules/gh-pages": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-3.2.3.tgz", - "integrity": "sha512-jA1PbapQ1jqzacECfjUaO9gV8uBgU6XNMV0oXLtfCX3haGLe5Atq8BxlrADhbD6/UdG9j6tZLWAkAybndOXTJg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-5.0.0.tgz", + "integrity": "sha512-Nqp1SjkPIB94Xw/3yYNTUL+G2dxlhjvv1zeN/4kMC1jfViTEqhtVz/Ba1zSXHuvXCN9ADNS1dN4r5/J/nZWEQQ==", "dependencies": { - "async": "^2.6.1", + "async": "^3.2.4", "commander": "^2.18.0", - "email-addresses": "^3.0.1", + "email-addresses": "^5.0.0", "filenamify": "^4.3.0", "find-cache-dir": "^3.3.1", "fs-extra": "^8.1.0", @@ -1112,11 +1109,6 @@ "node": ">=8" } }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -1945,12 +1937,9 @@ "dev": true }, "async": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", - "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", - "requires": { - "lodash": "^4.17.14" - } + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" }, "balanced-match": { "version": "1.0.2", @@ -2053,9 +2042,9 @@ } }, "email-addresses": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-3.1.0.tgz", - "integrity": "sha512-k0/r7GrWVL32kZlGwfPNgB2Y/mMXVTq/decgLczm/j34whdaspNrZO8CnXPf1laaHxI6ptUlsnAxN+UAPw+fzg==" + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-5.0.0.tgz", + "integrity": "sha512-4OIPYlA6JXqtVn8zpHpGiI7vE6EQOAg16aGnDMIAlZVinnoZ8208tW1hAbjWydgN/4PLTT9q+O1K6AH/vALJGw==" }, "emoji-regex": { "version": "8.0.0", @@ -2367,13 +2356,13 @@ "dev": true }, "gh-pages": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-3.2.3.tgz", - "integrity": "sha512-jA1PbapQ1jqzacECfjUaO9gV8uBgU6XNMV0oXLtfCX3haGLe5Atq8BxlrADhbD6/UdG9j6tZLWAkAybndOXTJg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-5.0.0.tgz", + "integrity": "sha512-Nqp1SjkPIB94Xw/3yYNTUL+G2dxlhjvv1zeN/4kMC1jfViTEqhtVz/Ba1zSXHuvXCN9ADNS1dN4r5/J/nZWEQQ==", "requires": { - "async": "^2.6.1", + "async": "^3.2.4", "commander": "^2.18.0", - "email-addresses": "^3.0.1", + "email-addresses": "^5.0.0", "filenamify": "^4.3.0", "find-cache-dir": "^3.3.1", "fs-extra": "^8.1.0", @@ -2574,11 +2563,6 @@ "p-locate": "^4.1.0" } }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", diff --git a/.openapidoc/package.json b/.openapidoc/package.json index 559babacf3d..ffd3f8db272 100644 --- a/.openapidoc/package.json +++ b/.openapidoc/package.json @@ -12,7 +12,7 @@ }, "main": "./publish.js", "dependencies": { - "gh-pages": "^3.1.0", + "gh-pages": "^5.0.0", "git-url-parse": "^13.1.0", "js-yaml": "^4.1.0", "node-fetch": "^3.3.1" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7a7d4b1c442..6ce2a650e03 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -31,7 +31,9 @@ You'll find us on [Discord] and that's the fastest way to get an answer. ### Your first code contribution Start by looking through the 'good first issue' and 'help wanted' issues: * [Good First Issue][search-label-good-first-issue] - issues which should only require a few lines of code, and a test or two. -* [Help wanted issues][search-label-help-wanted] - issues which are a bit more involved than `good first issue` issues. +* [Help wanted issues][search-label-help-wanted] - issues that are a bit more involved than `good first issue` issues. + +Please keep in mind that we do not accept non-code contributions like fixing comments, typos or some other trivial fixes. Although we appreciate the extra help, managing lots of these small contributions is unfeasible, and puts extra pressure in our continuous delivery systems (running all tests, etc). Feel free to open an issue pointing any of those errors and we will batch them into a single change. ### Local Development The codebase is maintained using the "*contributor workflow*" where everyone without exception contributes patch proposals using "*pull-requests*". This facilitates social contribution, easy testing and peer review. @@ -47,7 +49,7 @@ In general a commit serves a single purpose and diffs should be easily comprehen ### Architectural Best Practices -Questions on architectural best practices will be guided by the principles set forth in [Effective Java](http://index-of.es/Java/Effective%20Java.pdf) by Joshua Bloch +Questions on architectural best practices will be guided by the principles set forth in Effective Java by Joshua Bloch ### Automated Test coverage All code submissions must be accompanied by appropriate automated tests. The goal is to provide confidence in the code’s robustness, while avoiding redundant tests. @@ -79,7 +81,7 @@ Following these guidelines helps maintainers and the community understand your r Explain the problem and include additional details to help maintainers reproduce the problem: * **Use a clear and descriptive title** for the issue to identify the problem. -* **Describe the exact steps which reproduce the problem** in as many details as possible. For example, start by explaining how you started Teku, e.g. which command exactly you used in the terminal, or how you started it otherwise. +* **Describe the exact steps which reproduce the problem** in as many details as possible. For example, start by explaining how you started Teku, e.g. which command exactly you used in the terminal, or how you started it otherwise. * **Provide specific examples to demonstrate the steps**. Include links to files or GitHub projects, or copy/pasteable snippets, which you use in those examples. If you're providing snippets in the issue, use [Markdown code blocks](https://help.github.com/articles/markdown-basics/#multiple-lines). * **Describe the behavior you observed after following the steps** and point out what exactly is the problem with that behavior. * **Explain which behavior you expected to see instead and why.** diff --git a/README.md b/README.md index 7992cbfd124..6da942c6995 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,8 @@ [![Twitter Follow](https://img.shields.io/twitter/follow/Teku_Consensys)](https://twitter.com/Teku_Consensys) [![GitPOAP Badge](https://public-api.gitpoap.io/v1/repo/ConsenSys/teku/badge)](https://www.gitpoap.io/gh/ConsenSys/teku) -Teku is an open-source Ethereum consensus client written in Java and containing a full beacon node and validator client implementation. +Teku is an open-source Ethereum consensus client written in Java and containing a full beacon node and validator client implementation. + See the [Changelog](https://github.com/Consensys/teku/releases) for details of the latest releases and upcoming breaking changes. ## Useful links @@ -52,9 +53,9 @@ Release notifications are available via: ### Install Prerequisites -* Java 17+ +* Java 21+ -Note: Official builds of Teku are performed with Java 17. +Note: Official builds of Teku are performed with Java 21. Building on a more recent version of Java is supported, but the resulting build will not work on earlier versions of Java. diff --git a/beacon/sync/src/main/java/tech/pegasys/teku/beacon/sync/forward/singlepeer/PeerSync.java b/beacon/sync/src/main/java/tech/pegasys/teku/beacon/sync/forward/singlepeer/PeerSync.java index 03f99e8a4d0..93c9a577a21 100644 --- a/beacon/sync/src/main/java/tech/pegasys/teku/beacon/sync/forward/singlepeer/PeerSync.java +++ b/beacon/sync/src/main/java/tech/pegasys/teku/beacon/sync/forward/singlepeer/PeerSync.java @@ -250,8 +250,7 @@ private SafeFuture executeSync( private PeerSyncResult handleFailedRequestToPeer( final Eth2Peer peer, final PeerStatus peerStatus, final Throwable err) { final Throwable rootException = Throwables.getRootCause(err); - if (rootException instanceof FailedBlockImportException) { - final FailedBlockImportException importException = (FailedBlockImportException) rootException; + if (rootException instanceof FailedBlockImportException importException) { final FailureReason reason = importException.getResult().getFailureReason(); final SignedBeaconBlock block = importException.getBlock(); diff --git a/beacon/validator/src/test/java/tech/pegasys/teku/validator/coordinator/AbstractBlockFactoryTest.java b/beacon/validator/src/test/java/tech/pegasys/teku/validator/coordinator/AbstractBlockFactoryTest.java index 5c654b7becf..f8d090b5e83 100644 --- a/beacon/validator/src/test/java/tech/pegasys/teku/validator/coordinator/AbstractBlockFactoryTest.java +++ b/beacon/validator/src/test/java/tech/pegasys/teku/validator/coordinator/AbstractBlockFactoryTest.java @@ -369,7 +369,8 @@ protected void prepareValidPayload(final Spec spec, final BeaconState genericSta state, beaconStateAccessors.getCurrentEpoch(state))) .timestamp( miscHelpers.computeTimeAtSlot(state.getGenesisTime(), state.getSlot())) - .withdrawals(Collections::emptyList)); + .withdrawals(Collections::emptyList) + .executionWitness(dataStructureUtil::randomExecutionWitness)); executionPayloadHeader = SchemaDefinitionsBellatrix.required(spec.getGenesisSpec().getSchemaDefinitions()) .getExecutionPayloadHeaderSchema() diff --git a/build.gradle b/build.gradle index 49462ba079a..8e7231d85d2 100644 --- a/build.gradle +++ b/build.gradle @@ -22,11 +22,11 @@ buildscript { plugins { id 'com.diffplug.spotless' version '6.25.0' id 'com.github.ben-manes.versions' version '0.51.0' - id 'com.github.jk1.dependency-license-report' version '2.5' - id 'io.spring.dependency-management' version '1.1.4' - id 'net.ltgt.errorprone' version '3.1.0' apply false - id 'de.undercouch.download' version '5.5.0' - id 'org.ajoberstar.grgit' version '5.2.1' + id 'com.github.jk1.dependency-license-report' version '2.8' + id 'io.spring.dependency-management' version '1.1.6' + id 'net.ltgt.errorprone' version '4.0.1' apply false + id 'de.undercouch.download' version '5.6.0' + id 'org.ajoberstar.grgit' version '5.2.2' } rootProject.version = calculatePublishVersion() @@ -114,6 +114,19 @@ dependencyRules { } } +def isNonStable = { String version -> + def stableKeyword = ['RELEASE', 'FINAL', 'GA'].any { keyword -> version.toUpperCase().contains(keyword) } + def regex = /^[0-9,.v-]+(-r)?$/ + return !stableKeyword && !(version ==~ regex) +} + +// reject all non stable versions +tasks.named("dependencyUpdates").configure { + rejectVersionIf { + isNonStable(it.candidate.version) + } +} + allprojects { apply plugin: 'java-library' apply plugin: 'java-test-fixtures' @@ -130,8 +143,13 @@ allprojects { jar.preserveFileTimestamps = false } - sourceCompatibility = '17' - targetCompatibility = '17' + java { + sourceCompatibility = JavaVersion.VERSION_21 + } + + java { + targetCompatibility = JavaVersion.VERSION_21 + } repositories { mavenLocal() @@ -244,7 +262,9 @@ allprojects { check('PackageLocation', net.ltgt.gradle.errorprone.CheckSeverity.WARN) } options.encoding = 'UTF-8' + } + /* * Pass some system properties provided on the gradle command line to test executions for * convenience. @@ -295,12 +315,15 @@ allprojects { } } -def refTestVersion = 'v1.4.0-beta.7-hotfix' // Arbitrary change to refresh cache number: 1 +def refTestVersion = 'v1.5.0-alpha.3' def blsRefTestVersion = 'v0.1.2' +def slashingProtectionInterchangeRefTestVersion = 'v5.3.0' def refTestBaseUrl = 'https://github.com/ethereum/consensus-spec-tests/releases/download' def blsRefTestBaseUrl = 'https://github.com/ethereum/bls12-381-tests/releases/download' +def slashingProtectionInterchangeRefTestBaseUrl = 'https://github.com/eth-clients/slashing-protection-interchange-tests/archive/refs/tags' def refTestDownloadDir = "${buildDir}/refTests/${refTestVersion}" def blsRefTestDownloadDir = "${buildDir}/blsRefTests/${blsRefTestVersion}" +def slashingProtectionInterchangeRefTestDownloadDir = "${buildDir}/slashingProtectionInterchangeRefTests/${slashingProtectionInterchangeRefTestVersion}" def refTestExpandDir = "${project.rootDir}/eth-reference-tests/src/referenceTest/resources/consensus-spec-tests/" task downloadEthRefTests(type: Download) { @@ -321,7 +344,15 @@ task downloadBlsRefTests(type: Download) { overwrite false } -task downloadRefTests(dependsOn: [downloadEthRefTests, downloadBlsRefTests]) +task downloadSlashingProtectionInterchangeRefTests(type: Download) { + src([ + "${slashingProtectionInterchangeRefTestBaseUrl}/${slashingProtectionInterchangeRefTestVersion}.tar.gz" + ]) + dest "${slashingProtectionInterchangeRefTestDownloadDir}/slashing-protection-interchange-tests.tar.gz" + overwrite false +} + +task downloadRefTests(dependsOn: [downloadEthRefTests, downloadBlsRefTests, downloadSlashingProtectionInterchangeRefTests]) task cleanRefTestsGeneral(type: Delete) { delete "${refTestExpandDir}/tests/general" @@ -359,8 +390,25 @@ task expandRefTestsBls(type: Copy, dependsOn: [cleanRefTestsBls, downloadBlsRefT into "${refTestExpandDir}/tests/bls" } -task expandRefTests(dependsOn: [expandRefTestsGeneral, expandRefTestsMainnet, expandRefTestsMinimal, expandRefTestsBls]) -task cleanRefTests(dependsOn: [cleanRefTestsGeneral, cleanRefTestsMainnet, cleanRefTestsMinimal, cleanRefTestsBls]) +task cleanRefTestsSlashingProtectionInterchange(type: Delete) { + delete "${refTestExpandDir}/tests/slashing-protection-interchange" +} + +task expandRefTestsSlashingProtectionInterchange(type: Copy, dependsOn: [cleanRefTestsSlashingProtectionInterchange, downloadSlashingProtectionInterchangeRefTests]) { + from { + tarTree("${slashingProtectionInterchangeRefTestDownloadDir}/slashing-protection-interchange-tests.tar.gz").matching { + include "**/tests/generated/*.json" + // flatten + eachFile { FileCopyDetails fcp -> + fcp.path = fcp.name + } + } + } + into "${refTestExpandDir}/tests/slashing-protection-interchange" +} + +task expandRefTests(dependsOn: [expandRefTestsGeneral, expandRefTestsMainnet, expandRefTestsMinimal, expandRefTestsBls, expandRefTestsSlashingProtectionInterchange]) +task cleanRefTests(dependsOn: [cleanRefTestsGeneral, cleanRefTestsMainnet, cleanRefTestsMinimal, cleanRefTestsBls, cleanRefTestsSlashingProtectionInterchange]) task deploy() {} @@ -496,7 +544,7 @@ tasks.register("dockerDistUntar") { } def dockerImage = "consensys/teku" -def dockerJdkVariants = [ "jdk17", "jdk21" ] +def dockerJdkVariants = [ "jdk21" ] def dockerBuildDir = "build/docker-teku/" def executableAndArg = System.getProperty('os.name').toLowerCase().contains('windows') ? ["cmd", "/c"] : ["sh", "-c"] @@ -505,13 +553,15 @@ task distDocker { dependsOn dockerDistUntar def dockerBuildVersion = 'develop' doLast { + def includeCommitHashInDockerTag = project.hasProperty('includeCommitHashInDockerTag') && project.property('includeCommitHashInDockerTag').toBoolean() + def commitHashTag = includeCommitHashInDockerTag ? '-' + grgit.head().getAbbreviatedId() : '' for (def variant in dockerJdkVariants) { copy { from file("${projectDir}/docker/${variant}/Dockerfile") into(dockerBuildDir) } exec { - def image = "${dockerImage}:${dockerBuildVersion}-${variant}" + def image = "${dockerImage}:${dockerBuildVersion}-${variant}${commitHashTag}" workingDir dockerBuildDir executable executableAndArg[0] args executableAndArg[1], "docker build --pull --build-arg BUILD_DATE=${buildTime()} --build-arg VERSION=${dockerBuildVersion} --build-arg VCS_REF=${getCheckedOutGitCommitHash()} -t ${image} ." @@ -520,7 +570,7 @@ task distDocker { // tag the "default" (which is the variant in the zero position) exec { executable executableAndArg[0] - args executableAndArg[1], "docker tag ${dockerImage}:${dockerBuildVersion}-${dockerJdkVariants[0]} ${dockerImage}:${dockerBuildVersion}" + args executableAndArg[1], "docker tag ${dockerImage}:${dockerBuildVersion}-${dockerJdkVariants[0]}${commitHashTag} ${dockerImage}:${dockerBuildVersion}${commitHashTag}" } } } @@ -542,12 +592,14 @@ task uploadDocker { } doLast { + def includeCommitHashInDockerTag = project.hasProperty('includeCommitHashInDockerTag') && project.property('includeCommitHashInDockerTag').toBoolean() + def commitHashTag = includeCommitHashInDockerTag ? '-' + grgit.head().getAbbreviatedId() : '' for (def variant in dockerJdkVariants) { def tags = "" - versionPrefixes.forEach { prefix -> tags += "-t ${dockerImage}:${prefix.trim()}-${variant}-${architecture} "} + versionPrefixes.forEach { prefix -> tags += "-t ${dockerImage}:${prefix.trim()}-${variant}-${architecture}${commitHashTag} "} if (variant == dockerJdkVariants[0]) { - versionPrefixes.forEach { prefix -> tags += "-t ${dockerImage}:${prefix.trim()}-${architecture} "} + versionPrefixes.forEach { prefix -> tags += "-t ${dockerImage}:${prefix.trim()}-${architecture}${commitHashTag} "} } copy { @@ -589,6 +641,8 @@ task manifestDocker { } doLast { + def includeCommitHashInDockerTag = project.hasProperty('includeCommitHashInDockerTag') && project.property('includeCommitHashInDockerTag').toBoolean() + def commitHashTag = includeCommitHashInDockerTag ? '-' + grgit.head().getAbbreviatedId() : '' for (def variant in dockerJdkVariants) { def tags = [] def cmd = "" @@ -599,10 +653,10 @@ task manifestDocker { } for (def tag in tags) { - platforms.forEach { platform -> cmd += "${tag}-${platform} " } + platforms.forEach { platform -> cmd += "${tag}-${platform}${commitHashTag} " } exec { executable executableAndArg[0] - args executableAndArg[1], "docker manifest create ${tag} ${cmd} && docker manifest push ${tag}" + args executableAndArg[1], "docker manifest create ${tag}${commitHashTag} ${cmd} && docker manifest push ${tag}${commitHashTag}" } } } diff --git a/dashboard/teku-dashboard-grafana.json b/dashboard/teku-dashboard-grafana.json deleted file mode 100644 index 55012559188..00000000000 --- a/dashboard/teku-dashboard-grafana.json +++ /dev/null @@ -1,738 +0,0 @@ -{ - "__inputs": [ - { - "name": "DS_PROMETHEUS", - "label": "Prometheus", - "description": "", - "type": "datasource", - "pluginId": "prometheus", - "pluginName": "Prometheus" - } - ], - "__requires": [ - { - "type": "grafana", - "id": "grafana", - "name": "Grafana", - "version": "6.2.4" - }, - { - "type": "panel", - "id": "graph", - "name": "Graph", - "version": "" - }, - { - "type": "datasource", - "id": "prometheus", - "name": "Prometheus", - "version": "1.0.0" - }, - { - "type": "panel", - "id": "table", - "name": "Table", - "version": "" - } - ], - "annotations": { - "list": [ - { - "$$hashKey": "object:215", - "builtIn": 1, - "datasource": "-- Grafana --", - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "name": "Annotations & Alerts", - "type": "dashboard" - } - ] - }, - "description": "Provides an overview of Teku nodes", - "editable": true, - "gnetId": null, - "graphTooltip": 0, - "id": 5, - "iteration": 1588132665027, - "links": [], - "panels": [ - { - "collapsed": false, - "datasource": null, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 0 - }, - "id": 16, - "panels": [], - "title": "Beacon Node", - "type": "row" - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "Prometheus", - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 10, - "w": 8, - "x": 0, - "y": 1 - }, - "hiddenSeries": false, - "id": 2, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "maxPerRow": 24, - "nullPointMode": "null", - "options": { - "dataLinks": [] - }, - "percentage": false, - "pointradius": 2, - "points": false, - "renderer": "flot", - "repeat": null, - "repeatDirection": "h", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "beacon_epoch", - "interval": "", - "legendFormat": "", - "refId": "A" - }, - { - "expr": "beacon_current_justified_epoch", - "interval": "", - "legendFormat": "", - "refId": "C" - }, - { - "expr": "beacon_previous_justified_epoch", - "interval": "", - "legendFormat": "", - "refId": "D" - }, - { - "expr": "beacon_finalized_epoch", - "interval": "", - "legendFormat": "", - "refId": "B" - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Epoch", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": null, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 10, - "w": 8, - "x": 8, - "y": 1 - }, - "hiddenSeries": false, - "id": 6, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", - "options": { - "dataLinks": [] - }, - "percentage": false, - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "beacon_slot", - "instant": false, - "interval": "", - "legendFormat": "", - "refId": "A" - }, - { - "expr": "beacon_head_slot", - "interval": "", - "legendFormat": "", - "refId": "B" - } - ], - "thresholds": [ - { - "colorMode": "critical", - "fill": true, - "line": true, - "op": "gt", - "yaxis": "left" - } - ], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Slot", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": null, - "description": "The number of peers currently connected.", - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 10, - "w": 8, - "x": 16, - "y": 1 - }, - "hiddenSeries": false, - "id": 22, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", - "options": { - "dataLinks": [] - }, - "percentage": false, - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "libp2p_peers", - "interval": "", - "intervalFactor": 3, - "legendFormat": "", - "refId": "A" - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Peers", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "decimals": 0, - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } - }, - { - "collapsed": false, - "datasource": null, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 11 - }, - "id": 14, - "panels": [], - "title": "System", - "type": "row" - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": null, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 9, - "w": 8, - "x": 0, - "y": 12 - }, - "hiddenSeries": false, - "id": 12, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "dataLinks": [] - }, - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "irate(process_cpu_seconds_total{instance=~\"$system\"}[1m])", - "format": "time_series", - "interval": "", - "intervalFactor": 3, - "legendFormat": "CPU Time IRate [{{instance}}]", - "refId": "A" - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "CPU", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": null, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 9, - "w": 8, - "x": 8, - "y": 12 - }, - "hiddenSeries": false, - "id": 10, - "legend": { - "alignAsTable": true, - "avg": true, - "current": true, - "max": true, - "min": true, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "dataLinks": [] - }, - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "jvm_memory_bytes_used{instance=~\"$system\", area=\"heap\"} + ignoring(area) jvm_memory_bytes_used{instance=~\"$system\", area=\"nonheap\"}", - "format": "time_series", - "intervalFactor": 5, - "legendFormat": "{{instance}}", - "refId": "A" - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Memory Used", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "decbytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "Prometheus", - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 9, - "w": 8, - "x": 16, - "y": 12 - }, - "hiddenSeries": false, - "id": 8, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [ - { - "title": "", - "url": "" - } - ], - "nullPointMode": "null", - "options": { - "dataLinks": [] - }, - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "rate(jvm_gc_collection_seconds_sum{instance=~\"$system\"}[1m])", - "format": "time_series", - "interval": "", - "intervalFactor": 5, - "legendFormat": "{{gc}} [{{instance}}]", - "metric": "jvm_gc_collection_seconds_sum", - "refId": "A", - "step": 10 - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "GC time", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "decimals": null, - "format": "percentunit", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } - } - ], - "refresh": "10s", - "schemaVersion": 22, - "style": "dark", - "tags": [ - "ethereum", - "teku", - "eth2.0" - ], - "templating": { - "list": [ - { - "allValue": null, - "current": { - "text": "All", - "value": [ - "$__all" - ] - }, - "datasource": "Prometheus", - "definition": "query_result(beacon_slot)", - "hide": 0, - "includeAll": true, - "index": -1, - "label": "System", - "multi": true, - "name": "system", - "options": [], - "query": "query_result(beacon_slot)", - "refresh": 2, - "regex": "/instance=\"([^\"]*)\"/", - "skipUrlSync": false, - "sort": 5, - "tagValuesQuery": "", - "tags": [], - "tagsQuery": "", - "type": "query", - "useTags": false - } - ] - }, - "time": { - "from": "now-5m", - "to": "now" - }, - "timepicker": { - "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ] - }, - "timezone": "", - "title": "Teku Overview", - "uid": "JxLDWgqWy", - "variables": { - "list": [] - }, - "version": 2 -} diff --git a/data/beaconrestapi/src/integration-test/resources/tech/pegasys/teku/beaconrestapi/beacon/paths/_eth_v3_validator_blocks_{slot}.json b/data/beaconrestapi/src/integration-test/resources/tech/pegasys/teku/beaconrestapi/beacon/paths/_eth_v3_validator_blocks_{slot}.json index ac0790d1d6b..8d33030722a 100644 --- a/data/beaconrestapi/src/integration-test/resources/tech/pegasys/teku/beaconrestapi/beacon/paths/_eth_v3_validator_blocks_{slot}.json +++ b/data/beaconrestapi/src/integration-test/resources/tech/pegasys/teku/beaconrestapi/beacon/paths/_eth_v3_validator_blocks_{slot}.json @@ -1,6 +1,6 @@ { "get" : { - "tags" : [ "Experimental" ], + "tags" : [ "Validator", "Validator Required Api" ], "operationId" : "produceBlockV3", "summary" : "Produce a new block, without signature", "description" : "Requests a beacon node to produce a valid block, which can then be signed by a validator. The\nreturned block may be blinded or unblinded, depending on the current state of the network as\ndecided by the execution and beacon nodes.\nThe beacon node must return an unblinded block if it obtains the execution payload from its\npaired execution node. It must only return a blinded block if it obtains the execution payload\nheader from an MEV relay.\nMetadata in the response indicates the type of block produced, and the supported types of block\nwill be added to as forks progress.", diff --git a/data/beaconrestapi/src/main/java/tech/pegasys/teku/beaconrestapi/handlers/v3/validator/GetNewBlockV3.java b/data/beaconrestapi/src/main/java/tech/pegasys/teku/beaconrestapi/handlers/v3/validator/GetNewBlockV3.java index a1668ce7438..37613684af1 100644 --- a/data/beaconrestapi/src/main/java/tech/pegasys/teku/beaconrestapi/handlers/v3/validator/GetNewBlockV3.java +++ b/data/beaconrestapi/src/main/java/tech/pegasys/teku/beaconrestapi/handlers/v3/validator/GetNewBlockV3.java @@ -31,7 +31,8 @@ import static tech.pegasys.teku.infrastructure.http.RestApiConstants.HEADER_EXECUTION_PAYLOAD_BLINDED; import static tech.pegasys.teku.infrastructure.http.RestApiConstants.HEADER_EXECUTION_PAYLOAD_VALUE; import static tech.pegasys.teku.infrastructure.http.RestApiConstants.SLOT_PATH_DESCRIPTION; -import static tech.pegasys.teku.infrastructure.http.RestApiConstants.TAG_EXPERIMENTAL; +import static tech.pegasys.teku.infrastructure.http.RestApiConstants.TAG_VALIDATOR; +import static tech.pegasys.teku.infrastructure.http.RestApiConstants.TAG_VALIDATOR_REQUIRED; import static tech.pegasys.teku.infrastructure.json.types.CoreTypes.BOOLEAN_TYPE; import static tech.pegasys.teku.infrastructure.json.types.CoreTypes.UINT256_TYPE; @@ -90,7 +91,7 @@ private static EndpointMetadata getEndpointMetaData( + "header from an MEV relay.\n" + "Metadata in the response indicates the type of block produced, and the supported types of block\n" + "will be added to as forks progress.") - .tags(TAG_EXPERIMENTAL) + .tags(TAG_VALIDATOR, TAG_VALIDATOR_REQUIRED) .pathParam(SLOT_PARAMETER.withDescription(SLOT_PATH_DESCRIPTION)) .queryParamRequired(RANDAO_PARAMETER) .queryParam(GRAFFITI_PARAMETER) diff --git a/data/beaconrestapi/src/test/java/tech/pegasys/teku/beaconrestapi/handlers/v1/events/StubContext.java b/data/beaconrestapi/src/test/java/tech/pegasys/teku/beaconrestapi/handlers/v1/events/StubContext.java index aede946e151..6c42e778101 100644 --- a/data/beaconrestapi/src/test/java/tech/pegasys/teku/beaconrestapi/handlers/v1/events/StubContext.java +++ b/data/beaconrestapi/src/test/java/tech/pegasys/teku/beaconrestapi/handlers/v1/events/StubContext.java @@ -13,16 +13,22 @@ package tech.pegasys.teku.beaconrestapi.handlers.v1.events; +import io.javalin.config.Key; import io.javalin.http.Context; import io.javalin.http.HandlerType; import io.javalin.http.HttpStatus; +import io.javalin.json.JsonMapper; +import io.javalin.plugin.ContextPlugin; +import io.javalin.security.RouteRole; import jakarta.servlet.ServletOutputStream; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.InputStream; import java.util.Map; +import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.function.Supplier; +import java.util.stream.Stream; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -36,12 +42,6 @@ public StubContext(final HttpServletRequest req, final HttpServletResponse res) this.res = res; } - @Override - @SuppressWarnings("TypeParameterUnusedInFormals") - public T appAttribute(@NotNull final String s) { - return null; - } - @NotNull @Override public String endpointHandlerPath() { @@ -107,4 +107,41 @@ public Context result(@NotNull final InputStream inputStream) { public InputStream resultInputStream() { return null; } + + @Override + public T appData(@NotNull final Key key) { + return null; + } + + @NotNull + @Override + public JsonMapper jsonMapper() { + return null; + } + + @NotNull + @Override + public Context minSizeForCompression(final int i) { + return null; + } + + @NotNull + @Override + public Set routeRoles() { + return null; + } + + @NotNull + @Override + public Context skipRemainingHandlers() { + return null; + } + + @Override + public T with(@NotNull final Class> aClass) { + return null; + } + + @Override + public void writeJsonStream(@NotNull final Stream stream) {} } diff --git a/data/provider/src/main/java/tech/pegasys/teku/api/SchemaObjectProvider.java b/data/provider/src/main/java/tech/pegasys/teku/api/SchemaObjectProvider.java index c3d089d07cb..6aae6634831 100644 --- a/data/provider/src/main/java/tech/pegasys/teku/api/SchemaObjectProvider.java +++ b/data/provider/src/main/java/tech/pegasys/teku/api/SchemaObjectProvider.java @@ -36,6 +36,11 @@ import tech.pegasys.teku.api.schema.deneb.BeaconStateDeneb; import tech.pegasys.teku.api.schema.deneb.BlindedBeaconBlockBodyDeneb; import tech.pegasys.teku.api.schema.deneb.BlindedBlockDeneb; +import tech.pegasys.teku.api.schema.electra.BeaconBlockBodyElectra; +import tech.pegasys.teku.api.schema.electra.BeaconBlockElectra; +import tech.pegasys.teku.api.schema.electra.BeaconStateElectra; +import tech.pegasys.teku.api.schema.electra.BlindedBeaconBlockBodyElectra; +import tech.pegasys.teku.api.schema.electra.BlindedBlockElectra; import tech.pegasys.teku.api.schema.phase0.BeaconBlockPhase0; import tech.pegasys.teku.api.schema.phase0.BeaconStatePhase0; import tech.pegasys.teku.infrastructure.unsigned.UInt64; @@ -111,6 +116,13 @@ public BeaconBlock getBlindedBlock( block.getParentRoot(), block.getStateRoot(), getBlindedBlockBodyCapella(block.getBody())); + case ELECTRA: + return new BlindedBlockElectra( + block.getSlot(), + block.getProposerIndex(), + block.getParentRoot(), + block.getStateRoot(), + getBlindedBlockBodyElectra(block.getBody())); case DENEB: return new BlindedBlockDeneb( block.getSlot(), @@ -155,6 +167,13 @@ public BeaconBlock getBeaconBlock( block.getParentRoot(), block.getStateRoot(), getBeaconBlockBodyCapella(block.getBody())); + case ELECTRA: + return new BeaconBlockElectra( + block.getSlot(), + block.getProposerIndex(), + block.getParentRoot(), + block.getStateRoot(), + getBeaconBlockBodyElectra(block.getBody())); case DENEB: return new BeaconBlockDeneb( block.getSlot(), @@ -188,6 +207,13 @@ private BeaconBlockBodyCapella getBeaconBlockBodyCapella( .BeaconBlockBodyCapella.required(body)); } + private BeaconBlockBodyElectra getBeaconBlockBodyElectra( + final tech.pegasys.teku.spec.datastructures.blocks.blockbody.BeaconBlockBody body) { + return new BeaconBlockBodyElectra( + tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.electra + .BeaconBlockBodyElectra.required(body)); + } + private BeaconBlockBodyDeneb getBeaconBlockBodyDeneb( final tech.pegasys.teku.spec.datastructures.blocks.blockbody.BeaconBlockBody body) { return new BeaconBlockBodyDeneb( @@ -209,6 +235,13 @@ private BlindedBeaconBlockBodyCapella getBlindedBlockBodyCapella( .BlindedBeaconBlockBodyCapella.required(body)); } + private BlindedBeaconBlockBodyElectra getBlindedBlockBodyElectra( + final tech.pegasys.teku.spec.datastructures.blocks.blockbody.BeaconBlockBody body) { + return new BlindedBeaconBlockBodyElectra( + tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.electra + .BlindedBeaconBlockBodyElectra.required(body)); + } + private BlindedBeaconBlockBodyDeneb getBlindedBlockBodyDeneb( final tech.pegasys.teku.spec.datastructures.blocks.blockbody.BeaconBlockBody body) { return new BlindedBeaconBlockBodyDeneb( @@ -228,6 +261,8 @@ public BeaconState getBeaconState( return new BeaconStateBellatrix(state); case CAPELLA: return new BeaconStateCapella(state); + case ELECTRA: + return new BeaconStateElectra(state); case DENEB: return new BeaconStateDeneb(state); default: diff --git a/data/provider/src/main/java/tech/pegasys/teku/api/ValidatorDataProvider.java b/data/provider/src/main/java/tech/pegasys/teku/api/ValidatorDataProvider.java index 52df7ea36fa..7dffb06c948 100644 --- a/data/provider/src/main/java/tech/pegasys/teku/api/ValidatorDataProvider.java +++ b/data/provider/src/main/java/tech/pegasys/teku/api/ValidatorDataProvider.java @@ -37,6 +37,8 @@ import tech.pegasys.teku.api.schema.capella.SignedBlindedBeaconBlockCapella; import tech.pegasys.teku.api.schema.deneb.SignedBeaconBlockDeneb; import tech.pegasys.teku.api.schema.deneb.SignedBlindedBeaconBlockDeneb; +import tech.pegasys.teku.api.schema.electra.SignedBeaconBlockElectra; +import tech.pegasys.teku.api.schema.electra.SignedBlindedBeaconBlockElectra; import tech.pegasys.teku.api.schema.phase0.SignedBeaconBlockPhase0; import tech.pegasys.teku.bls.BLSSignature; import tech.pegasys.teku.ethereum.json.types.validator.ProposerDuties; @@ -276,6 +278,9 @@ public SignedBeaconBlock parseBlock(final JsonProvider jsonProvider, final Strin case CAPELLA: signedBeaconBlock = mapper.treeToValue(jsonNode, SignedBeaconBlockCapella.class); break; + case ELECTRA: + signedBeaconBlock = mapper.treeToValue(jsonNode, SignedBeaconBlockElectra.class); + break; case DENEB: signedBeaconBlock = mapper.treeToValue(jsonNode, SignedBeaconBlockDeneb.class); break; @@ -305,6 +310,9 @@ public SignedBeaconBlock parseBlindedBlock( case CAPELLA: signedBlindedBlock = mapper.treeToValue(jsonNode, SignedBlindedBeaconBlockCapella.class); break; + case ELECTRA: + signedBlindedBlock = mapper.treeToValue(jsonNode, SignedBlindedBeaconBlockElectra.class); + break; case DENEB: signedBlindedBlock = mapper.treeToValue(jsonNode, SignedBlindedBeaconBlockDeneb.class); break; diff --git a/data/provider/src/test/java/tech/pegasys/teku/api/ValidatorDataProviderTest.java b/data/provider/src/test/java/tech/pegasys/teku/api/ValidatorDataProviderTest.java index ce36b8ca600..70399566db9 100644 --- a/data/provider/src/test/java/tech/pegasys/teku/api/ValidatorDataProviderTest.java +++ b/data/provider/src/test/java/tech/pegasys/teku/api/ValidatorDataProviderTest.java @@ -532,6 +532,7 @@ void registerValidators_shouldIgnoreExitedAndUnknownValidators() { ValidatorStatus.values()[statusIdx])) .collect(Collectors.toUnmodifiableMap(Map.Entry::getKey, Map.Entry::getValue)); + @SuppressWarnings("EnumOrdinal") final List exitedOrUnknownKeys = IntStream.range( ValidatorStatus.exited_unslashed.ordinal(), numOfValidatorRegistrationsAttempted) diff --git a/data/serializer/src/main/java/tech/pegasys/teku/api/schema/ExecutionPayload.java b/data/serializer/src/main/java/tech/pegasys/teku/api/schema/ExecutionPayload.java index cfaa0b823df..82a43985f5a 100644 --- a/data/serializer/src/main/java/tech/pegasys/teku/api/schema/ExecutionPayload.java +++ b/data/serializer/src/main/java/tech/pegasys/teku/api/schema/ExecutionPayload.java @@ -17,6 +17,7 @@ import tech.pegasys.teku.api.schema.bellatrix.ExecutionPayloadBellatrix; import tech.pegasys.teku.api.schema.capella.ExecutionPayloadCapella; import tech.pegasys.teku.api.schema.deneb.ExecutionPayloadDeneb; +import tech.pegasys.teku.api.schema.electra.ExecutionPayloadElectra; public interface ExecutionPayload { @@ -28,6 +29,10 @@ default Optional toVersionCapella() { return Optional.empty(); } + default Optional toVersionElectra() { + return Optional.empty(); + } + default Optional toVersionDeneb() { return Optional.empty(); } diff --git a/data/serializer/src/main/java/tech/pegasys/teku/api/schema/ExecutionPayloadHeader.java b/data/serializer/src/main/java/tech/pegasys/teku/api/schema/ExecutionPayloadHeader.java index 592f930abac..04f400963bb 100644 --- a/data/serializer/src/main/java/tech/pegasys/teku/api/schema/ExecutionPayloadHeader.java +++ b/data/serializer/src/main/java/tech/pegasys/teku/api/schema/ExecutionPayloadHeader.java @@ -17,6 +17,7 @@ import tech.pegasys.teku.api.schema.bellatrix.ExecutionPayloadHeaderBellatrix; import tech.pegasys.teku.api.schema.capella.ExecutionPayloadHeaderCapella; import tech.pegasys.teku.api.schema.deneb.ExecutionPayloadHeaderDeneb; +import tech.pegasys.teku.api.schema.electra.ExecutionPayloadHeaderElectra; import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadHeaderSchema; public interface ExecutionPayloadHeader { @@ -31,6 +32,10 @@ default Optional toVersionCapella() { return Optional.empty(); } + default Optional toVersionElectra() { + return Optional.empty(); + } + default Optional toVersionDeneb() { return Optional.empty(); } diff --git a/data/serializer/src/main/java/tech/pegasys/teku/api/schema/Version.java b/data/serializer/src/main/java/tech/pegasys/teku/api/schema/Version.java index f779eb25d95..b73babad251 100644 --- a/data/serializer/src/main/java/tech/pegasys/teku/api/schema/Version.java +++ b/data/serializer/src/main/java/tech/pegasys/teku/api/schema/Version.java @@ -21,12 +21,15 @@ public enum Version { altair, bellatrix, capella, + electra, deneb; public static Version fromMilestone(final SpecMilestone milestone) { switch (milestone) { case DENEB: return deneb; + case ELECTRA: + return electra; case CAPELLA: return capella; case BELLATRIX: diff --git a/data/serializer/src/main/java/tech/pegasys/teku/api/schema/deneb/ExecutionPayloadDeneb.java b/data/serializer/src/main/java/tech/pegasys/teku/api/schema/deneb/ExecutionPayloadDeneb.java index 062178c1b03..468d822e3ba 100644 --- a/data/serializer/src/main/java/tech/pegasys/teku/api/schema/deneb/ExecutionPayloadDeneb.java +++ b/data/serializer/src/main/java/tech/pegasys/teku/api/schema/deneb/ExecutionPayloadDeneb.java @@ -22,15 +22,15 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.units.bigints.UInt256; -import tech.pegasys.teku.api.schema.ExecutionPayload; -import tech.pegasys.teku.api.schema.capella.ExecutionPayloadCapella; import tech.pegasys.teku.api.schema.capella.Withdrawal; +import tech.pegasys.teku.api.schema.electra.ExecutionPayloadElectra; import tech.pegasys.teku.infrastructure.bytes.Bytes20; import tech.pegasys.teku.infrastructure.unsigned.UInt64; +import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayload; import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadBuilder; import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadSchema; -public class ExecutionPayloadDeneb extends ExecutionPayloadCapella implements ExecutionPayload { +public class ExecutionPayloadDeneb extends ExecutionPayloadElectra { @JsonProperty("blob_gas_used") public final UInt64 blobGasUsed; @@ -55,6 +55,7 @@ public ExecutionPayloadDeneb( @JsonProperty("block_hash") final Bytes32 blockHash, @JsonProperty("transactions") final List transactions, @JsonProperty("withdrawals") final List withdrawals, + @JsonProperty("execution_witness") final Bytes executionWitness, @JsonProperty("blob_gas_used") final UInt64 blobGasUsed, @JsonProperty("excess_blob_gas") final UInt64 excessBlobGas) { super( @@ -72,13 +73,13 @@ public ExecutionPayloadDeneb( baseFeePerGas, blockHash, transactions, - withdrawals); + withdrawals, + executionWitness); this.blobGasUsed = blobGasUsed; this.excessBlobGas = excessBlobGas; } - public ExecutionPayloadDeneb( - final tech.pegasys.teku.spec.datastructures.execution.ExecutionPayload executionPayload) { + public ExecutionPayloadDeneb(final ExecutionPayload executionPayload) { super(executionPayload); this.blobGasUsed = executionPayload.toVersionDeneb().orElseThrow().getBlobGasUsed(); this.excessBlobGas = executionPayload.toVersionDeneb().orElseThrow().getExcessBlobGas(); @@ -137,6 +138,7 @@ public String toString() { .add("blockHash", blockHash) .add("transactions", transactions) .add("withdrawals", withdrawals) + .add("executionWitness", executionWitness) .add("blobGasUsed", blobGasUsed) .add("excessBlobGas", excessBlobGas) .toString(); diff --git a/data/serializer/src/main/java/tech/pegasys/teku/api/schema/deneb/ExecutionPayloadHeaderDeneb.java b/data/serializer/src/main/java/tech/pegasys/teku/api/schema/deneb/ExecutionPayloadHeaderDeneb.java index a7be2550066..06aa625c7ae 100644 --- a/data/serializer/src/main/java/tech/pegasys/teku/api/schema/deneb/ExecutionPayloadHeaderDeneb.java +++ b/data/serializer/src/main/java/tech/pegasys/teku/api/schema/deneb/ExecutionPayloadHeaderDeneb.java @@ -21,13 +21,14 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.units.bigints.UInt256; -import tech.pegasys.teku.api.schema.capella.ExecutionPayloadHeaderCapella; import tech.pegasys.teku.infrastructure.bytes.Bytes20; import tech.pegasys.teku.infrastructure.unsigned.UInt64; import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadHeader; import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadHeaderSchema; +import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionPayloadHeaderElectra; -public class ExecutionPayloadHeaderDeneb extends ExecutionPayloadHeaderCapella { +public class ExecutionPayloadHeaderDeneb + extends tech.pegasys.teku.api.schema.electra.ExecutionPayloadHeaderElectra { @JsonProperty("blob_gas_used") public final UInt64 blobGasUsed; @@ -52,6 +53,7 @@ public ExecutionPayloadHeaderDeneb( @JsonProperty("block_hash") final Bytes32 blockHash, @JsonProperty("transactions_root") final Bytes32 transactionsRoot, @JsonProperty("withdrawals_root") final Bytes32 withdrawalsRoot, + @JsonProperty("execution_witness_root") final Bytes32 executionWitnessRoot, @JsonProperty("blob_gas_used") final UInt64 blobGasUsed, @JsonProperty("excess_blob_gas") final UInt64 excessBlobGas) { super( @@ -69,7 +71,8 @@ public ExecutionPayloadHeaderDeneb( baseFeePerGas, blockHash, transactionsRoot, - withdrawalsRoot); + withdrawalsRoot, + executionWitnessRoot); this.blobGasUsed = blobGasUsed; this.excessBlobGas = excessBlobGas; } @@ -90,7 +93,11 @@ public ExecutionPayloadHeaderDeneb(final ExecutionPayloadHeader executionPayload executionPayloadHeader.getBaseFeePerGas(), executionPayloadHeader.getBlockHash(), executionPayloadHeader.getTransactionsRoot(), - executionPayloadHeader.getOptionalWithdrawalsRoot().orElseThrow()); + executionPayloadHeader.getOptionalWithdrawalsRoot().orElseThrow(), + executionPayloadHeader + .toVersionElectra() + .map(ExecutionPayloadHeaderElectra::getExecutionWitnessRoot) + .orElse(null)); this.blobGasUsed = executionPayloadHeader.toVersionDeneb().orElseThrow().getBlobGasUsed(); this.excessBlobGas = executionPayloadHeader.toVersionDeneb().orElseThrow().getExcessBlobGas(); } @@ -116,6 +123,7 @@ public ExecutionPayloadHeader asInternalExecutionPayloadHeader( .blockHash(blockHash) .transactionsRoot(transactionsRoot) .withdrawalsRoot(() -> withdrawalsRoot) + .executionWitnessRoot(() -> executionWitnessRoot) .blobGasUsed(() -> blobGasUsed) .excessBlobGas(() -> excessBlobGas)); } @@ -164,6 +172,7 @@ public String toString() { .add("blockHash", blockHash) .add("transactionsRoot", transactionsRoot) .add("withdrawalsRoot", withdrawalsRoot) + .add("executionWitnessRoot", executionWitnessRoot) .add("blobGasUsed", blobGasUsed) .add("excessBlobGas", excessBlobGas) .toString(); diff --git a/data/serializer/src/main/java/tech/pegasys/teku/api/schema/electra/BeaconBlockBodyElectra.java b/data/serializer/src/main/java/tech/pegasys/teku/api/schema/electra/BeaconBlockBodyElectra.java new file mode 100644 index 00000000000..8614bb90749 --- /dev/null +++ b/data/serializer/src/main/java/tech/pegasys/teku/api/schema/electra/BeaconBlockBodyElectra.java @@ -0,0 +1,111 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.api.schema.electra; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import org.apache.tuweni.bytes.Bytes32; +import tech.pegasys.teku.api.schema.Attestation; +import tech.pegasys.teku.api.schema.AttesterSlashing; +import tech.pegasys.teku.api.schema.BLSSignature; +import tech.pegasys.teku.api.schema.Deposit; +import tech.pegasys.teku.api.schema.Eth1Data; +import tech.pegasys.teku.api.schema.ProposerSlashing; +import tech.pegasys.teku.api.schema.SignedVoluntaryExit; +import tech.pegasys.teku.api.schema.altair.BeaconBlockBodyAltair; +import tech.pegasys.teku.api.schema.altair.SyncAggregate; +import tech.pegasys.teku.api.schema.capella.SignedBlsToExecutionChange; +import tech.pegasys.teku.infrastructure.async.SafeFuture; +import tech.pegasys.teku.infrastructure.ssz.schema.SszListSchema; +import tech.pegasys.teku.spec.SpecVersion; +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.BeaconBlockBody; +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.electra.BeaconBlockBodySchemaElectra; + +public class BeaconBlockBodyElectra extends BeaconBlockBodyAltair { + + @JsonProperty("execution_payload") + public final ExecutionPayloadElectra executionPayload; + + @JsonProperty("bls_to_execution_changes") + public final List blsToExecutionChanges; + + @JsonCreator + public BeaconBlockBodyElectra( + @JsonProperty("randao_reveal") final BLSSignature randaoReveal, + @JsonProperty("eth1_data") final Eth1Data eth1Data, + @JsonProperty("graffiti") final Bytes32 graffiti, + @JsonProperty("proposer_slashings") final List proposerSlashings, + @JsonProperty("attester_slashings") final List attesterSlashings, + @JsonProperty("attestations") final List attestations, + @JsonProperty("deposits") final List deposits, + @JsonProperty("voluntary_exits") final List voluntaryExits, + @JsonProperty("sync_aggregate") final SyncAggregate syncAggregate, + @JsonProperty("execution_payload") final ExecutionPayloadElectra executionPayload, + @JsonProperty("bls_to_execution_changes") + final List blsToExecutionChanges) { + super( + randaoReveal, + eth1Data, + graffiti, + proposerSlashings, + attesterSlashings, + attestations, + deposits, + voluntaryExits, + syncAggregate); + checkNotNull(executionPayload, "Execution Payload is required for capella blocks"); + this.executionPayload = executionPayload; + checkNotNull(blsToExecutionChanges, "BlsToExecutionChanges is required for capella blocks"); + this.blsToExecutionChanges = blsToExecutionChanges; + } + + public BeaconBlockBodyElectra( + tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.electra.BeaconBlockBodyElectra + message) { + super(message); + checkNotNull(message.getExecutionPayload(), "Execution Payload is required for electra blocks"); + this.executionPayload = new ExecutionPayloadElectra(message.getExecutionPayload()); + checkNotNull( + message.getBlsToExecutionChanges(), "BlsToExecutionChanges is required for electra blocks"); + this.blsToExecutionChanges = + message.getBlsToExecutionChanges().stream().map(SignedBlsToExecutionChange::new).toList(); + } + + @Override + public BeaconBlockBodySchemaElectra getBeaconBlockBodySchema(final SpecVersion spec) { + return (BeaconBlockBodySchemaElectra) spec.getSchemaDefinitions().getBeaconBlockBodySchema(); + } + + @Override + public BeaconBlockBody asInternalBeaconBlockBody(final SpecVersion spec) { + final SszListSchema< + tech.pegasys.teku.spec.datastructures.operations.SignedBlsToExecutionChange, ?> + blsToExecutionChangesSchema = + getBeaconBlockBodySchema(spec).getBlsToExecutionChangesSchema(); + + return super.asInternalBeaconBlockBody( + spec, + builder -> { + builder.executionPayload(executionPayload.asInternalExecutionPayload(spec)); + builder.blsToExecutionChanges( + this.blsToExecutionChanges.stream() + .map(b -> b.asInternalSignedBlsToExecutionChange(spec)) + .collect(blsToExecutionChangesSchema.collector())); + return SafeFuture.COMPLETE; + }); + } +} diff --git a/data/serializer/src/main/java/tech/pegasys/teku/api/schema/electra/BeaconBlockElectra.java b/data/serializer/src/main/java/tech/pegasys/teku/api/schema/electra/BeaconBlockElectra.java new file mode 100644 index 00000000000..26e763be43b --- /dev/null +++ b/data/serializer/src/main/java/tech/pegasys/teku/api/schema/electra/BeaconBlockElectra.java @@ -0,0 +1,65 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.api.schema.electra; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import org.apache.tuweni.bytes.Bytes32; +import tech.pegasys.teku.api.schema.altair.BeaconBlockAltair; +import tech.pegasys.teku.infrastructure.unsigned.UInt64; +import tech.pegasys.teku.spec.Spec; +import tech.pegasys.teku.spec.SpecVersion; +import tech.pegasys.teku.spec.datastructures.blocks.BeaconBlock; +import tech.pegasys.teku.spec.schemas.SchemaDefinitionsElectra; + +public class BeaconBlockElectra extends BeaconBlockAltair { + + public BeaconBlockElectra(BeaconBlock message) { + super( + message.getSlot(), + message.getProposerIndex(), + message.getParentRoot(), + message.getStateRoot(), + new BeaconBlockBodyElectra(message.getBody().toVersionElectra().orElseThrow())); + } + + @Override + public BeaconBlock asInternalBeaconBlock(Spec spec) { + final SpecVersion specVersion = spec.atSlot(slot); + return SchemaDefinitionsElectra.required(specVersion.getSchemaDefinitions()) + .getBeaconBlockSchema() + .create( + slot, + proposer_index, + parent_root, + state_root, + body.asInternalBeaconBlockBody(specVersion)); + } + + @JsonProperty("body") + @Override + public BeaconBlockBodyElectra getBody() { + return (BeaconBlockBodyElectra) body; + } + + @JsonCreator + public BeaconBlockElectra( + @JsonProperty("slot") final UInt64 slot, + @JsonProperty("proposer_index") final UInt64 proposerIndex, + @JsonProperty("parent_root") final Bytes32 parentRoot, + @JsonProperty("state_root") final Bytes32 stateRoot, + @JsonProperty("body") final BeaconBlockBodyElectra body) { + super(slot, proposerIndex, parentRoot, stateRoot, body); + } +} diff --git a/data/serializer/src/main/java/tech/pegasys/teku/api/schema/electra/BeaconStateElectra.java b/data/serializer/src/main/java/tech/pegasys/teku/api/schema/electra/BeaconStateElectra.java new file mode 100644 index 00000000000..4d3aca15743 --- /dev/null +++ b/data/serializer/src/main/java/tech/pegasys/teku/api/schema/electra/BeaconStateElectra.java @@ -0,0 +1,196 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.api.schema.electra; + +import static tech.pegasys.teku.api.schema.SchemaConstants.EXAMPLE_UINT64; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import java.util.List; +import org.apache.tuweni.bytes.Bytes32; +import tech.pegasys.teku.api.schema.BeaconBlockHeader; +import tech.pegasys.teku.api.schema.Checkpoint; +import tech.pegasys.teku.api.schema.Eth1Data; +import tech.pegasys.teku.api.schema.Fork; +import tech.pegasys.teku.api.schema.Validator; +import tech.pegasys.teku.api.schema.altair.BeaconStateAltair; +import tech.pegasys.teku.api.schema.altair.SyncCommittee; +import tech.pegasys.teku.api.schema.capella.HistoricalSummary; +import tech.pegasys.teku.infrastructure.ssz.collections.SszBitvector; +import tech.pegasys.teku.infrastructure.ssz.schema.SszListSchema; +import tech.pegasys.teku.infrastructure.unsigned.UInt64; +import tech.pegasys.teku.spec.SpecVersion; +import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionPayloadHeaderSchemaElectra; +import tech.pegasys.teku.spec.datastructures.state.SyncCommittee.SyncCommitteeSchema; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconState; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.MutableBeaconState; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.electra.BeaconStateSchemaElectra; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.electra.MutableBeaconStateElectra; + +public class BeaconStateElectra extends BeaconStateAltair { + + @JsonProperty("latest_execution_payload_header") + public ExecutionPayloadHeaderElectra latestExecutionPayloadHeader; + + @JsonProperty("next_withdrawal_index") + @Schema(type = "string", example = EXAMPLE_UINT64) + public final UInt64 nextWithdrawalIndex; + + @JsonProperty("next_withdrawal_validator_index") + @Schema(type = "string", example = EXAMPLE_UINT64) + public final UInt64 nextWithdrawalValidatorIndex; + + @JsonProperty("historical_summaries") + public final List historicalSummaries; + + public BeaconStateElectra( + @JsonProperty("genesis_time") final UInt64 genesisTime, + @JsonProperty("genesis_validators_root") final Bytes32 genesisValidatorsRoot, + @JsonProperty("slot") final UInt64 slot, + @JsonProperty("fork") final Fork fork, + @JsonProperty("latest_block_header") final BeaconBlockHeader latestBlockHeader, + @JsonProperty("block_roots") final List blockRoots, + @JsonProperty("state_roots") final List stateRoots, + @JsonProperty("historical_roots") final List historicalRoots, + @JsonProperty("eth1_data") final Eth1Data eth1Data, + @JsonProperty("eth1_data_votes") final List eth1DataVotes, + @JsonProperty("eth1_deposit_index") final UInt64 eth1DepositIndex, + @JsonProperty("validators") final List validators, + @JsonProperty("balances") final List balances, + @JsonProperty("randao_mixes") final List randaoMixes, + @JsonProperty("slashings") final List slashings, + @JsonProperty("previous_epoch_participation") final byte[] previousEpochParticipation, + @JsonProperty("current_epoch_participation") final byte[] currentEpochParticipation, + @JsonProperty("justification_bits") final SszBitvector justificationBits, + @JsonProperty("previous_justified_checkpoint") final Checkpoint previousJustifiedCheckpoint, + @JsonProperty("current_justified_checkpoint") final Checkpoint currentJustifiedCheckpoint, + @JsonProperty("finalized_checkpoint") final Checkpoint finalizedCheckpoint, + @JsonProperty("inactivity_scores") final List inactivityScores, + @JsonProperty("current_sync_committee") final SyncCommittee currentSyncCommittee, + @JsonProperty("next_sync_committee") final SyncCommittee nextSyncCommittee, + @JsonProperty("latest_execution_payload_header") + final ExecutionPayloadHeaderElectra latestExecutionPayloadHeader, + @JsonProperty("next_withdrawal_index") final UInt64 nextWithdrawalIndex, + @JsonProperty("next_withdrawal_validator_index") final UInt64 nextWithdrawalValidatorIndex, + @JsonProperty("historical_summaries") final List historicalSummaries) { + super( + genesisTime, + genesisValidatorsRoot, + slot, + fork, + latestBlockHeader, + blockRoots, + stateRoots, + historicalRoots, + eth1Data, + eth1DataVotes, + eth1DepositIndex, + validators, + balances, + randaoMixes, + slashings, + previousEpochParticipation, + currentEpochParticipation, + justificationBits, + previousJustifiedCheckpoint, + currentJustifiedCheckpoint, + finalizedCheckpoint, + inactivityScores, + currentSyncCommittee, + nextSyncCommittee); + this.latestExecutionPayloadHeader = latestExecutionPayloadHeader; + this.nextWithdrawalIndex = nextWithdrawalIndex; + this.nextWithdrawalValidatorIndex = nextWithdrawalValidatorIndex; + this.historicalSummaries = historicalSummaries; + } + + public BeaconStateElectra(BeaconState beaconState) { + super(beaconState); + final tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.electra + .BeaconStateElectra + electra = beaconState.toVersionElectra().orElseThrow(); + this.latestExecutionPayloadHeader = + new ExecutionPayloadHeaderElectra(electra.getLatestExecutionPayloadHeader()); + this.nextWithdrawalIndex = electra.getNextWithdrawalIndex(); + this.nextWithdrawalValidatorIndex = electra.getNextWithdrawalValidatorIndex(); + this.historicalSummaries = + electra.getHistoricalSummaries().stream().map(HistoricalSummary::new).toList(); + } + + @Override + protected void applyAdditionalFields( + final MutableBeaconState state, final SpecVersion specVersion) { + state + .toMutableVersionElectra() + .ifPresent( + mutableBeaconStateElectra -> + applyElectraFields( + specVersion, + mutableBeaconStateElectra, + BeaconStateSchemaElectra.required( + mutableBeaconStateElectra.getBeaconStateSchema()) + .getCurrentSyncCommitteeSchema(), + BeaconStateSchemaElectra.required( + mutableBeaconStateElectra.getBeaconStateSchema()) + .getLastExecutionPayloadHeaderSchema(), + BeaconStateSchemaElectra.required( + mutableBeaconStateElectra.getBeaconStateSchema()) + .getHistoricalSummariesSchema(), + this)); + } + + protected static void applyElectraFields( + final SpecVersion specVersion, + MutableBeaconStateElectra state, + SyncCommitteeSchema syncCommitteeSchema, + ExecutionPayloadHeaderSchemaElectra executionPayloadHeaderSchema, + SszListSchema< + tech.pegasys.teku.spec.datastructures.state.versions.capella.HistoricalSummary, ?> + historicalSummariesSchema, + BeaconStateElectra instance) { + + BeaconStateAltair.applyAltairFields(state, syncCommitteeSchema, instance); + + state.setLatestExecutionPayloadHeader( + executionPayloadHeaderSchema.createExecutionPayloadHeader( + builder -> + builder + .parentHash(instance.latestExecutionPayloadHeader.parentHash) + .feeRecipient(instance.latestExecutionPayloadHeader.feeRecipient) + .stateRoot(instance.latestExecutionPayloadHeader.stateRoot) + .receiptsRoot(instance.latestExecutionPayloadHeader.receiptsRoot) + .logsBloom(instance.latestExecutionPayloadHeader.logsBloom) + .prevRandao(instance.latestExecutionPayloadHeader.prevRandao) + .blockNumber(instance.latestExecutionPayloadHeader.blockNumber) + .gasLimit(instance.latestExecutionPayloadHeader.gasLimit) + .gasUsed(instance.latestExecutionPayloadHeader.gasUsed) + .timestamp(instance.latestExecutionPayloadHeader.timestamp) + .extraData(instance.latestExecutionPayloadHeader.extraData) + .baseFeePerGas(instance.latestExecutionPayloadHeader.baseFeePerGas) + .blockHash(instance.latestExecutionPayloadHeader.blockHash) + .transactionsRoot(instance.latestExecutionPayloadHeader.transactionsRoot) + .withdrawalsRoot(() -> instance.latestExecutionPayloadHeader.withdrawalsRoot) + .executionWitnessRoot( + () -> instance.latestExecutionPayloadHeader.executionWitnessRoot))); + + state.setNextWithdrawalIndex(instance.nextWithdrawalIndex); + state.setNextWithdrawalValidatorIndex(instance.nextWithdrawalValidatorIndex); + state.setHistoricalSummaries( + historicalSummariesSchema.createFromElements( + instance.historicalSummaries.stream() + .map( + historicalSummary -> historicalSummary.asInternalHistoricalSummary(specVersion)) + .toList())); + } +} diff --git a/data/serializer/src/main/java/tech/pegasys/teku/api/schema/electra/BlindedBeaconBlockBodyElectra.java b/data/serializer/src/main/java/tech/pegasys/teku/api/schema/electra/BlindedBeaconBlockBodyElectra.java new file mode 100644 index 00000000000..d8bfacf41dc --- /dev/null +++ b/data/serializer/src/main/java/tech/pegasys/teku/api/schema/electra/BlindedBeaconBlockBodyElectra.java @@ -0,0 +1,125 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.api.schema.electra; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import org.apache.tuweni.bytes.Bytes32; +import tech.pegasys.teku.api.schema.Attestation; +import tech.pegasys.teku.api.schema.AttesterSlashing; +import tech.pegasys.teku.api.schema.BLSSignature; +import tech.pegasys.teku.api.schema.Deposit; +import tech.pegasys.teku.api.schema.Eth1Data; +import tech.pegasys.teku.api.schema.ProposerSlashing; +import tech.pegasys.teku.api.schema.SignedVoluntaryExit; +import tech.pegasys.teku.api.schema.altair.BeaconBlockBodyAltair; +import tech.pegasys.teku.api.schema.altair.SyncAggregate; +import tech.pegasys.teku.api.schema.capella.SignedBlsToExecutionChange; +import tech.pegasys.teku.infrastructure.async.SafeFuture; +import tech.pegasys.teku.infrastructure.ssz.schema.SszListSchema; +import tech.pegasys.teku.spec.SpecVersion; +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.BeaconBlockBody; +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.capella.BlindedBeaconBlockBodySchemaCapella; +import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadHeaderSchema; + +public class BlindedBeaconBlockBodyElectra extends BeaconBlockBodyAltair { + + @JsonProperty("execution_payload_header") + public final ExecutionPayloadHeaderElectra executionPayloadHeader; + + @JsonProperty("bls_to_execution_changes") + public final List blsToExecutionChanges; + + @JsonCreator + public BlindedBeaconBlockBodyElectra( + @JsonProperty("randao_reveal") final BLSSignature randaoReveal, + @JsonProperty("eth1_data") final Eth1Data eth1Data, + @JsonProperty("graffiti") final Bytes32 graffiti, + @JsonProperty("proposer_slashings") final List proposerSlashings, + @JsonProperty("attester_slashings") final List attesterSlashings, + @JsonProperty("attestations") final List attestations, + @JsonProperty("deposits") final List deposits, + @JsonProperty("voluntary_exits") final List voluntaryExits, + @JsonProperty("sync_aggregate") final SyncAggregate syncAggregate, + @JsonProperty("execution_payload_header") + final ExecutionPayloadHeaderElectra executionPayloadHeader, + @JsonProperty("bls_to_execution_changes") + final List blsToExecutionChanges) { + super( + randaoReveal, + eth1Data, + graffiti, + proposerSlashings, + attesterSlashings, + attestations, + deposits, + voluntaryExits, + syncAggregate); + checkNotNull( + executionPayloadHeader, "Execution Payload Header is required for capella blinded blocks"); + this.executionPayloadHeader = executionPayloadHeader; + checkNotNull( + blsToExecutionChanges, "bls_to_execution_changes is required for capella blinded blocks"); + this.blsToExecutionChanges = blsToExecutionChanges; + } + + public BlindedBeaconBlockBodyElectra( + final tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.electra + .BlindedBeaconBlockBodyElectra + blockBody) { + super(blockBody); + this.executionPayloadHeader = + new ExecutionPayloadHeaderElectra(blockBody.getExecutionPayloadHeader()); + this.blsToExecutionChanges = + blockBody.getBlsToExecutionChanges().stream().map(SignedBlsToExecutionChange::new).toList(); + } + + @Override + public BlindedBeaconBlockBodySchemaCapella getBeaconBlockBodySchema(final SpecVersion spec) { + return (BlindedBeaconBlockBodySchemaCapella) + spec.getSchemaDefinitions().getBlindedBeaconBlockBodySchema(); + } + + @Override + public boolean isBlinded() { + return true; + } + + @Override + public BeaconBlockBody asInternalBeaconBlockBody(final SpecVersion spec) { + + final ExecutionPayloadHeaderSchema executionPayloadHeaderSchema = + getBeaconBlockBodySchema(spec).getExecutionPayloadHeaderSchema(); + + final SszListSchema< + tech.pegasys.teku.spec.datastructures.operations.SignedBlsToExecutionChange, ?> + blsToExecutionChangesSchema = getBeaconBlockBodySchema(spec).getBlsToExecutionChanges(); + + return super.asInternalBeaconBlockBody( + spec, + builder -> { + builder.executionPayloadHeader( + executionPayloadHeader.asInternalExecutionPayloadHeader( + executionPayloadHeaderSchema)); + builder.blsToExecutionChanges( + this.blsToExecutionChanges.stream() + .map(b -> b.asInternalSignedBlsToExecutionChange(spec)) + .collect(blsToExecutionChangesSchema.collector())); + return SafeFuture.COMPLETE; + }); + } +} diff --git a/data/serializer/src/main/java/tech/pegasys/teku/api/schema/electra/BlindedBlockElectra.java b/data/serializer/src/main/java/tech/pegasys/teku/api/schema/electra/BlindedBlockElectra.java new file mode 100644 index 00000000000..b2d8a059698 --- /dev/null +++ b/data/serializer/src/main/java/tech/pegasys/teku/api/schema/electra/BlindedBlockElectra.java @@ -0,0 +1,70 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.api.schema.electra; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import org.apache.tuweni.bytes.Bytes32; +import tech.pegasys.teku.api.schema.altair.BeaconBlockAltair; +import tech.pegasys.teku.infrastructure.unsigned.UInt64; +import tech.pegasys.teku.spec.Spec; +import tech.pegasys.teku.spec.SpecVersion; +import tech.pegasys.teku.spec.datastructures.blocks.BeaconBlock; +import tech.pegasys.teku.spec.datastructures.blocks.BeaconBlockSchema; + +public class BlindedBlockElectra extends BeaconBlockAltair { + + public BlindedBlockElectra(BeaconBlock message) { + super( + message.getSlot(), + message.getProposerIndex(), + message.getParentRoot(), + message.getStateRoot(), + new BlindedBeaconBlockBodyElectra( + message.getBody().toBlindedVersionElectra().orElseThrow())); + } + + @Override + public BeaconBlockSchema getBeaconBlockSchema(final SpecVersion spec) { + return spec.getSchemaDefinitions().getBlindedBeaconBlockSchema(); + } + + @Override + public BeaconBlock asInternalBeaconBlock(Spec spec) { + final SpecVersion specVersion = spec.atSlot(slot); + return getBeaconBlockSchema(specVersion) + .create( + slot, + proposer_index, + parent_root, + state_root, + body.asInternalBeaconBlockBody(specVersion)); + } + + @JsonProperty("body") + @Override + public BlindedBeaconBlockBodyElectra getBody() { + return (BlindedBeaconBlockBodyElectra) body; + } + + @JsonCreator + public BlindedBlockElectra( + @JsonProperty("slot") final UInt64 slot, + @JsonProperty("proposer_index") final UInt64 proposerIndex, + @JsonProperty("parent_root") final Bytes32 parentRoot, + @JsonProperty("state_root") final Bytes32 stateRoot, + @JsonProperty("body") final BlindedBeaconBlockBodyElectra body) { + super(slot, proposerIndex, parentRoot, stateRoot, body); + } +} diff --git a/data/serializer/src/main/java/tech/pegasys/teku/api/schema/electra/ExecutionPayloadElectra.java b/data/serializer/src/main/java/tech/pegasys/teku/api/schema/electra/ExecutionPayloadElectra.java new file mode 100644 index 00000000000..8dd6aaaff4f --- /dev/null +++ b/data/serializer/src/main/java/tech/pegasys/teku/api/schema/electra/ExecutionPayloadElectra.java @@ -0,0 +1,144 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.api.schema.electra; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.common.base.MoreObjects; +import io.swagger.v3.oas.annotations.media.Schema; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; +import org.apache.tuweni.units.bigints.UInt256; +import tech.pegasys.teku.api.schema.capella.ExecutionPayloadCapella; +import tech.pegasys.teku.api.schema.capella.Withdrawal; +import tech.pegasys.teku.infrastructure.bytes.Bytes20; +import tech.pegasys.teku.infrastructure.unsigned.UInt64; +import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayload; +import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadBuilder; +import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadSchema; + +public class ExecutionPayloadElectra extends ExecutionPayloadCapella { + + @JsonProperty("execution_witness") + @Schema(type = "string", format = "byte") + public final Bytes executionWitness; + + @JsonCreator + public ExecutionPayloadElectra( + @JsonProperty("parent_hash") Bytes32 parentHash, + @JsonProperty("fee_recipient") Bytes20 feeRecipient, + @JsonProperty("state_root") Bytes32 stateRoot, + @JsonProperty("receipts_root") Bytes32 receiptsRoot, + @JsonProperty("logs_bloom") Bytes logsBloom, + @JsonProperty("prev_randao") Bytes32 prevRandao, + @JsonProperty("block_number") UInt64 blockNumber, + @JsonProperty("gas_limit") UInt64 gasLimit, + @JsonProperty("gas_used") UInt64 gasUsed, + @JsonProperty("timestamp") UInt64 timestamp, + @JsonProperty("extra_data") Bytes extraData, + @JsonProperty("base_fee_per_gas") UInt256 baseFeePerGas, + @JsonProperty("block_hash") Bytes32 blockHash, + @JsonProperty("transactions") List transactions, + @JsonProperty("withdrawals") List withdrawals, + @JsonProperty("execution_witness") Bytes executionWitness) { + super( + parentHash, + feeRecipient, + stateRoot, + receiptsRoot, + logsBloom, + prevRandao, + blockNumber, + gasLimit, + gasUsed, + timestamp, + extraData, + baseFeePerGas, + blockHash, + transactions, + withdrawals); + this.executionWitness = executionWitness; + } + + public ExecutionPayloadElectra(ExecutionPayload executionPayload) { + super(executionPayload); + this.executionWitness = + executionPayload + .toVersionElectra() + .map(electraHeader -> electraHeader.getExecutionWitness().sszSerialize()) + .orElse(null); + } + + @Override + protected ExecutionPayloadBuilder applyToBuilder( + final ExecutionPayloadSchema executionPayloadSchema, + final ExecutionPayloadBuilder builder) { + return super.applyToBuilder(executionPayloadSchema, builder) + .executionWitness( + () -> + executionPayloadSchema + .getExecutionWitnessSchemaRequired() + .sszDeserialize(executionWitness)); + } + + @Override + public Optional toVersionElectra() { + return Optional.of(this); + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + if (!super.equals(o)) { + return false; + } + final ExecutionPayloadElectra that = (ExecutionPayloadElectra) o; + return Objects.equals(executionWitness, that.executionWitness); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), executionWitness); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("parentHash", parentHash) + .add("feeRecipient", feeRecipient) + .add("stateRoot", stateRoot) + .add("receiptsRoot", receiptsRoot) + .add("logsBloom", logsBloom) + .add("prevRandao", prevRandao) + .add("blockNumber", blockNumber) + .add("gasLimit", gasLimit) + .add("gasUsed", gasUsed) + .add("timestamp", timestamp) + .add("extraData", extraData) + .add("baseFeePerGas", baseFeePerGas) + .add("blockHash", blockHash) + .add("transactions", transactions) + .add("withdrawals", withdrawals) + .add("executionWitness", executionWitness) + .toString(); + } +} diff --git a/data/serializer/src/main/java/tech/pegasys/teku/api/schema/electra/ExecutionPayloadHeaderElectra.java b/data/serializer/src/main/java/tech/pegasys/teku/api/schema/electra/ExecutionPayloadHeaderElectra.java new file mode 100644 index 00000000000..f4e4b18ab82 --- /dev/null +++ b/data/serializer/src/main/java/tech/pegasys/teku/api/schema/electra/ExecutionPayloadHeaderElectra.java @@ -0,0 +1,148 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.api.schema.electra; + +import static tech.pegasys.teku.api.schema.SchemaConstants.DESCRIPTION_BYTES32; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.common.base.MoreObjects; +import io.swagger.v3.oas.annotations.media.Schema; +import java.util.Objects; +import java.util.Optional; +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; +import org.apache.tuweni.units.bigints.UInt256; +import tech.pegasys.teku.api.schema.capella.ExecutionPayloadHeaderCapella; +import tech.pegasys.teku.infrastructure.bytes.Bytes20; +import tech.pegasys.teku.infrastructure.unsigned.UInt64; +import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadHeader; + +public class ExecutionPayloadHeaderElectra extends ExecutionPayloadHeaderCapella { + + @JsonProperty("execution_witness_root") + @Schema(type = "string", format = "byte", description = DESCRIPTION_BYTES32) + public final Bytes32 executionWitnessRoot; + + @JsonCreator + public ExecutionPayloadHeaderElectra( + @JsonProperty("parent_hash") Bytes32 parentHash, + @JsonProperty("fee_recipient") Bytes20 feeRecipient, + @JsonProperty("state_root") Bytes32 stateRoot, + @JsonProperty("receipts_root") Bytes32 receiptsRoot, + @JsonProperty("logs_bloom") Bytes logsBloom, + @JsonProperty("prev_randao") Bytes32 prevRandao, + @JsonProperty("block_number") UInt64 blockNumber, + @JsonProperty("gas_limit") UInt64 gasLimit, + @JsonProperty("gas_used") UInt64 gasUsed, + @JsonProperty("timestamp") UInt64 timestamp, + @JsonProperty("extra_data") Bytes extraData, + @JsonProperty("base_fee_per_gas") UInt256 baseFeePerGas, + @JsonProperty("block_hash") Bytes32 blockHash, + @JsonProperty("transactions_root") Bytes32 transactionsRoot, + @JsonProperty("withdrawals_root") Bytes32 withdrawalsRoot, + @JsonProperty("execution_witness_root") Bytes32 executionWitnessRoot) { + super( + parentHash, + feeRecipient, + stateRoot, + receiptsRoot, + logsBloom, + prevRandao, + blockNumber, + gasLimit, + gasUsed, + timestamp, + extraData, + baseFeePerGas, + blockHash, + transactionsRoot, + withdrawalsRoot); + this.executionWitnessRoot = executionWitnessRoot; + } + + public ExecutionPayloadHeaderElectra(ExecutionPayloadHeader executionPayloadHeader) { + super( + executionPayloadHeader.getParentHash(), + executionPayloadHeader.getFeeRecipient(), + executionPayloadHeader.getStateRoot(), + executionPayloadHeader.getReceiptsRoot(), + executionPayloadHeader.getLogsBloom(), + executionPayloadHeader.getPrevRandao(), + executionPayloadHeader.getBlockNumber(), + executionPayloadHeader.getGasLimit(), + executionPayloadHeader.getGasUsed(), + executionPayloadHeader.getTimestamp(), + executionPayloadHeader.getExtraData(), + executionPayloadHeader.getBaseFeePerGas(), + executionPayloadHeader.getBlockHash(), + executionPayloadHeader.getTransactionsRoot(), + executionPayloadHeader.getOptionalWithdrawalsRoot().orElseThrow()); + this.executionWitnessRoot = + executionPayloadHeader + .toVersionElectra() + .map( + tech.pegasys.teku.spec.datastructures.execution.versions.electra + .ExecutionPayloadHeaderElectra + ::getExecutionWitnessRoot) + .orElse(null); + } + + @Override + public Optional toVersionElectra() { + return Optional.of(this); + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + if (!super.equals(o)) { + return false; + } + final ExecutionPayloadHeaderElectra that = (ExecutionPayloadHeaderElectra) o; + return Objects.equals(executionWitnessRoot, that.executionWitnessRoot); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), executionWitnessRoot); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("parentHash", parentHash) + .add("feeRecipient", feeRecipient) + .add("stateRoot", stateRoot) + .add("receiptsRoot", receiptsRoot) + .add("logsBloom", logsBloom) + .add("prevRandao", prevRandao) + .add("blockNumber", blockNumber) + .add("gasLimit", gasLimit) + .add("gasUsed", gasUsed) + .add("timestamp", timestamp) + .add("extraData", extraData) + .add("baseFeePerGas", baseFeePerGas) + .add("blockHash", blockHash) + .add("transactionsRoot", transactionsRoot) + .add("withdrawalsRoot", withdrawalsRoot) + .add("executionWitnessRoot", executionWitnessRoot) + .toString(); + } +} diff --git a/data/serializer/src/main/java/tech/pegasys/teku/api/schema/electra/SignedBeaconBlockElectra.java b/data/serializer/src/main/java/tech/pegasys/teku/api/schema/electra/SignedBeaconBlockElectra.java new file mode 100644 index 00000000000..73e0ebd245a --- /dev/null +++ b/data/serializer/src/main/java/tech/pegasys/teku/api/schema/electra/SignedBeaconBlockElectra.java @@ -0,0 +1,43 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.api.schema.electra; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import tech.pegasys.teku.api.schema.BLSSignature; +import tech.pegasys.teku.api.schema.SignedBeaconBlock; +import tech.pegasys.teku.api.schema.interfaces.SignedBlock; + +public class SignedBeaconBlockElectra extends SignedBeaconBlock implements SignedBlock { + private final BeaconBlockElectra message; + + public SignedBeaconBlockElectra( + tech.pegasys.teku.spec.datastructures.blocks.SignedBeaconBlock internalBlock) { + super(internalBlock); + this.message = new BeaconBlockElectra(internalBlock.getMessage()); + } + + @Override + public BeaconBlockElectra getMessage() { + return message; + } + + @JsonCreator + public SignedBeaconBlockElectra( + @JsonProperty("message") final BeaconBlockElectra message, + @JsonProperty("signature") final BLSSignature signature) { + super(message, signature); + this.message = message; + } +} diff --git a/data/serializer/src/main/java/tech/pegasys/teku/api/schema/electra/SignedBlindedBeaconBlockElectra.java b/data/serializer/src/main/java/tech/pegasys/teku/api/schema/electra/SignedBlindedBeaconBlockElectra.java new file mode 100644 index 00000000000..747596dc4da --- /dev/null +++ b/data/serializer/src/main/java/tech/pegasys/teku/api/schema/electra/SignedBlindedBeaconBlockElectra.java @@ -0,0 +1,47 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.api.schema.electra; + +import static com.google.common.base.Preconditions.checkArgument; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import tech.pegasys.teku.api.schema.BLSSignature; +import tech.pegasys.teku.api.schema.SignedBeaconBlock; +import tech.pegasys.teku.api.schema.interfaces.SignedBlock; + +public class SignedBlindedBeaconBlockElectra extends SignedBeaconBlock implements SignedBlock { + private final BlindedBlockElectra message; + + public SignedBlindedBeaconBlockElectra( + tech.pegasys.teku.spec.datastructures.blocks.SignedBeaconBlock internalBlock) { + super(internalBlock); + checkArgument( + internalBlock.getMessage().getBody().isBlinded(), "requires a signed blinded beacon block"); + this.message = new BlindedBlockElectra(internalBlock.getMessage()); + } + + @Override + public BlindedBlockElectra getMessage() { + return message; + } + + @JsonCreator + public SignedBlindedBeaconBlockElectra( + @JsonProperty("message") final BlindedBlockElectra message, + @JsonProperty("signature") final BLSSignature signature) { + super(message, signature); + this.message = message; + } +} diff --git a/docker/jdk17/Dockerfile b/docker/jdk17/Dockerfile deleted file mode 100644 index 17d3fb7c843..00000000000 --- a/docker/jdk17/Dockerfile +++ /dev/null @@ -1,56 +0,0 @@ -FROM eclipse-temurin:17 as jre-build - -# Create a custom Java runtime -RUN JAVA_TOOL_OPTIONS="-Djdk.lang.Process.launchMechanism=vfork" $JAVA_HOME/bin/jlink \ - --add-modules ALL-MODULE-PATH \ - --strip-debug \ - --no-man-pages \ - --no-header-files \ - --compress=2 \ - --output /javaruntime - -FROM ubuntu:22.04 -ENV JAVA_HOME=/opt/java/openjdk -ENV PATH "${JAVA_HOME}/bin:${PATH}" -COPY --from=jre-build /javaruntime $JAVA_HOME - -RUN apt-get -y update && apt-get -y upgrade && apt-get -y install curl libc-bin libc6 && rm -rf /var/lib/api/lists/* -RUN adduser --disabled-password --gecos "" --home /opt/teku teku && \ - chown teku:teku /opt/teku && \ - chmod 0755 /opt/teku - -USER teku -WORKDIR /opt/teku - -# copy application (with libraries inside) -COPY --chown=teku:teku teku /opt/teku/ - -# Default to UTF-8 locale -ENV LANG C.UTF-8 - -ENV TEKU_REST_API_INTERFACE="0.0.0.0" -ENV TEKU_VALIDATOR_API_INTERFACE="0.0.0.0" -ENV TEKU_METRICS_INTERFACE="0.0.0.0" -ENV PATH "/opt/teku/bin:${PATH}" - -# List Exposed Ports -# Metrics, Rest API, LibP2P, Discv5 -EXPOSE 8008 5051 9000 9000/udp - -# specify default command -ENTRYPOINT ["/opt/teku/bin/teku"] - - -# Build-time metadata as defined at http://label-schema.org -ARG BUILD_DATE -ARG VCS_REF -ARG VERSION -LABEL org.label-schema.build-date=$BUILD_DATE \ - org.label-schema.name="Teku" \ - org.label-schema.description="Ethereum Consensus Client" \ - org.label-schema.url="https://docs.teku.consensys.io/" \ - org.label-schema.vcs-ref=$VCS_REF \ - org.label-schema.vcs-url="https://github.com/Consensys/teku.git" \ - org.label-schema.vendor="Consensys" \ - org.label-schema.version=$VERSION \ - org.label-schema.schema-version="1.0" diff --git a/docker/jdk21/Dockerfile b/docker/jdk21/Dockerfile index e2d9f233924..996efa66fcf 100644 --- a/docker/jdk21/Dockerfile +++ b/docker/jdk21/Dockerfile @@ -9,13 +9,20 @@ RUN JAVA_TOOL_OPTIONS="-Djdk.lang.Process.launchMechanism=vfork" $JAVA_HOME/bin/ --compress=2 \ --output /javaruntime -FROM ubuntu:22.04 +FROM ubuntu:24.04 ENV JAVA_HOME=/opt/java/openjdk ENV PATH "${JAVA_HOME}/bin:${PATH}" COPY --from=jre-build /javaruntime $JAVA_HOME -RUN apt-get -y update && apt-get -y upgrade && apt-get -y install curl libc-bin libc6 && rm -rf /var/lib/api/lists/* -RUN adduser --disabled-password --gecos "" --home /opt/teku teku && \ +RUN apt-get -y update && apt-get -y upgrade && apt-get -y install curl libc-bin libc6 adduser && \ + # Clean apt cache + apt-get clean && \ + rm -rf /var/cache/apt/archives/* && \ + rm -rf /var/lib/apt/lists/* + +# Ubuntu 23.10 and above comes with an "ubuntu" user with uid 1000. We need 1000 for teku. +RUN userdel ubuntu 2>/dev/null || true && rm -rf /home/ubuntu && \ + adduser --uid 1000 --disabled-password --gecos "" --home /opt/teku teku && \ chown teku:teku /opt/teku && \ chmod 0755 /opt/teku diff --git a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/schema/ExecutionPayloadV2.java b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/schema/ExecutionPayloadV2.java index 59ca7794e81..85e8632b54c 100644 --- a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/schema/ExecutionPayloadV2.java +++ b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/schema/ExecutionPayloadV2.java @@ -22,6 +22,7 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.units.bigints.UInt256; +import tech.pegasys.teku.ethereum.executionclient.schema.verkle.ExecutionWitness; import tech.pegasys.teku.infrastructure.bytes.Bytes20; import tech.pegasys.teku.infrastructure.ssz.SszList; import tech.pegasys.teku.infrastructure.ssz.collections.impl.SszByteListImpl; @@ -29,10 +30,13 @@ import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayload; import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadBuilder; import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadSchema; +import tech.pegasys.teku.spec.datastructures.execution.verkle.ExecutionWitnessSchema; import tech.pegasys.teku.spec.datastructures.execution.versions.capella.Withdrawal; +import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionPayloadElectra; public class ExecutionPayloadV2 extends ExecutionPayloadV1 { public final List withdrawals; + public final ExecutionWitness executionWitness; public ExecutionPayloadV2( @JsonProperty("parentHash") Bytes32 parentHash, @@ -49,7 +53,8 @@ public ExecutionPayloadV2( @JsonProperty("baseFeePerGas") UInt256 baseFeePerGas, @JsonProperty("blockHash") Bytes32 blockHash, @JsonProperty("transactions") List transactions, - @JsonProperty("withdrawals") List withdrawals) { + @JsonProperty("withdrawals") List withdrawals, + @JsonProperty("execution_witness") ExecutionWitness executionWitness) { super( parentHash, feeRecipient, @@ -66,10 +71,16 @@ public ExecutionPayloadV2( blockHash, transactions); this.withdrawals = withdrawals; + this.executionWitness = executionWitness; } - public static ExecutionPayloadV2 fromInternalExecutionPayload(ExecutionPayload executionPayload) { - List withdrawalsList = getWithdrawals(executionPayload.getOptionalWithdrawals()); + public static ExecutionPayloadV2 fromInternalExecutionPayload( + final ExecutionPayload executionPayload) { + final List withdrawalsList = + getWithdrawals(executionPayload.getOptionalWithdrawals()); + final ExecutionWitness executionWitness = + getExecutionWitness( + executionPayload.toVersionElectra().map(ExecutionPayloadElectra::getExecutionWitness)); return new ExecutionPayloadV2( executionPayload.getParentHash(), executionPayload.getFeeRecipient(), @@ -85,7 +96,8 @@ public static ExecutionPayloadV2 fromInternalExecutionPayload(ExecutionPayload e executionPayload.getBaseFeePerGas(), executionPayload.getBlockHash(), executionPayload.getTransactions().stream().map(SszByteListImpl::getBytes).toList(), - withdrawalsList); + withdrawalsList, + executionWitness); } @Override @@ -99,7 +111,12 @@ protected ExecutionPayloadBuilder applyToBuilder( .map( withdrawalV1 -> createInternalWithdrawal(withdrawalV1, executionPayloadSchema)) - .toList()); + .toList()) + .executionWitness( + () -> { + checkNotNull(executionWitness, "execution witness not provided when required"); + return createInternalExecutionWitness(executionWitness, executionPayloadSchema); + }); } private Withdrawal createInternalWithdrawal( @@ -127,4 +144,23 @@ public static List getWithdrawals( } return withdrawals; } + + public static ExecutionWitness getExecutionWitness( + final Optional + maybeExecutionWitness) { + if (maybeExecutionWitness.isEmpty()) { + return null; + } + + return new ExecutionWitness(maybeExecutionWitness.get()); + } + + private tech.pegasys.teku.spec.datastructures.execution.verkle.ExecutionWitness + createInternalExecutionWitness( + final ExecutionWitness executionWitness, + ExecutionPayloadSchema executionPayloadSchema) { + final ExecutionWitnessSchema executionWitnessSchema = + executionPayloadSchema.getExecutionWitnessSchemaRequired(); + return executionWitness.asInternalExecutionWitness(executionWitnessSchema); + } } diff --git a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/schema/ExecutionPayloadV3.java b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/schema/ExecutionPayloadV3.java index d15b5986cbf..b1bf2785fa4 100644 --- a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/schema/ExecutionPayloadV3.java +++ b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/schema/ExecutionPayloadV3.java @@ -22,6 +22,7 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.units.bigints.UInt256; +import tech.pegasys.teku.ethereum.executionclient.schema.verkle.ExecutionWitness; import tech.pegasys.teku.ethereum.executionclient.serialization.UInt64AsHexDeserializer; import tech.pegasys.teku.ethereum.executionclient.serialization.UInt64AsHexSerializer; import tech.pegasys.teku.infrastructure.bytes.Bytes20; @@ -31,6 +32,7 @@ import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadBuilder; import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadSchema; import tech.pegasys.teku.spec.datastructures.execution.versions.deneb.ExecutionPayloadDeneb; +import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionPayloadElectra; public class ExecutionPayloadV3 extends ExecutionPayloadV2 { @JsonSerialize(using = UInt64AsHexSerializer.class) @@ -57,6 +59,7 @@ public ExecutionPayloadV3( @JsonProperty("blockHash") Bytes32 blockHash, @JsonProperty("transactions") List transactions, @JsonProperty("withdrawals") List withdrawals, + @JsonProperty("execution_witness") ExecutionWitness executionWitness, @JsonProperty("blobGasUsed") UInt64 blobGasUsed, @JsonProperty("excessBlobGas") UInt64 excessBlobGas) { super( @@ -74,7 +77,8 @@ public ExecutionPayloadV3( baseFeePerGas, blockHash, transactions, - withdrawals); + withdrawals, + executionWitness); this.blobGasUsed = blobGasUsed; this.excessBlobGas = excessBlobGas; } @@ -83,6 +87,9 @@ public static ExecutionPayloadV3 fromInternalExecutionPayload( final ExecutionPayload executionPayload) { final List withdrawalsList = getWithdrawals(executionPayload.getOptionalWithdrawals()); + final ExecutionWitness executionWitness = + getExecutionWitness( + executionPayload.toVersionElectra().map(ExecutionPayloadElectra::getExecutionWitness)); return new ExecutionPayloadV3( executionPayload.getParentHash(), executionPayload.getFeeRecipient(), @@ -99,6 +106,7 @@ public static ExecutionPayloadV3 fromInternalExecutionPayload( executionPayload.getBlockHash(), executionPayload.getTransactions().stream().map(SszByteListImpl::getBytes).toList(), withdrawalsList, + executionWitness, executionPayload.toVersionDeneb().map(ExecutionPayloadDeneb::getBlobGasUsed).orElse(null), executionPayload .toVersionDeneb() diff --git a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/schema/verkle/ExecutionWitness.java b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/schema/verkle/ExecutionWitness.java new file mode 100644 index 00000000000..db160f02649 --- /dev/null +++ b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/schema/verkle/ExecutionWitness.java @@ -0,0 +1,62 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.ethereum.executionclient.schema.verkle; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import org.apache.tuweni.bytes.Bytes32; +import tech.pegasys.teku.spec.datastructures.execution.verkle.ExecutionWitnessSchema; +import tech.pegasys.teku.spec.datastructures.execution.verkle.StemStateDiffSchema; + +public class ExecutionWitness { + + @JsonProperty("stateDiff") + private final List stateDiff; + + @JsonProperty("verkleProof") + private final VerkleProof verkleProof; + + @JsonProperty("parentStateRoot") + private final Bytes32 parentStateRoot; + + public ExecutionWitness( + @JsonProperty("stateDiff") final List stateDiff, + @JsonProperty("verkleProof") final VerkleProof verkleProof, + @JsonProperty("parentStateRoot") final Bytes32 parentStateRoot) { + this.stateDiff = stateDiff; + this.verkleProof = verkleProof; + this.parentStateRoot = parentStateRoot; + } + + public ExecutionWitness( + final tech.pegasys.teku.spec.datastructures.execution.verkle.ExecutionWitness + executionWitness) { + this.stateDiff = executionWitness.getStateDiffs().stream().map(StemStateDiff::new).toList(); + this.verkleProof = new VerkleProof(executionWitness.getVerkleProof()); + this.parentStateRoot = executionWitness.getParentStateRoot(); + } + + public tech.pegasys.teku.spec.datastructures.execution.verkle.ExecutionWitness + asInternalExecutionWitness(final ExecutionWitnessSchema schema) { + return schema.create( + stateDiff.stream() + .map( + external -> + external.asInternalStemStateDiff( + (StemStateDiffSchema) schema.getStateDiffSchema().getElementSchema())) + .toList(), + verkleProof.asInternalVerkleProof(schema.getVerkleProofSchema()), + parentStateRoot); + } +} diff --git a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/schema/verkle/IpaProof.java b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/schema/verkle/IpaProof.java new file mode 100644 index 00000000000..e254f2c86cf --- /dev/null +++ b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/schema/verkle/IpaProof.java @@ -0,0 +1,61 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.ethereum.executionclient.schema.verkle; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import java.util.List; +import org.apache.tuweni.bytes.Bytes32; +import tech.pegasys.teku.ethereum.executionclient.serialization.Bytes32Deserializer; +import tech.pegasys.teku.ethereum.executionclient.serialization.BytesSerializer; +import tech.pegasys.teku.spec.datastructures.execution.verkle.IpaProofSchema; + +public class IpaProof { + + @JsonSerialize(contentUsing = BytesSerializer.class) + @JsonDeserialize(contentUsing = Bytes32Deserializer.class) + @JsonProperty("cl") + private final List cl; + + @JsonSerialize(contentUsing = BytesSerializer.class) + @JsonDeserialize(contentUsing = Bytes32Deserializer.class) + @JsonProperty("cr") + private final List cr; + + @JsonSerialize(using = BytesSerializer.class) + @JsonDeserialize(using = Bytes32Deserializer.class) + @JsonProperty("finalEvaluation") + private final Bytes32 finalEvaluation; + + public IpaProof( + @JsonProperty("cl") final List cl, + @JsonProperty("cr") final List cr, + @JsonProperty("finalEvaluation") final Bytes32 finalEvaluation) { + this.cl = cl; + this.cr = cr; + this.finalEvaluation = finalEvaluation; + } + + public IpaProof(final tech.pegasys.teku.spec.datastructures.execution.verkle.IpaProof ipaProof) { + this.cl = ipaProof.getCl(); + this.cr = ipaProof.getCr(); + this.finalEvaluation = ipaProof.getFinalEvaluation(); + } + + public tech.pegasys.teku.spec.datastructures.execution.verkle.IpaProof asInternalIpaProof( + final IpaProofSchema schema) { + return schema.create(cl, cr, finalEvaluation); + } +} diff --git a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/schema/verkle/StemStateDiff.java b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/schema/verkle/StemStateDiff.java new file mode 100644 index 00000000000..bf19faf2fc4 --- /dev/null +++ b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/schema/verkle/StemStateDiff.java @@ -0,0 +1,60 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.ethereum.executionclient.schema.verkle; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import java.util.List; +import tech.pegasys.teku.ethereum.executionclient.serialization.Bytes31Deserializer; +import tech.pegasys.teku.ethereum.executionclient.serialization.Bytes31Serializer; +import tech.pegasys.teku.infrastructure.bytes.Bytes31; +import tech.pegasys.teku.spec.datastructures.execution.verkle.StemStateDiffSchema; +import tech.pegasys.teku.spec.datastructures.execution.verkle.SuffixStateDiffSchema; + +public class StemStateDiff { + + @JsonSerialize(using = Bytes31Serializer.class) + @JsonDeserialize(using = Bytes31Deserializer.class) + @JsonProperty("stem") + private final Bytes31 stem; + + @JsonProperty("suffixDiffs") + private final List suffixDiffs; + + public StemStateDiff( + @JsonProperty("stem") final Bytes31 stem, + @JsonProperty("suffixDiffs") final List suffixDiffs) { + this.stem = stem; + this.suffixDiffs = suffixDiffs; + } + + public StemStateDiff( + final tech.pegasys.teku.spec.datastructures.execution.verkle.StemStateDiff stemStateDiff) { + this.stem = stemStateDiff.getStem(); + this.suffixDiffs = stemStateDiff.getStateDiffs().stream().map(SuffixStateDiff::new).toList(); + } + + public tech.pegasys.teku.spec.datastructures.execution.verkle.StemStateDiff + asInternalStemStateDiff(final StemStateDiffSchema schema) { + return schema.create( + stem, + suffixDiffs.stream() + .map( + external -> + external.asInternalSuffixStateDiff( + (SuffixStateDiffSchema) schema.getSuffixDiffsSchema().getElementSchema())) + .toList()); + } +} diff --git a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/schema/verkle/SuffixStateDiff.java b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/schema/verkle/SuffixStateDiff.java new file mode 100644 index 00000000000..90a8265e2df --- /dev/null +++ b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/schema/verkle/SuffixStateDiff.java @@ -0,0 +1,65 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.ethereum.executionclient.schema.verkle; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import java.util.Optional; +import org.apache.tuweni.bytes.Bytes32; +import tech.pegasys.teku.ethereum.executionclient.serialization.ByteUInt8Serializer; +import tech.pegasys.teku.ethereum.executionclient.serialization.ByteUint8Deserializer; +import tech.pegasys.teku.ethereum.executionclient.serialization.Bytes32Deserializer; +import tech.pegasys.teku.ethereum.executionclient.serialization.BytesSerializer; +import tech.pegasys.teku.spec.datastructures.execution.verkle.SuffixStateDiffSchema; + +public class SuffixStateDiff { + + @JsonSerialize(using = ByteUInt8Serializer.class) + @JsonDeserialize(using = ByteUint8Deserializer.class) + @JsonProperty("suffix") + private final Byte suffix; + + @JsonSerialize(using = BytesSerializer.class) + @JsonDeserialize(using = Bytes32Deserializer.class) + @JsonProperty("currentValue") + private final Bytes32 currentValue; + + @JsonSerialize(using = BytesSerializer.class) + @JsonDeserialize(using = Bytes32Deserializer.class) + @JsonProperty("newValue") + private final Bytes32 newValue; + + public SuffixStateDiff( + @JsonProperty("suffix") final Byte suffix, + @JsonProperty("currentValue") Bytes32 currentValue, + @JsonProperty("newValue") Bytes32 newValue) { + this.suffix = suffix; + this.currentValue = currentValue; + this.newValue = newValue; + } + + public SuffixStateDiff( + final tech.pegasys.teku.spec.datastructures.execution.verkle.SuffixStateDiff + suffixStateDiff) { + this.suffix = suffixStateDiff.getSuffix(); + this.currentValue = suffixStateDiff.getCurrentValue().orElse(null); + this.newValue = suffixStateDiff.getNewValue().orElse(null); + } + + public tech.pegasys.teku.spec.datastructures.execution.verkle.SuffixStateDiff + asInternalSuffixStateDiff(final SuffixStateDiffSchema schema) { + return schema.create(suffix, Optional.ofNullable(currentValue), Optional.ofNullable(newValue)); + } +} diff --git a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/schema/verkle/VerkleProof.java b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/schema/verkle/VerkleProof.java new file mode 100644 index 00000000000..dbd51c70815 --- /dev/null +++ b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/schema/verkle/VerkleProof.java @@ -0,0 +1,86 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.ethereum.executionclient.schema.verkle; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import java.util.List; +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; +import tech.pegasys.teku.ethereum.executionclient.serialization.Bytes31Deserializer; +import tech.pegasys.teku.ethereum.executionclient.serialization.Bytes31Serializer; +import tech.pegasys.teku.ethereum.executionclient.serialization.Bytes32Deserializer; +import tech.pegasys.teku.ethereum.executionclient.serialization.BytesDeserializer; +import tech.pegasys.teku.ethereum.executionclient.serialization.BytesSerializer; +import tech.pegasys.teku.infrastructure.bytes.Bytes31; +import tech.pegasys.teku.spec.datastructures.execution.verkle.VerkleProofSchema; + +public class VerkleProof { + + @JsonSerialize(contentUsing = Bytes31Serializer.class) + @JsonDeserialize(contentUsing = Bytes31Deserializer.class) + @JsonProperty("otherStems") + private final List otherStems; + + @JsonSerialize(using = BytesSerializer.class) + @JsonDeserialize(using = BytesDeserializer.class) + @JsonProperty("depthExtensionPresent") + private final Bytes depthExtensionPresent; + + @JsonSerialize(contentUsing = BytesSerializer.class) + @JsonDeserialize(contentUsing = Bytes32Deserializer.class) + @JsonProperty("commitmentsByPath") + private final List commitmentsByPath; + + @JsonSerialize(using = BytesSerializer.class) + @JsonDeserialize(using = Bytes32Deserializer.class) + @JsonProperty("d") + private final Bytes32 d; + + @JsonProperty("ipaProof") + private final IpaProof ipaProof; + + public VerkleProof( + @JsonProperty("otherStems") final List otherStems, + @JsonProperty("depthExtensionPresent") final Bytes depthExtensionPresent, + @JsonProperty("commitmentsByPath") final List commitmentsByPath, + @JsonProperty("d") final Bytes32 d, + @JsonProperty("ipaProof") final IpaProof ipaProof) { + this.otherStems = otherStems; + this.depthExtensionPresent = depthExtensionPresent; + this.commitmentsByPath = commitmentsByPath; + this.d = d; + this.ipaProof = ipaProof; + } + + public VerkleProof( + final tech.pegasys.teku.spec.datastructures.execution.verkle.VerkleProof verkleProof) { + this.otherStems = verkleProof.getOtherStems(); + this.depthExtensionPresent = verkleProof.getDepthExtensionPresent(); + this.commitmentsByPath = verkleProof.getCommitmentsByPath(); + this.d = verkleProof.getD(); + this.ipaProof = new IpaProof(verkleProof.getIpaProof()); + } + + public tech.pegasys.teku.spec.datastructures.execution.verkle.VerkleProof asInternalVerkleProof( + final VerkleProofSchema schema) { + return schema.create( + otherStems, + depthExtensionPresent, + commitmentsByPath, + d, + ipaProof.asInternalIpaProof(schema.getIpaProofSchema())); + } +} diff --git a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/serialization/ByteUInt8Serializer.java b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/serialization/ByteUInt8Serializer.java new file mode 100644 index 00000000000..767e4c095a5 --- /dev/null +++ b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/serialization/ByteUInt8Serializer.java @@ -0,0 +1,27 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.ethereum.executionclient.serialization; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import java.io.IOException; + +public class ByteUInt8Serializer extends JsonSerializer { + @Override + public void serialize(Byte value, JsonGenerator gen, SerializerProvider provider) + throws IOException { + gen.writeNumber(Byte.toUnsignedInt(value)); + } +} diff --git a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/serialization/ByteUint8Deserializer.java b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/serialization/ByteUint8Deserializer.java new file mode 100644 index 00000000000..a3c48771546 --- /dev/null +++ b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/serialization/ByteUint8Deserializer.java @@ -0,0 +1,27 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.ethereum.executionclient.serialization; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import java.io.IOException; + +public class ByteUint8Deserializer extends JsonDeserializer { + + @Override + public Byte deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + return (byte) p.getIntValue(); + } +} diff --git a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/serialization/Bytes31Deserializer.java b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/serialization/Bytes31Deserializer.java new file mode 100644 index 00000000000..fa2494d7211 --- /dev/null +++ b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/serialization/Bytes31Deserializer.java @@ -0,0 +1,28 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.ethereum.executionclient.serialization; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import java.io.IOException; +import tech.pegasys.teku.infrastructure.bytes.Bytes31; + +public class Bytes31Deserializer extends JsonDeserializer { + + @Override + public Bytes31 deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + return Bytes31.fromHexString(p.getValueAsString()); + } +} diff --git a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/serialization/Bytes31Serializer.java b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/serialization/Bytes31Serializer.java new file mode 100644 index 00000000000..2a2453ec4b8 --- /dev/null +++ b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/serialization/Bytes31Serializer.java @@ -0,0 +1,29 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.ethereum.executionclient.serialization; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import java.io.IOException; +import java.util.Locale; +import tech.pegasys.teku.infrastructure.bytes.Bytes31; + +public class Bytes31Serializer extends JsonSerializer { + @Override + public void serialize(Bytes31 value, JsonGenerator gen, SerializerProvider serializers) + throws IOException { + gen.writeString(value.toHexString().toLowerCase(Locale.ROOT)); + } +} diff --git a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/serialization/UInt8Deserializer.java b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/serialization/UInt8Deserializer.java new file mode 100644 index 00000000000..aa9683aeaad --- /dev/null +++ b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/serialization/UInt8Deserializer.java @@ -0,0 +1,27 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.ethereum.executionclient.serialization; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import java.io.IOException; + +public class UInt8Deserializer extends JsonDeserializer { + @Override + public Byte deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + final int intValue = p.getValueAsInt(); + return (byte) intValue; + } +} diff --git a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/serialization/UInt8Serializer.java b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/serialization/UInt8Serializer.java new file mode 100644 index 00000000000..a75e8c770cc --- /dev/null +++ b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/serialization/UInt8Serializer.java @@ -0,0 +1,27 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.ethereum.executionclient.serialization; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import java.io.IOException; + +public class UInt8Serializer extends JsonSerializer { + @Override + public void serialize(Byte value, JsonGenerator gen, SerializerProvider serializers) + throws IOException { + gen.writeNumber(Byte.toUnsignedInt(value)); + } +} diff --git a/ethereum/executionlayer/src/main/java/tech/pegasys/teku/ethereum/executionlayer/MilestoneBasedEngineJsonRpcMethodsResolver.java b/ethereum/executionlayer/src/main/java/tech/pegasys/teku/ethereum/executionlayer/MilestoneBasedEngineJsonRpcMethodsResolver.java index c91f739f98f..39edaf267ee 100644 --- a/ethereum/executionlayer/src/main/java/tech/pegasys/teku/ethereum/executionlayer/MilestoneBasedEngineJsonRpcMethodsResolver.java +++ b/ethereum/executionlayer/src/main/java/tech/pegasys/teku/ethereum/executionlayer/MilestoneBasedEngineJsonRpcMethodsResolver.java @@ -68,6 +68,9 @@ public MilestoneBasedEngineJsonRpcMethodsResolver( case CAPELLA: methodsByMilestone.put(milestone, capellaSupportedMethods()); break; + case ELECTRA: + methodsByMilestone.put(milestone, electraSupportedMethods()); + break; case DENEB: methodsByMilestone.put(milestone, denebSupportedMethods()); break; @@ -95,6 +98,16 @@ private Map> capellaSupportedMethods() { return methods; } + private Map> electraSupportedMethods() { + final Map> methods = new HashMap<>(); + + methods.put(ENGINE_NEW_PAYLOAD, new EngineNewPayloadV2(executionEngineClient)); + methods.put(ENGINE_GET_PAYLOAD, new EngineGetPayloadV2(executionEngineClient, spec)); + methods.put(ENGINE_FORK_CHOICE_UPDATED, new EngineForkChoiceUpdatedV2(executionEngineClient)); + + return methods; + } + private Map> denebSupportedMethods() { final Map> methods = new HashMap<>(); diff --git a/ethereum/executionlayer/src/test/java/tech/pegasys/teku/ethereum/executionlayer/BuilderBidValidatorTest.java b/ethereum/executionlayer/src/test/java/tech/pegasys/teku/ethereum/executionlayer/BuilderBidValidatorTest.java index 9f637c91f55..f08d78aa085 100644 --- a/ethereum/executionlayer/src/test/java/tech/pegasys/teku/ethereum/executionlayer/BuilderBidValidatorTest.java +++ b/ethereum/executionlayer/src/test/java/tech/pegasys/teku/ethereum/executionlayer/BuilderBidValidatorTest.java @@ -295,6 +295,7 @@ private ExecutionPayloadHeader createExecutionPayloadHeaderWithGasLimit( .blockHash(Bytes32.random()) .transactionsRoot(Bytes32.ZERO) .withdrawalsRoot(() -> Bytes32.ZERO) + .executionWitnessRoot(() -> Bytes32.ZERO) .blobGasUsed(() -> UInt64.ONE) .excessBlobGas(() -> UInt64.ONE)); } diff --git a/ethereum/networks/src/main/java/tech/pegasys/teku/networks/Eth2NetworkConfiguration.java b/ethereum/networks/src/main/java/tech/pegasys/teku/networks/Eth2NetworkConfiguration.java index 3de702e159c..f0053d0cf46 100644 --- a/ethereum/networks/src/main/java/tech/pegasys/teku/networks/Eth2NetworkConfiguration.java +++ b/ethereum/networks/src/main/java/tech/pegasys/teku/networks/Eth2NetworkConfiguration.java @@ -83,6 +83,7 @@ public class Eth2NetworkConfiguration { private final Optional altairForkEpoch; private final Optional bellatrixForkEpoch; private final Optional capellaForkEpoch; + private final Optional electraForkEpoch; private final Optional denebForkEpoch; private final Eth1Address eth1DepositContractAddress; private final Optional eth1DepositContractDeployBlock; @@ -112,6 +113,7 @@ private Eth2NetworkConfiguration( final Optional altairForkEpoch, final Optional bellatrixForkEpoch, final Optional capellaForkEpoch, + final Optional electraForkEpoch, final Optional denebForkEpoch, final Optional terminalBlockHashOverride, final Optional totalTerminalDifficultyOverride, @@ -133,6 +135,7 @@ private Eth2NetworkConfiguration( this.altairForkEpoch = altairForkEpoch; this.bellatrixForkEpoch = bellatrixForkEpoch; this.capellaForkEpoch = capellaForkEpoch; + this.electraForkEpoch = electraForkEpoch; this.denebForkEpoch = denebForkEpoch; this.eth1DepositContractAddress = eth1DepositContractAddress == null @@ -212,6 +215,7 @@ public Optional getForkEpoch(final SpecMilestone specMilestone) { case ALTAIR -> altairForkEpoch; case BELLATRIX -> bellatrixForkEpoch; case CAPELLA -> capellaForkEpoch; + case ELECTRA -> electraForkEpoch; case DENEB -> denebForkEpoch; default -> Optional.empty(); }; @@ -288,6 +292,7 @@ public static class Builder { private Optional altairForkEpoch = Optional.empty(); private Optional bellatrixForkEpoch = Optional.empty(); private Optional capellaForkEpoch = Optional.empty(); + private Optional electraForkEpoch = Optional.empty(); private Optional denebForkEpoch = Optional.empty(); private Optional terminalBlockHashOverride = Optional.empty(); private Optional totalTerminalDifficultyOverride = Optional.empty(); @@ -332,6 +337,9 @@ public Eth2NetworkConfiguration build() { builder.capellaBuilder( capellaBuilder -> capellaForkEpoch.ifPresent(capellaBuilder::capellaForkEpoch)); + builder.electraBuilder( + electraBuilder -> + electraForkEpoch.ifPresent(electraBuilder::electraForkEpoch)); builder.denebBuilder( denebBuilder -> { denebForkEpoch.ifPresent(denebBuilder::denebForkEpoch); @@ -369,6 +377,7 @@ public Eth2NetworkConfiguration build() { altairForkEpoch, bellatrixForkEpoch, capellaForkEpoch, + electraForkEpoch, denebForkEpoch, terminalBlockHashOverride, totalTerminalDifficultyOverride, @@ -557,6 +566,11 @@ public Builder capellaForkEpoch(final UInt64 capellaForkEpoch) { return this; } + public Builder electraForkEpoch(final UInt64 electraForkEpoch) { + this.electraForkEpoch = Optional.of(electraForkEpoch); + return this; + } + public Builder denebForkEpoch(final UInt64 denebForkEpoch) { this.denebForkEpoch = Optional.of(denebForkEpoch); return this; diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/SpecFactory.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/SpecFactory.java index a6d3cd83e70..e2983d9dcb9 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/SpecFactory.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/SpecFactory.java @@ -17,6 +17,7 @@ import static tech.pegasys.teku.spec.SpecMilestone.BELLATRIX; import static tech.pegasys.teku.spec.SpecMilestone.CAPELLA; import static tech.pegasys.teku.spec.SpecMilestone.DENEB; +import static tech.pegasys.teku.spec.SpecMilestone.ELECTRA; import static tech.pegasys.teku.spec.SpecMilestone.PHASE0; import static tech.pegasys.teku.spec.config.SpecConfig.FAR_FUTURE_EPOCH; @@ -27,6 +28,7 @@ import tech.pegasys.teku.spec.config.SpecConfigBellatrix; import tech.pegasys.teku.spec.config.SpecConfigCapella; import tech.pegasys.teku.spec.config.SpecConfigDeneb; +import tech.pegasys.teku.spec.config.SpecConfigElectra; import tech.pegasys.teku.spec.config.SpecConfigLoader; import tech.pegasys.teku.spec.config.builder.SpecConfigBuilder; @@ -54,12 +56,19 @@ public static Spec create(final SpecConfig config) { .toVersionCapella() .map(SpecConfigCapella::getCapellaForkEpoch) .orElse(FAR_FUTURE_EPOCH); + final UInt64 electraForkEpoch = + config + .toVersionElectra() + .map(SpecConfigElectra::getElectraForkEpoch) + .orElse(FAR_FUTURE_EPOCH); final UInt64 denebForkEpoch = config.toVersionDeneb().map(SpecConfigDeneb::getDenebForkEpoch).orElse(FAR_FUTURE_EPOCH); final SpecMilestone highestMilestoneSupported; if (!denebForkEpoch.equals(FAR_FUTURE_EPOCH)) { highestMilestoneSupported = DENEB; + } else if (!electraForkEpoch.equals(FAR_FUTURE_EPOCH)) { + highestMilestoneSupported = ELECTRA; } else if (!capellaForkEpoch.equals(FAR_FUTURE_EPOCH)) { highestMilestoneSupported = CAPELLA; } else if (!bellatrixForkEpoch.equals(FAR_FUTURE_EPOCH)) { diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/SpecMilestone.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/SpecMilestone.java index 16d83cc969e..67daf39d086 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/SpecMilestone.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/SpecMilestone.java @@ -26,12 +26,14 @@ import tech.pegasys.teku.spec.config.SpecConfigBellatrix; import tech.pegasys.teku.spec.config.SpecConfigCapella; import tech.pegasys.teku.spec.config.SpecConfigDeneb; +import tech.pegasys.teku.spec.config.SpecConfigElectra; public enum SpecMilestone { PHASE0, ALTAIR, BELLATRIX, CAPELLA, + ELECTRA, DENEB; /** @@ -49,7 +51,8 @@ public SpecMilestone getPreviousMilestone() { if (equals(PHASE0)) { throw new IllegalArgumentException("There is no milestone prior to Phase0"); } - return SpecMilestone.values()[ordinal() - 1]; + final List priorMilestones = getAllPriorMilestones(this); + return priorMilestones.getLast(); } /** @@ -111,6 +114,8 @@ static Optional getForkVersion( return specConfig.toVersionBellatrix().map(SpecConfigBellatrix::getBellatrixForkVersion); case CAPELLA: return specConfig.toVersionCapella().map(SpecConfigCapella::getCapellaForkVersion); + case ELECTRA: + return specConfig.toVersionElectra().map(SpecConfigElectra::getElectraForkVersion); case DENEB: return specConfig.toVersionDeneb().map(SpecConfigDeneb::getDenebForkVersion); default: @@ -130,6 +135,8 @@ static Optional getForkEpoch(final SpecConfig specConfig, final SpecMile return specConfig.toVersionBellatrix().map(SpecConfigBellatrix::getBellatrixForkEpoch); case CAPELLA: return specConfig.toVersionCapella().map(SpecConfigCapella::getCapellaForkEpoch); + case ELECTRA: + return specConfig.toVersionElectra().map(SpecConfigElectra::getElectraForkEpoch); case DENEB: return specConfig.toVersionDeneb().map(SpecConfigDeneb::getDenebForkEpoch); default: diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/SpecVersion.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/SpecVersion.java index 3231888f7dc..8431f27b6c7 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/SpecVersion.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/SpecVersion.java @@ -19,18 +19,21 @@ import tech.pegasys.teku.spec.config.SpecConfigBellatrix; import tech.pegasys.teku.spec.config.SpecConfigCapella; import tech.pegasys.teku.spec.config.SpecConfigDeneb; +import tech.pegasys.teku.spec.config.SpecConfigElectra; import tech.pegasys.teku.spec.logic.DelegatingSpecLogic; import tech.pegasys.teku.spec.logic.SpecLogic; import tech.pegasys.teku.spec.logic.versions.altair.SpecLogicAltair; import tech.pegasys.teku.spec.logic.versions.bellatrix.SpecLogicBellatrix; import tech.pegasys.teku.spec.logic.versions.capella.SpecLogicCapella; import tech.pegasys.teku.spec.logic.versions.deneb.SpecLogicDeneb; +import tech.pegasys.teku.spec.logic.versions.electra.SpecLogicElectra; import tech.pegasys.teku.spec.logic.versions.phase0.SpecLogicPhase0; import tech.pegasys.teku.spec.schemas.SchemaDefinitions; import tech.pegasys.teku.spec.schemas.SchemaDefinitionsAltair; import tech.pegasys.teku.spec.schemas.SchemaDefinitionsBellatrix; import tech.pegasys.teku.spec.schemas.SchemaDefinitionsCapella; import tech.pegasys.teku.spec.schemas.SchemaDefinitionsDeneb; +import tech.pegasys.teku.spec.schemas.SchemaDefinitionsElectra; import tech.pegasys.teku.spec.schemas.SchemaDefinitionsPhase0; public class SpecVersion extends DelegatingSpecLogic { @@ -56,6 +59,7 @@ public static Optional create( case ALTAIR -> specConfig.toVersionAltair().map(SpecVersion::createAltair); case BELLATRIX -> specConfig.toVersionBellatrix().map(SpecVersion::createBellatrix); case CAPELLA -> specConfig.toVersionCapella().map(SpecVersion::createCapella); + case ELECTRA -> specConfig.toVersionElectra().map(SpecVersion::createElectra); case DENEB -> specConfig.toVersionDeneb().map(SpecVersion::createDeneb); }; } @@ -84,6 +88,12 @@ static SpecVersion createCapella(final SpecConfigCapella specConfig) { return new SpecVersion(SpecMilestone.CAPELLA, specConfig, schemaDefinitions, specLogic); } + static SpecVersion createElectra(final SpecConfigElectra specConfig) { + final SchemaDefinitionsElectra schemaDefinitions = new SchemaDefinitionsElectra(specConfig); + final SpecLogicElectra specLogic = SpecLogicElectra.create(specConfig, schemaDefinitions); + return new SpecVersion(SpecMilestone.ELECTRA, specConfig, schemaDefinitions, specLogic); + } + static SpecVersion createDeneb(final SpecConfigDeneb specConfig) { final SchemaDefinitionsDeneb schemaDefinitions = new SchemaDefinitionsDeneb(specConfig); final SpecLogicDeneb specLogic = SpecLogicDeneb.create(specConfig, schemaDefinitions); diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/config/DelegatingSpecConfigElectra.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/config/DelegatingSpecConfigElectra.java new file mode 100644 index 00000000000..37560537298 --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/config/DelegatingSpecConfigElectra.java @@ -0,0 +1,63 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.config; + +import java.util.Optional; +import tech.pegasys.teku.infrastructure.bytes.Bytes4; +import tech.pegasys.teku.infrastructure.unsigned.UInt64; + +public class DelegatingSpecConfigElectra extends DelegatingSpecConfigCapella + implements SpecConfigElectra { + private final SpecConfigElectra specConfigElectra; + + public DelegatingSpecConfigElectra(final SpecConfigElectra specConfig) { + super(specConfig); + this.specConfigElectra = SpecConfigElectra.required(specConfig); + } + + @Override + public Optional toVersionElectra() { + return Optional.of(this); + } + + @Override + public Bytes4 getElectraForkVersion() { + return specConfigElectra.getElectraForkVersion(); + } + + @Override + public UInt64 getElectraForkEpoch() { + return specConfigElectra.getElectraForkEpoch(); + } + + @Override + public int getMaxStems() { + return specConfigElectra.getMaxStems(); + } + + @Override + public int getMaxCommitmentsPerStem() { + return specConfigElectra.getMaxCommitmentsPerStem(); + } + + @Override + public int getVerkleWidth() { + return specConfigElectra.getVerkleWidth(); + } + + @Override + public int getIpaProofDepth() { + return specConfigElectra.getIpaProofDepth(); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/config/SpecConfig.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/config/SpecConfig.java index a3273edbea0..a36893c91db 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/config/SpecConfig.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/config/SpecConfig.java @@ -179,6 +179,10 @@ default Optional toVersionCapella() { return Optional.empty(); } + default Optional toVersionElectra() { + return Optional.empty(); + } + default Optional toVersionDeneb() { return Optional.empty(); } diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/config/SpecConfigDeneb.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/config/SpecConfigDeneb.java index aa4296251be..379347c70da 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/config/SpecConfigDeneb.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/config/SpecConfigDeneb.java @@ -19,7 +19,7 @@ import tech.pegasys.teku.infrastructure.bytes.Bytes4; import tech.pegasys.teku.infrastructure.unsigned.UInt64; -public interface SpecConfigDeneb extends SpecConfigCapella, NetworkingSpecConfigDeneb { +public interface SpecConfigDeneb extends SpecConfigElectra, NetworkingSpecConfigDeneb { BigInteger BLS_MODULUS = new BigInteger( "52435875175126190479447740508185965837690552500527637822603658699938581184513"); diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/config/SpecConfigDenebImpl.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/config/SpecConfigDenebImpl.java index 53ced36b5af..16fbe3a8b7a 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/config/SpecConfigDenebImpl.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/config/SpecConfigDenebImpl.java @@ -18,7 +18,7 @@ import tech.pegasys.teku.infrastructure.bytes.Bytes4; import tech.pegasys.teku.infrastructure.unsigned.UInt64; -public class SpecConfigDenebImpl extends DelegatingSpecConfigCapella implements SpecConfigDeneb { +public class SpecConfigDenebImpl extends DelegatingSpecConfigElectra implements SpecConfigDeneb { private final Bytes4 denebForkVersion; private final UInt64 denebForkEpoch; @@ -35,7 +35,7 @@ public class SpecConfigDenebImpl extends DelegatingSpecConfigCapella implements private final Optional maybeEpochsStoreBlobs; public SpecConfigDenebImpl( - final SpecConfigCapella specConfig, + final SpecConfigElectra specConfig, final Bytes4 denebForkVersion, final UInt64 denebForkEpoch, final int maxPerEpochActivationChurnLimit, diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/config/SpecConfigElectra.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/config/SpecConfigElectra.java new file mode 100644 index 00000000000..93d216a6d39 --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/config/SpecConfigElectra.java @@ -0,0 +1,46 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.config; + +import java.util.Optional; +import tech.pegasys.teku.infrastructure.bytes.Bytes4; +import tech.pegasys.teku.infrastructure.unsigned.UInt64; + +public interface SpecConfigElectra extends SpecConfigCapella { + + static SpecConfigElectra required(SpecConfig specConfig) { + return specConfig + .toVersionElectra() + .orElseThrow( + () -> + new IllegalArgumentException( + "Expected Electra spec config but got: " + + specConfig.getClass().getSimpleName())); + } + + Bytes4 getElectraForkVersion(); + + UInt64 getElectraForkEpoch(); + + @Override + Optional toVersionElectra(); + + int getMaxStems(); + + int getMaxCommitmentsPerStem(); + + int getVerkleWidth(); + + int getIpaProofDepth(); +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/config/SpecConfigElectraImpl.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/config/SpecConfigElectraImpl.java new file mode 100644 index 00000000000..e55fd05fc42 --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/config/SpecConfigElectraImpl.java @@ -0,0 +1,113 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.config; + +import java.util.Objects; +import java.util.Optional; +import tech.pegasys.teku.infrastructure.bytes.Bytes4; +import tech.pegasys.teku.infrastructure.unsigned.UInt64; + +public class SpecConfigElectraImpl extends DelegatingSpecConfigCapella + implements SpecConfigElectra { + + private final Bytes4 electraForkVersion; + private final UInt64 electraForkEpoch; + + private final int maxStems; + private final int maxCommitmentsPerStem; + private final int verkleWidth; + private final int ipaProofDepth; + + public SpecConfigElectraImpl( + final SpecConfigCapella specConfig, + final Bytes4 electraForkVersion, + final UInt64 electraForkEpoch, + final int maxStems, + final int maxCommitmentsPerStem, + final int verkleWidth, + final int ipaProofDepth) { + super(specConfig); + this.electraForkVersion = electraForkVersion; + this.electraForkEpoch = electraForkEpoch; + this.maxStems = maxStems; + this.maxCommitmentsPerStem = maxCommitmentsPerStem; + this.verkleWidth = verkleWidth; + this.ipaProofDepth = ipaProofDepth; + } + + @Override + public Bytes4 getElectraForkVersion() { + return electraForkVersion; + } + + @Override + public UInt64 getElectraForkEpoch() { + return electraForkEpoch; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final SpecConfigElectraImpl that = (SpecConfigElectraImpl) o; + return Objects.equals(specConfig, that.specConfig) + && Objects.equals(electraForkVersion, that.electraForkVersion) + && Objects.equals(electraForkEpoch, that.electraForkEpoch) + && maxStems == that.maxStems + && maxCommitmentsPerStem == that.maxCommitmentsPerStem + && verkleWidth == that.verkleWidth + && ipaProofDepth == that.ipaProofDepth; + } + + @Override + public int hashCode() { + return Objects.hash( + specConfig, + electraForkVersion, + electraForkEpoch, + maxStems, + maxCommitmentsPerStem, + verkleWidth, + ipaProofDepth); + } + + @Override + public int getMaxStems() { + return maxStems; + } + + @Override + public int getMaxCommitmentsPerStem() { + return maxCommitmentsPerStem; + } + + @Override + public int getVerkleWidth() { + return verkleWidth; + } + + @Override + public int getIpaProofDepth() { + return ipaProofDepth; + } + + @Override + public Optional toVersionElectra() { + return Optional.of(this); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/config/SpecConfigLoader.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/config/SpecConfigLoader.java index 7799664b9a3..ce9d80bfb0e 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/config/SpecConfigLoader.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/config/SpecConfigLoader.java @@ -32,7 +32,7 @@ public class SpecConfigLoader { private static final Logger LOG = LogManager.getLogger(); private static final List AVAILABLE_PRESETS = - List.of("phase0", "altair", "bellatrix", "capella", "deneb"); + List.of("phase0", "altair", "bellatrix", "capella", "electra", "deneb"); private static final String CONFIG_PATH = "configs/"; private static final String PRESET_PATH = "presets/"; diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/config/SpecConfigReader.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/config/SpecConfigReader.java index ccab382ddbb..ff89ef90e42 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/config/SpecConfigReader.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/config/SpecConfigReader.java @@ -48,6 +48,7 @@ import tech.pegasys.teku.spec.config.builder.BellatrixBuilder; import tech.pegasys.teku.spec.config.builder.CapellaBuilder; import tech.pegasys.teku.spec.config.builder.DenebBuilder; +import tech.pegasys.teku.spec.config.builder.ElectraBuilder; import tech.pegasys.teku.spec.config.builder.SpecConfigBuilder; public class SpecConfigReader { @@ -186,6 +187,16 @@ public void loadFromMap( unprocessedConfig.remove(constantKey); }); + // Process electra config + streamConfigSetters(ElectraBuilder.class) + .forEach( + setter -> { + final String constantKey = camelToSnakeCase(setter.getName()); + final Object rawValue = unprocessedConfig.get(constantKey); + invokeSetter(setter, configBuilder::electraBuilder, constantKey, rawValue); + unprocessedConfig.remove(constantKey); + }); + // Process Deneb config streamConfigSetters(DenebBuilder.class) .forEach( diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/config/builder/DenebBuilder.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/config/builder/DenebBuilder.java index 2ddd5990e00..533c8a8ec1c 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/config/builder/DenebBuilder.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/config/builder/DenebBuilder.java @@ -23,11 +23,11 @@ import tech.pegasys.teku.infrastructure.bytes.Bytes4; import tech.pegasys.teku.infrastructure.unsigned.UInt64; import tech.pegasys.teku.spec.config.SpecConfig; -import tech.pegasys.teku.spec.config.SpecConfigCapella; import tech.pegasys.teku.spec.config.SpecConfigDeneb; import tech.pegasys.teku.spec.config.SpecConfigDenebImpl; +import tech.pegasys.teku.spec.config.SpecConfigElectra; -public class DenebBuilder implements ForkConfigBuilder { +public class DenebBuilder implements ForkConfigBuilder { private Bytes4 denebForkVersion; private UInt64 denebForkEpoch; @@ -46,7 +46,7 @@ public class DenebBuilder implements ForkConfigBuilder { + + private Bytes4 electraForkVersion; + private UInt64 electraForkEpoch; + + private Integer maxStems; + private Integer maxCommitmentsPerStem; + private Integer verkleWidth; + private Integer ipaProofDepth; + + ElectraBuilder() {} + + @Override + public SpecConfigElectra build(final SpecConfigCapella specConfig) { + return new SpecConfigElectraImpl( + specConfig, + electraForkVersion, + electraForkEpoch, + maxStems, + maxCommitmentsPerStem, + verkleWidth, + ipaProofDepth); + } + + public ElectraBuilder electraForkEpoch(final UInt64 electraForkEpoch) { + checkNotNull(electraForkEpoch); + this.electraForkEpoch = electraForkEpoch; + return this; + } + + public ElectraBuilder electraForkVersion(final Bytes4 electraForkVersion) { + checkNotNull(electraForkVersion); + this.electraForkVersion = electraForkVersion; + return this; + } + + public ElectraBuilder maxStems(final Integer maxStems) { + this.maxStems = maxStems; + return this; + } + + public ElectraBuilder maxCommitmentsPerStem(final Integer maxCommitmentsPerStem) { + this.maxCommitmentsPerStem = maxCommitmentsPerStem; + return this; + } + + public ElectraBuilder verkleWidth(final Integer verkleWidth) { + this.verkleWidth = verkleWidth; + return this; + } + + public ElectraBuilder ipaProofDepth(final Integer ipaProofDepth) { + this.ipaProofDepth = ipaProofDepth; + return this; + } + + public UInt64 getElectraForkEpoch() { + return electraForkEpoch; + } + + @Override + public void validate() { + if (electraForkEpoch == null) { + // Config doesn't include Electra configuration but we need some values for the REST API + // type definitions. + // Provide MainNet-like defaults and ensure Electra isn't actually supported + electraForkEpoch = SpecConfig.FAR_FUTURE_EPOCH; + electraForkVersion = SpecBuilderUtil.PLACEHOLDER_FORK_VERSION; + } + + // Fill default zeros if fork is unsupported + if (electraForkEpoch.equals(FAR_FUTURE_EPOCH)) { + SpecBuilderUtil.fillMissingValuesWithZeros(this); + } + + validateConstants(); + } + + @Override + public Map getValidationMap() { + final Map constants = new HashMap<>(); + constants.put("capellaForkVersion", electraForkVersion); + constants.put("capellaForkEpoch", electraForkEpoch); + constants.put("maxStems", maxStems); + constants.put("maxCommitmentsPerStem", maxCommitmentsPerStem); + constants.put("verkleWidth", verkleWidth); + constants.put("ipaProofDepth", ipaProofDepth); + + return constants; + } + + @Override + public void addOverridableItemsToRawConfig(final BiConsumer rawConfig) { + rawConfig.accept("ELECTRA_FORK_EPOCH", electraForkEpoch); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/config/builder/SpecConfigBuilder.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/config/builder/SpecConfigBuilder.java index d89e0dfdd34..9a6c6b2c5ce 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/config/builder/SpecConfigBuilder.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/config/builder/SpecConfigBuilder.java @@ -134,6 +134,7 @@ public class SpecConfigBuilder { BuilderChain.create(new AltairBuilder()) .appendBuilder(new BellatrixBuilder()) .appendBuilder(new CapellaBuilder()) + .appendBuilder(new ElectraBuilder()) .appendBuilder(new DenebBuilder()); public SpecConfig build() { @@ -721,6 +722,11 @@ public SpecConfigBuilder capellaBuilder(final Consumer consumer) return this; } + public SpecConfigBuilder electraBuilder(final Consumer consumer) { + builderChain.withBuilder(ElectraBuilder.class, consumer); + return this; + } + public SpecConfigBuilder denebBuilder(final Consumer consumer) { builderChain.withBuilder(DenebBuilder.class, consumer); return this; diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/BeaconBlockBody.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/BeaconBlockBody.java index 45dcefbb69a..54d60cd6bb6 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/BeaconBlockBody.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/BeaconBlockBody.java @@ -28,9 +28,12 @@ import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.capella.BlindedBeaconBlockBodyCapella; import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.deneb.BeaconBlockBodyDeneb; import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.deneb.BlindedBeaconBlockBodyDeneb; +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.electra.BeaconBlockBodyElectra; +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.electra.BlindedBeaconBlockBodyElectra; import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayload; import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadHeader; import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadSummary; +import tech.pegasys.teku.spec.datastructures.execution.verkle.ExecutionWitness; import tech.pegasys.teku.spec.datastructures.operations.Attestation; import tech.pegasys.teku.spec.datastructures.operations.AttesterSlashing; import tech.pegasys.teku.spec.datastructures.operations.Deposit; @@ -85,6 +88,10 @@ default Optional> getOptionalBlobKzgCommitments() { return Optional.empty(); } + default Optional getOptionalExecutionWitness() { + return Optional.empty(); + } + default boolean isBlinded() { return false; } @@ -112,6 +119,14 @@ default Optional toBlindedVersionCapella() { return Optional.empty(); } + default Optional toVersionElectra() { + return Optional.empty(); + } + + default Optional toBlindedVersionElectra() { + return Optional.empty(); + } + default Optional toVersionDeneb() { return Optional.empty(); } diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/BeaconBlockBodySchema.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/BeaconBlockBodySchema.java index 1e392bcc2b9..8a4b71a7cfd 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/BeaconBlockBodySchema.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/BeaconBlockBodySchema.java @@ -24,6 +24,7 @@ import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.bellatrix.BeaconBlockBodySchemaBellatrix; import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.capella.BeaconBlockBodySchemaCapella; import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.deneb.BeaconBlockBodySchemaDeneb; +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.electra.BeaconBlockBodySchemaElectra; import tech.pegasys.teku.spec.datastructures.operations.Attestation; import tech.pegasys.teku.spec.datastructures.operations.AttesterSlashing; import tech.pegasys.teku.spec.datastructures.operations.Deposit; @@ -61,6 +62,10 @@ default Optional> toVersionCapella() { return Optional.empty(); } + default Optional> toVersionElectra() { + return Optional.empty(); + } + default Optional> toVersionDeneb() { return Optional.empty(); } diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/deneb/BeaconBlockBodyBuilderDeneb.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/deneb/BeaconBlockBodyBuilderDeneb.java index 82130d751c7..8a1cd4af540 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/deneb/BeaconBlockBodyBuilderDeneb.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/deneb/BeaconBlockBodyBuilderDeneb.java @@ -20,13 +20,13 @@ import tech.pegasys.teku.spec.datastructures.blocks.blockbody.BeaconBlockBody; import tech.pegasys.teku.spec.datastructures.blocks.blockbody.BeaconBlockBodyBuilder; import tech.pegasys.teku.spec.datastructures.blocks.blockbody.BeaconBlockBodySchema; -import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.capella.BeaconBlockBodyBuilderCapella; +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.electra.BeaconBlockBodyBuilderElectra; import tech.pegasys.teku.spec.datastructures.execution.versions.deneb.ExecutionPayloadDenebImpl; import tech.pegasys.teku.spec.datastructures.execution.versions.deneb.ExecutionPayloadHeaderDenebImpl; import tech.pegasys.teku.spec.datastructures.type.SszKZGCommitment; import tech.pegasys.teku.spec.datastructures.type.SszSignature; -public class BeaconBlockBodyBuilderDeneb extends BeaconBlockBodyBuilderCapella { +public class BeaconBlockBodyBuilderDeneb extends BeaconBlockBodyBuilderElectra { private SszList blobKzgCommitments; diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/deneb/BeaconBlockBodyDeneb.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/deneb/BeaconBlockBodyDeneb.java index 0536710cf48..8e8220867b4 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/deneb/BeaconBlockBodyDeneb.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/deneb/BeaconBlockBodyDeneb.java @@ -16,11 +16,11 @@ import java.util.Optional; import tech.pegasys.teku.infrastructure.ssz.SszList; import tech.pegasys.teku.spec.datastructures.blocks.blockbody.BeaconBlockBody; -import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.capella.BeaconBlockBodyCapella; +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.electra.BeaconBlockBodyElectra; import tech.pegasys.teku.spec.datastructures.execution.versions.deneb.ExecutionPayloadDeneb; import tech.pegasys.teku.spec.datastructures.type.SszKZGCommitment; -public interface BeaconBlockBodyDeneb extends BeaconBlockBodyCapella { +public interface BeaconBlockBodyDeneb extends BeaconBlockBodyElectra { static BeaconBlockBodyDeneb required(final BeaconBlockBody body) { return body.toVersionDeneb() .orElseThrow( diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/deneb/BeaconBlockBodySchemaDeneb.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/deneb/BeaconBlockBodySchemaDeneb.java index bbd1a4dbdd0..847827b6932 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/deneb/BeaconBlockBodySchemaDeneb.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/deneb/BeaconBlockBodySchemaDeneb.java @@ -18,11 +18,11 @@ import java.util.Optional; import tech.pegasys.teku.infrastructure.ssz.schema.SszListSchema; import tech.pegasys.teku.spec.datastructures.blocks.blockbody.BeaconBlockBodySchema; -import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.capella.BeaconBlockBodySchemaCapella; +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.electra.BeaconBlockBodySchemaElectra; import tech.pegasys.teku.spec.datastructures.type.SszKZGCommitment; public interface BeaconBlockBodySchemaDeneb - extends BeaconBlockBodySchemaCapella { + extends BeaconBlockBodySchemaElectra { static BeaconBlockBodySchemaDeneb required(final BeaconBlockBodySchema schema) { checkArgument( diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/deneb/BeaconBlockBodySchemaDenebImpl.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/deneb/BeaconBlockBodySchemaDenebImpl.java index d7d22576adf..6db02107615 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/deneb/BeaconBlockBodySchemaDenebImpl.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/deneb/BeaconBlockBodySchemaDenebImpl.java @@ -32,6 +32,7 @@ import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.altair.SyncAggregate; import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.altair.SyncAggregateSchema; import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadSchema; +import tech.pegasys.teku.spec.datastructures.execution.verkle.ExecutionWitnessSchema; import tech.pegasys.teku.spec.datastructures.execution.versions.deneb.ExecutionPayloadDenebImpl; import tech.pegasys.teku.spec.datastructures.execution.versions.deneb.ExecutionPayloadSchemaDeneb; import tech.pegasys.teku.spec.datastructures.operations.Attestation; @@ -99,6 +100,7 @@ public static BeaconBlockBodySchemaDenebImpl create( final AttesterSlashingSchema attesterSlashingSchema, final SignedBlsToExecutionChangeSchema blsToExecutionChangeSchema, final BlobKzgCommitmentsSchema blobKzgCommitmentsSchema, + final ExecutionWitnessSchema executionWitnessSchema, final String containerName) { return new BeaconBlockBodySchemaDenebImpl( containerName, @@ -126,7 +128,9 @@ public static BeaconBlockBodySchemaDenebImpl create( namedSchema( BlockBodyFields.SYNC_AGGREGATE, SyncAggregateSchema.create(specConfig.getSyncCommitteeSize())), - namedSchema(BlockBodyFields.EXECUTION_PAYLOAD, new ExecutionPayloadSchemaDeneb(specConfig)), + namedSchema( + BlockBodyFields.EXECUTION_PAYLOAD, + new ExecutionPayloadSchemaDeneb(specConfig, executionWitnessSchema)), namedSchema( BlockBodyFields.BLS_TO_EXECUTION_CHANGES, SszListSchema.create( diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/deneb/BlindedBeaconBlockBodyDeneb.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/deneb/BlindedBeaconBlockBodyDeneb.java index 57619d90072..553731f8a4e 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/deneb/BlindedBeaconBlockBodyDeneb.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/deneb/BlindedBeaconBlockBodyDeneb.java @@ -16,10 +16,10 @@ import java.util.Optional; import tech.pegasys.teku.infrastructure.ssz.SszList; import tech.pegasys.teku.spec.datastructures.blocks.blockbody.BeaconBlockBody; -import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.capella.BlindedBeaconBlockBodyCapella; +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.electra.BlindedBeaconBlockBodyElectra; import tech.pegasys.teku.spec.datastructures.type.SszKZGCommitment; -public interface BlindedBeaconBlockBodyDeneb extends BlindedBeaconBlockBodyCapella { +public interface BlindedBeaconBlockBodyDeneb extends BlindedBeaconBlockBodyElectra { static BlindedBeaconBlockBodyDeneb required(final BeaconBlockBody body) { return body.toBlindedVersionDeneb() .orElseThrow( diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/deneb/BlindedBeaconBlockBodySchemaDeneb.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/deneb/BlindedBeaconBlockBodySchemaDeneb.java index 00114141102..f0901f22d2d 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/deneb/BlindedBeaconBlockBodySchemaDeneb.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/deneb/BlindedBeaconBlockBodySchemaDeneb.java @@ -17,11 +17,11 @@ import tech.pegasys.teku.infrastructure.ssz.schema.SszListSchema; import tech.pegasys.teku.spec.datastructures.blocks.blockbody.BeaconBlockBodySchema; -import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.capella.BlindedBeaconBlockBodySchemaCapella; +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.electra.BlindedBeaconBlockBodySchemaElectra; import tech.pegasys.teku.spec.datastructures.type.SszKZGCommitment; public interface BlindedBeaconBlockBodySchemaDeneb - extends BlindedBeaconBlockBodySchemaCapella { + extends BlindedBeaconBlockBodySchemaElectra { static BlindedBeaconBlockBodySchemaDeneb required(final BeaconBlockBodySchema schema) { checkArgument( diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/deneb/BlindedBeaconBlockBodySchemaDenebImpl.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/deneb/BlindedBeaconBlockBodySchemaDenebImpl.java index 33a1ab1a759..6ede2d47f03 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/deneb/BlindedBeaconBlockBodySchemaDenebImpl.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/deneb/BlindedBeaconBlockBodySchemaDenebImpl.java @@ -31,6 +31,7 @@ import tech.pegasys.teku.spec.datastructures.blocks.blockbody.common.BlockBodyFields; import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.altair.SyncAggregate; import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.altair.SyncAggregateSchema; +import tech.pegasys.teku.spec.datastructures.execution.verkle.ExecutionWitnessSchema; import tech.pegasys.teku.spec.datastructures.execution.versions.deneb.ExecutionPayloadHeaderDenebImpl; import tech.pegasys.teku.spec.datastructures.execution.versions.deneb.ExecutionPayloadHeaderSchemaDeneb; import tech.pegasys.teku.spec.datastructures.operations.Attestation; @@ -98,6 +99,7 @@ public static BlindedBeaconBlockBodySchemaDenebImpl create( final AttesterSlashingSchema attesterSlashingSchema, final SignedBlsToExecutionChangeSchema signedBlsToExecutionChangeSchema, final BlobKzgCommitmentsSchema blobKzgCommitmentsSchema, + final ExecutionWitnessSchema executionWitnessSchema, final String containerName) { return new BlindedBeaconBlockBodySchemaDenebImpl( containerName, @@ -127,7 +129,7 @@ public static BlindedBeaconBlockBodySchemaDenebImpl create( SyncAggregateSchema.create(specConfig.getSyncCommitteeSize())), namedSchema( BlockBodyFields.EXECUTION_PAYLOAD_HEADER, - new ExecutionPayloadHeaderSchemaDeneb(specConfig)), + new ExecutionPayloadHeaderSchemaDeneb(specConfig, executionWitnessSchema)), namedSchema( BlockBodyFields.BLS_TO_EXECUTION_CHANGES, SszListSchema.create( diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/electra/BeaconBlockBodyBuilderElectra.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/electra/BeaconBlockBodyBuilderElectra.java new file mode 100644 index 00000000000..fae2476942b --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/electra/BeaconBlockBodyBuilderElectra.java @@ -0,0 +1,75 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.electra; + +import tech.pegasys.teku.infrastructure.ssz.primitive.SszBytes32; +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.BeaconBlockBody; +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.BeaconBlockBodySchema; +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.capella.BeaconBlockBodyBuilderCapella; +import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionPayloadElectraImpl; +import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionPayloadHeaderElectraImpl; +import tech.pegasys.teku.spec.datastructures.type.SszSignature; + +public class BeaconBlockBodyBuilderElectra extends BeaconBlockBodyBuilderCapella { + + public BeaconBlockBodyBuilderElectra( + final BeaconBlockBodySchema schema, + final BeaconBlockBodySchema blindedSchema) { + super(schema, blindedSchema); + } + + @Override + protected void validate() { + super.validate(); + } + + @Override + public BeaconBlockBody build() { + validate(); + if (isBlinded()) { + final BlindedBeaconBlockBodySchemaElectraImpl schema = + getAndValidateSchema(true, BlindedBeaconBlockBodySchemaElectraImpl.class); + return new BlindedBeaconBlockBodyElectraImpl( + schema, + new SszSignature(randaoReveal), + eth1Data, + SszBytes32.of(graffiti), + proposerSlashings, + attesterSlashings, + attestations, + deposits, + voluntaryExits, + syncAggregate, + (ExecutionPayloadHeaderElectraImpl) + executionPayloadHeader.toVersionElectra().orElseThrow(), + getBlsToExecutionChanges()); + } + + final BeaconBlockBodySchemaElectraImpl schema = + getAndValidateSchema(false, BeaconBlockBodySchemaElectraImpl.class); + return new BeaconBlockBodyElectraImpl( + schema, + new SszSignature(randaoReveal), + eth1Data, + SszBytes32.of(graffiti), + proposerSlashings, + attesterSlashings, + attestations, + deposits, + voluntaryExits, + syncAggregate, + (ExecutionPayloadElectraImpl) executionPayload.toVersionElectra().orElseThrow(), + getBlsToExecutionChanges()); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/electra/BeaconBlockBodyElectra.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/electra/BeaconBlockBodyElectra.java new file mode 100644 index 00000000000..33d857882ba --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/electra/BeaconBlockBodyElectra.java @@ -0,0 +1,46 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.electra; + +import java.util.Optional; +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.BeaconBlockBody; +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.capella.BeaconBlockBodyCapella; +import tech.pegasys.teku.spec.datastructures.execution.verkle.ExecutionWitness; +import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionPayloadElectra; + +public interface BeaconBlockBodyElectra extends BeaconBlockBodyCapella { + static BeaconBlockBodyElectra required(final BeaconBlockBody body) { + return body.toVersionElectra() + .orElseThrow( + () -> + new IllegalArgumentException( + "Expected electra block body but got " + body.getClass().getSimpleName())); + } + + @Override + BeaconBlockBodySchemaElectra getSchema(); + + @Override + ExecutionPayloadElectra getExecutionPayload(); + + @Override + default Optional getOptionalExecutionWitness() { + return Optional.of(getExecutionPayload().getExecutionWitness()); + } + + @Override + default Optional toVersionElectra() { + return Optional.of(this); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/electra/BeaconBlockBodyElectraImpl.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/electra/BeaconBlockBodyElectraImpl.java new file mode 100644 index 00000000000..e58170fa12a --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/electra/BeaconBlockBodyElectraImpl.java @@ -0,0 +1,155 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.electra; + +import org.apache.tuweni.bytes.Bytes32; +import tech.pegasys.teku.bls.BLSSignature; +import tech.pegasys.teku.infrastructure.ssz.SszList; +import tech.pegasys.teku.infrastructure.ssz.containers.Container11; +import tech.pegasys.teku.infrastructure.ssz.primitive.SszBytes32; +import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode; +import tech.pegasys.teku.spec.datastructures.blocks.Eth1Data; +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.altair.SyncAggregate; +import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionPayloadElectra; +import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionPayloadElectraImpl; +import tech.pegasys.teku.spec.datastructures.operations.Attestation; +import tech.pegasys.teku.spec.datastructures.operations.AttesterSlashing; +import tech.pegasys.teku.spec.datastructures.operations.Deposit; +import tech.pegasys.teku.spec.datastructures.operations.ProposerSlashing; +import tech.pegasys.teku.spec.datastructures.operations.SignedBlsToExecutionChange; +import tech.pegasys.teku.spec.datastructures.operations.SignedVoluntaryExit; +import tech.pegasys.teku.spec.datastructures.type.SszSignature; + +public class BeaconBlockBodyElectraImpl + extends Container11< + BeaconBlockBodyElectraImpl, + SszSignature, + Eth1Data, + SszBytes32, + SszList, + SszList, + SszList, + SszList, + SszList, + SyncAggregate, + ExecutionPayloadElectraImpl, + SszList> + implements BeaconBlockBodyElectra { + + BeaconBlockBodyElectraImpl( + BeaconBlockBodySchemaElectraImpl type, + SszSignature randaoReveal, + Eth1Data eth1Data, + SszBytes32 graffiti, + SszList proposerSlashings, + SszList attesterSlashings, + SszList attestations, + SszList deposits, + SszList voluntaryExits, + SyncAggregate syncAggregate, + ExecutionPayloadElectraImpl executionPayload, + SszList blsToExecutionChanges) { + super( + type, + randaoReveal, + eth1Data, + graffiti, + proposerSlashings, + attesterSlashings, + attestations, + deposits, + voluntaryExits, + syncAggregate, + executionPayload, + blsToExecutionChanges); + } + + BeaconBlockBodyElectraImpl(BeaconBlockBodySchemaElectraImpl type) { + super(type); + } + + BeaconBlockBodyElectraImpl(BeaconBlockBodySchemaElectraImpl type, TreeNode backingNode) { + super(type, backingNode); + } + + @Override + public BLSSignature getRandaoReveal() { + return getField0().getSignature(); + } + + @Override + public SszSignature getRandaoRevealSsz() { + return getField0(); + } + + @Override + public Eth1Data getEth1Data() { + return getField1(); + } + + @Override + public Bytes32 getGraffiti() { + return getField2().get(); + } + + @Override + public SszBytes32 getGraffitiSsz() { + return getField2(); + } + + @Override + public SszList getProposerSlashings() { + return getField3(); + } + + @Override + public SszList getAttesterSlashings() { + return getField4(); + } + + @Override + public SszList getAttestations() { + return getField5(); + } + + @Override + public SszList getDeposits() { + return getField6(); + } + + @Override + public SszList getVoluntaryExits() { + return getField7(); + } + + @Override + public SyncAggregate getSyncAggregate() { + return getField8(); + } + + @Override + public ExecutionPayloadElectra getExecutionPayload() { + return getField9(); + } + + @Override + public SszList getBlsToExecutionChanges() { + return getField10(); + } + + @Override + public BeaconBlockBodySchemaElectraImpl getSchema() { + return (BeaconBlockBodySchemaElectraImpl) super.getSchema(); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/electra/BeaconBlockBodySchemaElectra.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/electra/BeaconBlockBodySchemaElectra.java new file mode 100644 index 00000000000..a5b220ca26e --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/electra/BeaconBlockBodySchemaElectra.java @@ -0,0 +1,37 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.electra; + +import static com.google.common.base.Preconditions.checkArgument; + +import java.util.Optional; +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.BeaconBlockBodySchema; +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.capella.BeaconBlockBodySchemaCapella; + +public interface BeaconBlockBodySchemaElectra + extends BeaconBlockBodySchemaCapella { + + static BeaconBlockBodySchemaElectra required(final BeaconBlockBodySchema schema) { + checkArgument( + schema instanceof BeaconBlockBodySchemaElectra, + "Expected a BeaconBlockBodySchemaElectra but was %s", + schema.getClass()); + return (BeaconBlockBodySchemaElectra) schema; + } + + @Override + default Optional> toVersionElectra() { + return Optional.of(this); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/electra/BeaconBlockBodySchemaElectraImpl.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/electra/BeaconBlockBodySchemaElectraImpl.java new file mode 100644 index 00000000000..81e09dbcd4e --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/electra/BeaconBlockBodySchemaElectraImpl.java @@ -0,0 +1,203 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.electra; + +import it.unimi.dsi.fastutil.longs.LongList; +import java.util.function.Function; +import tech.pegasys.teku.infrastructure.async.SafeFuture; +import tech.pegasys.teku.infrastructure.ssz.SszList; +import tech.pegasys.teku.infrastructure.ssz.containers.ContainerSchema11; +import tech.pegasys.teku.infrastructure.ssz.primitive.SszBytes32; +import tech.pegasys.teku.infrastructure.ssz.schema.SszListSchema; +import tech.pegasys.teku.infrastructure.ssz.schema.SszPrimitiveSchemas; +import tech.pegasys.teku.infrastructure.ssz.tree.GIndexUtil; +import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode; +import tech.pegasys.teku.spec.config.SpecConfigElectra; +import tech.pegasys.teku.spec.datastructures.blocks.Eth1Data; +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.BeaconBlockBody; +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.BeaconBlockBodyBuilder; +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.common.BlockBodyFields; +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.altair.SyncAggregate; +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.altair.SyncAggregateSchema; +import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadSchema; +import tech.pegasys.teku.spec.datastructures.execution.verkle.ExecutionWitnessSchema; +import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionPayloadElectraImpl; +import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionPayloadSchemaElectra; +import tech.pegasys.teku.spec.datastructures.operations.Attestation; +import tech.pegasys.teku.spec.datastructures.operations.Attestation.AttestationSchema; +import tech.pegasys.teku.spec.datastructures.operations.AttesterSlashing; +import tech.pegasys.teku.spec.datastructures.operations.AttesterSlashing.AttesterSlashingSchema; +import tech.pegasys.teku.spec.datastructures.operations.Deposit; +import tech.pegasys.teku.spec.datastructures.operations.ProposerSlashing; +import tech.pegasys.teku.spec.datastructures.operations.SignedBlsToExecutionChange; +import tech.pegasys.teku.spec.datastructures.operations.SignedBlsToExecutionChangeSchema; +import tech.pegasys.teku.spec.datastructures.operations.SignedVoluntaryExit; +import tech.pegasys.teku.spec.datastructures.type.SszSignature; +import tech.pegasys.teku.spec.datastructures.type.SszSignatureSchema; + +public class BeaconBlockBodySchemaElectraImpl + extends ContainerSchema11< + BeaconBlockBodyElectraImpl, + SszSignature, + Eth1Data, + SszBytes32, + SszList, + SszList, + SszList, + SszList, + SszList, + SyncAggregate, + ExecutionPayloadElectraImpl, + SszList> + implements BeaconBlockBodySchemaElectra { + + protected BeaconBlockBodySchemaElectraImpl( + final String containerName, + final NamedSchema randaoRevealSchema, + final NamedSchema eth1DataSchema, + final NamedSchema graffitiSchema, + final NamedSchema> proposerSlashingsSchema, + final NamedSchema> attesterSlashingsSchema, + final NamedSchema> attestationsSchema, + final NamedSchema> depositsSchema, + final NamedSchema> voluntaryExitsSchema, + final NamedSchema syncAggregateSchema, + final NamedSchema executionPayloadSchema, + final NamedSchema> blsToExecutionChange) { + super( + containerName, + randaoRevealSchema, + eth1DataSchema, + graffitiSchema, + proposerSlashingsSchema, + attesterSlashingsSchema, + attestationsSchema, + depositsSchema, + voluntaryExitsSchema, + syncAggregateSchema, + executionPayloadSchema, + blsToExecutionChange); + } + + public static BeaconBlockBodySchemaElectraImpl create( + final SpecConfigElectra specConfig, + final AttesterSlashingSchema attesterSlashingSchema, + final SignedBlsToExecutionChangeSchema blsToExecutionChangeSchema, + final ExecutionWitnessSchema executionWitnessSchema, + final String containerName) { + return new BeaconBlockBodySchemaElectraImpl( + containerName, + namedSchema(BlockBodyFields.RANDAO_REVEAL, SszSignatureSchema.INSTANCE), + namedSchema(BlockBodyFields.ETH1_DATA, Eth1Data.SSZ_SCHEMA), + namedSchema(BlockBodyFields.GRAFFITI, SszPrimitiveSchemas.BYTES32_SCHEMA), + namedSchema( + BlockBodyFields.PROPOSER_SLASHINGS, + SszListSchema.create( + ProposerSlashing.SSZ_SCHEMA, specConfig.getMaxProposerSlashings())), + namedSchema( + BlockBodyFields.ATTESTER_SLASHINGS, + SszListSchema.create(attesterSlashingSchema, specConfig.getMaxAttesterSlashings())), + namedSchema( + BlockBodyFields.ATTESTATIONS, + SszListSchema.create( + new AttestationSchema(specConfig), specConfig.getMaxAttestations())), + namedSchema( + BlockBodyFields.DEPOSITS, + SszListSchema.create(Deposit.SSZ_SCHEMA, specConfig.getMaxDeposits())), + namedSchema( + BlockBodyFields.VOLUNTARY_EXITS, + SszListSchema.create( + SignedVoluntaryExit.SSZ_SCHEMA, specConfig.getMaxVoluntaryExits())), + namedSchema( + BlockBodyFields.SYNC_AGGREGATE, + SyncAggregateSchema.create(specConfig.getSyncCommitteeSize())), + namedSchema( + BlockBodyFields.EXECUTION_PAYLOAD, + new ExecutionPayloadSchemaElectra(specConfig, executionWitnessSchema)), + namedSchema( + BlockBodyFields.BLS_TO_EXECUTION_CHANGES, + SszListSchema.create( + blsToExecutionChangeSchema, specConfig.getMaxBlsToExecutionChanges()))); + } + + @Override + public SafeFuture createBlockBody( + final Function> bodyBuilder) { + final BeaconBlockBodyBuilderElectra builder = new BeaconBlockBodyBuilderElectra(this, null); + return bodyBuilder.apply(builder).thenApply(__ -> builder.build()); + } + + @Override + public BeaconBlockBody createEmpty() { + return new BeaconBlockBodyElectraImpl(this); + } + + @SuppressWarnings("unchecked") + @Override + public SszListSchema getProposerSlashingsSchema() { + return (SszListSchema) getFieldSchema3(); + } + + @SuppressWarnings("unchecked") + @Override + public SszListSchema getAttesterSlashingsSchema() { + return (SszListSchema) getFieldSchema4(); + } + + @SuppressWarnings("unchecked") + @Override + public SszListSchema getAttestationsSchema() { + return (SszListSchema) getFieldSchema5(); + } + + @SuppressWarnings("unchecked") + @Override + public SszListSchema getDepositsSchema() { + return (SszListSchema) getFieldSchema6(); + } + + @SuppressWarnings("unchecked") + @Override + public SszListSchema getVoluntaryExitsSchema() { + return (SszListSchema) getFieldSchema7(); + } + + @Override + public SyncAggregateSchema getSyncAggregateSchema() { + return (SyncAggregateSchema) getFieldSchema8(); + } + + @Override + public BeaconBlockBodyElectraImpl createFromBackingNode(TreeNode node) { + return new BeaconBlockBodyElectraImpl(this, node); + } + + @Override + public ExecutionPayloadSchema getExecutionPayloadSchema() { + return (ExecutionPayloadSchema) getFieldSchema9(); + } + + @SuppressWarnings("unchecked") + @Override + public SszListSchema getBlsToExecutionChangesSchema() { + return (SszListSchema) getFieldSchema10(); + } + + @Override + public LongList getBlindedNodeGeneralizedIndices() { + return GIndexUtil.gIdxComposeAll( + getChildGeneralizedIndex(getFieldIndex(BlockBodyFields.EXECUTION_PAYLOAD)), + getExecutionPayloadSchema().getBlindedNodeGeneralizedIndices()); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/electra/BlindedBeaconBlockBodyElectra.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/electra/BlindedBeaconBlockBodyElectra.java new file mode 100644 index 00000000000..c07701bacb5 --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/electra/BlindedBeaconBlockBodyElectra.java @@ -0,0 +1,37 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.electra; + +import java.util.Optional; +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.BeaconBlockBody; +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.capella.BlindedBeaconBlockBodyCapella; + +public interface BlindedBeaconBlockBodyElectra extends BlindedBeaconBlockBodyCapella { + static BlindedBeaconBlockBodyElectra required(final BeaconBlockBody body) { + return body.toBlindedVersionElectra() + .orElseThrow( + () -> + new IllegalArgumentException( + "Expected a electra blinded block body but got: " + + body.getClass().getSimpleName())); + } + + @Override + default Optional toBlindedVersionElectra() { + return Optional.of(this); + } + + @Override + BlindedBeaconBlockBodySchemaElectra getSchema(); +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/electra/BlindedBeaconBlockBodyElectraImpl.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/electra/BlindedBeaconBlockBodyElectraImpl.java new file mode 100644 index 00000000000..3cb61839623 --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/electra/BlindedBeaconBlockBodyElectraImpl.java @@ -0,0 +1,167 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.electra; + +import static com.google.common.base.Preconditions.checkArgument; + +import org.apache.tuweni.bytes.Bytes32; +import tech.pegasys.teku.bls.BLSSignature; +import tech.pegasys.teku.infrastructure.ssz.SszList; +import tech.pegasys.teku.infrastructure.ssz.containers.Container11; +import tech.pegasys.teku.infrastructure.ssz.primitive.SszBytes32; +import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode; +import tech.pegasys.teku.spec.datastructures.blocks.Eth1Data; +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.BeaconBlockBody; +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.altair.SyncAggregate; +import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadHeader; +import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionPayloadHeaderElectraImpl; +import tech.pegasys.teku.spec.datastructures.operations.Attestation; +import tech.pegasys.teku.spec.datastructures.operations.AttesterSlashing; +import tech.pegasys.teku.spec.datastructures.operations.Deposit; +import tech.pegasys.teku.spec.datastructures.operations.ProposerSlashing; +import tech.pegasys.teku.spec.datastructures.operations.SignedBlsToExecutionChange; +import tech.pegasys.teku.spec.datastructures.operations.SignedVoluntaryExit; +import tech.pegasys.teku.spec.datastructures.type.SszSignature; + +class BlindedBeaconBlockBodyElectraImpl + extends Container11< + BlindedBeaconBlockBodyElectraImpl, + SszSignature, + Eth1Data, + SszBytes32, + SszList, + SszList, + SszList, + SszList, + SszList, + SyncAggregate, + ExecutionPayloadHeaderElectraImpl, + SszList> + implements BlindedBeaconBlockBodyElectra { + + BlindedBeaconBlockBodyElectraImpl(BlindedBeaconBlockBodySchemaElectraImpl type) { + super(type); + } + + BlindedBeaconBlockBodyElectraImpl( + BlindedBeaconBlockBodySchemaElectraImpl type, TreeNode backingNode) { + super(type, backingNode); + } + + BlindedBeaconBlockBodyElectraImpl( + final BlindedBeaconBlockBodySchemaElectraImpl type, + final SszSignature randaoReveal, + final Eth1Data eth1Data, + final SszBytes32 graffiti, + final SszList proposerSlashings, + final SszList attesterSlashings, + final SszList attestations, + final SszList deposits, + final SszList voluntaryExits, + final SyncAggregate syncAggregate, + final ExecutionPayloadHeaderElectraImpl executionPayloadHeader, + final SszList blsToExecutionChanges) { + super( + type, + randaoReveal, + eth1Data, + graffiti, + proposerSlashings, + attesterSlashings, + attestations, + deposits, + voluntaryExits, + syncAggregate, + executionPayloadHeader, + blsToExecutionChanges); + } + + public static BlindedBeaconBlockBodyElectraImpl required(final BeaconBlockBody body) { + checkArgument( + body instanceof BlindedBeaconBlockBodyElectraImpl, + "Expected Electra blinded block body but got %s", + body.getClass()); + return (BlindedBeaconBlockBodyElectraImpl) body; + } + + @Override + public BLSSignature getRandaoReveal() { + return getField0().getSignature(); + } + + @Override + public SszSignature getRandaoRevealSsz() { + return getField0(); + } + + @Override + public Eth1Data getEth1Data() { + return getField1(); + } + + @Override + public Bytes32 getGraffiti() { + return getField2().get(); + } + + @Override + public SszBytes32 getGraffitiSsz() { + return getField2(); + } + + @Override + public SszList getProposerSlashings() { + return getField3(); + } + + @Override + public SszList getAttesterSlashings() { + return getField4(); + } + + @Override + public SszList getAttestations() { + return getField5(); + } + + @Override + public SszList getDeposits() { + return getField6(); + } + + @Override + public SszList getVoluntaryExits() { + return getField7(); + } + + @Override + public SyncAggregate getSyncAggregate() { + return getField8(); + } + + @Override + public ExecutionPayloadHeader getExecutionPayloadHeader() { + return getField9(); + } + + @Override + public SszList getBlsToExecutionChanges() { + return getField10(); + } + + @Override + public BlindedBeaconBlockBodySchemaElectraImpl getSchema() { + return (BlindedBeaconBlockBodySchemaElectraImpl) super.getSchema(); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/electra/BlindedBeaconBlockBodySchemaElectra.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/electra/BlindedBeaconBlockBodySchemaElectra.java new file mode 100644 index 00000000000..d4153786d33 --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/electra/BlindedBeaconBlockBodySchemaElectra.java @@ -0,0 +1,19 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.electra; + +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.capella.BlindedBeaconBlockBodySchemaCapella; + +public interface BlindedBeaconBlockBodySchemaElectra + extends BlindedBeaconBlockBodySchemaCapella {} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/electra/BlindedBeaconBlockBodySchemaElectraImpl.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/electra/BlindedBeaconBlockBodySchemaElectraImpl.java new file mode 100644 index 00000000000..9acf938e357 --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/electra/BlindedBeaconBlockBodySchemaElectraImpl.java @@ -0,0 +1,202 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.electra; + +import it.unimi.dsi.fastutil.longs.LongList; +import java.util.function.Function; +import tech.pegasys.teku.infrastructure.async.SafeFuture; +import tech.pegasys.teku.infrastructure.ssz.SszList; +import tech.pegasys.teku.infrastructure.ssz.containers.ContainerSchema11; +import tech.pegasys.teku.infrastructure.ssz.primitive.SszBytes32; +import tech.pegasys.teku.infrastructure.ssz.schema.SszListSchema; +import tech.pegasys.teku.infrastructure.ssz.schema.SszPrimitiveSchemas; +import tech.pegasys.teku.infrastructure.ssz.tree.GIndexUtil; +import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode; +import tech.pegasys.teku.spec.config.SpecConfigElectra; +import tech.pegasys.teku.spec.datastructures.blocks.Eth1Data; +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.BeaconBlockBody; +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.BeaconBlockBodyBuilder; +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.common.BlockBodyFields; +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.altair.SyncAggregate; +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.altair.SyncAggregateSchema; +import tech.pegasys.teku.spec.datastructures.execution.verkle.ExecutionWitnessSchema; +import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionPayloadHeaderElectraImpl; +import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionPayloadHeaderSchemaElectra; +import tech.pegasys.teku.spec.datastructures.operations.Attestation; +import tech.pegasys.teku.spec.datastructures.operations.Attestation.AttestationSchema; +import tech.pegasys.teku.spec.datastructures.operations.AttesterSlashing; +import tech.pegasys.teku.spec.datastructures.operations.AttesterSlashing.AttesterSlashingSchema; +import tech.pegasys.teku.spec.datastructures.operations.Deposit; +import tech.pegasys.teku.spec.datastructures.operations.ProposerSlashing; +import tech.pegasys.teku.spec.datastructures.operations.SignedBlsToExecutionChange; +import tech.pegasys.teku.spec.datastructures.operations.SignedBlsToExecutionChangeSchema; +import tech.pegasys.teku.spec.datastructures.operations.SignedVoluntaryExit; +import tech.pegasys.teku.spec.datastructures.type.SszSignature; +import tech.pegasys.teku.spec.datastructures.type.SszSignatureSchema; + +public class BlindedBeaconBlockBodySchemaElectraImpl + extends ContainerSchema11< + BlindedBeaconBlockBodyElectraImpl, + SszSignature, + Eth1Data, + SszBytes32, + SszList, + SszList, + SszList, + SszList, + SszList, + SyncAggregate, + ExecutionPayloadHeaderElectraImpl, + SszList> + implements BlindedBeaconBlockBodySchemaElectra { + + private BlindedBeaconBlockBodySchemaElectraImpl( + final String containerName, + NamedSchema randaoReveal, + NamedSchema eth1Data, + NamedSchema graffiti, + NamedSchema> proposerSlashings, + NamedSchema> attesterSlashings, + NamedSchema> attestations, + NamedSchema> deposits, + NamedSchema> voluntaryExits, + NamedSchema syncAggregate, + NamedSchema executionPayloadHeader, + NamedSchema> blsToExecutionChanges) { + super( + containerName, + randaoReveal, + eth1Data, + graffiti, + proposerSlashings, + attesterSlashings, + attestations, + deposits, + voluntaryExits, + syncAggregate, + executionPayloadHeader, + blsToExecutionChanges); + } + + public static BlindedBeaconBlockBodySchemaElectraImpl create( + final SpecConfigElectra specConfig, + final AttesterSlashingSchema attesterSlashingSchema, + final SignedBlsToExecutionChangeSchema signedBlsToExecutionChangeSchema, + final ExecutionWitnessSchema executionWitnessSchema, + final String containerName) { + return new BlindedBeaconBlockBodySchemaElectraImpl( + containerName, + namedSchema(BlockBodyFields.RANDAO_REVEAL, SszSignatureSchema.INSTANCE), + namedSchema(BlockBodyFields.ETH1_DATA, Eth1Data.SSZ_SCHEMA), + namedSchema(BlockBodyFields.GRAFFITI, SszPrimitiveSchemas.BYTES32_SCHEMA), + namedSchema( + BlockBodyFields.PROPOSER_SLASHINGS, + SszListSchema.create( + ProposerSlashing.SSZ_SCHEMA, specConfig.getMaxProposerSlashings())), + namedSchema( + BlockBodyFields.ATTESTER_SLASHINGS, + SszListSchema.create(attesterSlashingSchema, specConfig.getMaxAttesterSlashings())), + namedSchema( + BlockBodyFields.ATTESTATIONS, + SszListSchema.create( + new AttestationSchema(specConfig), specConfig.getMaxAttestations())), + namedSchema( + BlockBodyFields.DEPOSITS, + SszListSchema.create(Deposit.SSZ_SCHEMA, specConfig.getMaxDeposits())), + namedSchema( + BlockBodyFields.VOLUNTARY_EXITS, + SszListSchema.create( + SignedVoluntaryExit.SSZ_SCHEMA, specConfig.getMaxVoluntaryExits())), + namedSchema( + BlockBodyFields.SYNC_AGGREGATE, + SyncAggregateSchema.create(specConfig.getSyncCommitteeSize())), + namedSchema( + BlockBodyFields.EXECUTION_PAYLOAD_HEADER, + new ExecutionPayloadHeaderSchemaElectra(specConfig, executionWitnessSchema)), + namedSchema( + BlockBodyFields.BLS_TO_EXECUTION_CHANGES, + SszListSchema.create( + signedBlsToExecutionChangeSchema, specConfig.getMaxBlsToExecutionChanges()))); + } + + @Override + public SafeFuture createBlockBody( + final Function> bodyBuilder) { + final BeaconBlockBodyBuilderElectra builder = new BeaconBlockBodyBuilderElectra(null, this); + return bodyBuilder.apply(builder).thenApply(__ -> builder.build()); + } + + @Override + public BlindedBeaconBlockBodyElectraImpl createEmpty() { + return new BlindedBeaconBlockBodyElectraImpl(this); + } + + @SuppressWarnings("unchecked") + @Override + public SszListSchema getProposerSlashingsSchema() { + return (SszListSchema) getFieldSchema3(); + } + + @SuppressWarnings("unchecked") + @Override + public SszListSchema getAttesterSlashingsSchema() { + return (SszListSchema) getFieldSchema4(); + } + + @SuppressWarnings("unchecked") + @Override + public SszListSchema getAttestationsSchema() { + return (SszListSchema) getFieldSchema5(); + } + + @SuppressWarnings("unchecked") + @Override + public SszListSchema getDepositsSchema() { + return (SszListSchema) getFieldSchema6(); + } + + @SuppressWarnings("unchecked") + @Override + public SszListSchema getVoluntaryExitsSchema() { + return (SszListSchema) getFieldSchema7(); + } + + @Override + public SyncAggregateSchema getSyncAggregateSchema() { + return (SyncAggregateSchema) getFieldSchema8(); + } + + @Override + public BlindedBeaconBlockBodyElectraImpl createFromBackingNode(TreeNode node) { + return new BlindedBeaconBlockBodyElectraImpl(this, node); + } + + @Override + public ExecutionPayloadHeaderSchemaElectra getExecutionPayloadHeaderSchema() { + return (ExecutionPayloadHeaderSchemaElectra) getFieldSchema9(); + } + + @SuppressWarnings("unchecked") + @Override + public SszListSchema getBlsToExecutionChanges() { + return (SszListSchema) getFieldSchema10(); + } + + @Override + public LongList getBlindedNodeGeneralizedIndices() { + return GIndexUtil.gIdxComposeAll( + getChildGeneralizedIndex(getFieldIndex(BlockBodyFields.EXECUTION_PAYLOAD_HEADER)), + getExecutionPayloadHeaderSchema().getBlindedNodeGeneralizedIndices()); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/ExecutionPayload.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/ExecutionPayload.java index ff34555f82b..bb346ba9a85 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/ExecutionPayload.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/ExecutionPayload.java @@ -25,6 +25,7 @@ import tech.pegasys.teku.spec.datastructures.execution.versions.capella.ExecutionPayloadCapella; import tech.pegasys.teku.spec.datastructures.execution.versions.capella.Withdrawal; import tech.pegasys.teku.spec.datastructures.execution.versions.deneb.ExecutionPayloadDeneb; +import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionPayloadElectra; public interface ExecutionPayload extends ExecutionPayloadSummary, SszContainer, BuilderPayload { @@ -52,6 +53,10 @@ default Optional toVersionCapella() { return Optional.empty(); } + default Optional toVersionElectra() { + return Optional.empty(); + } + default Optional toVersionDeneb() { return Optional.empty(); } diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/ExecutionPayloadBuilder.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/ExecutionPayloadBuilder.java index 056e3f8052a..acd52f239f1 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/ExecutionPayloadBuilder.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/ExecutionPayloadBuilder.java @@ -20,6 +20,7 @@ import org.apache.tuweni.units.bigints.UInt256; import tech.pegasys.teku.infrastructure.bytes.Bytes20; import tech.pegasys.teku.infrastructure.unsigned.UInt64; +import tech.pegasys.teku.spec.datastructures.execution.verkle.ExecutionWitness; import tech.pegasys.teku.spec.datastructures.execution.versions.capella.Withdrawal; public interface ExecutionPayloadBuilder { @@ -53,6 +54,8 @@ public interface ExecutionPayloadBuilder { ExecutionPayloadBuilder withdrawals(Supplier> withdrawalsSupplier); + ExecutionPayloadBuilder executionWitness(Supplier executionWitnessSupplier); + ExecutionPayloadBuilder blobGasUsed(Supplier blobGasUsedSupplier); ExecutionPayloadBuilder excessBlobGas(Supplier excessBlobGasSupplier); diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/ExecutionPayloadFields.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/ExecutionPayloadFields.java index ae2d7803630..c6159a3d904 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/ExecutionPayloadFields.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/ExecutionPayloadFields.java @@ -35,7 +35,9 @@ public enum ExecutionPayloadFields implements SszFieldName { TRANSACTIONS_ROOT, WITHDRAWALS_ROOT, BLOB_GAS_USED, - EXCESS_BLOB_GAS; + EXCESS_BLOB_GAS, + EXECUTION_WITNESS, + EXECUTION_WITNESS_ROOT; private final String sszFieldName; diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/ExecutionPayloadHeader.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/ExecutionPayloadHeader.java index 6a0a11829bd..10e4a26ed80 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/ExecutionPayloadHeader.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/ExecutionPayloadHeader.java @@ -19,6 +19,7 @@ import tech.pegasys.teku.spec.datastructures.execution.versions.bellatrix.ExecutionPayloadHeaderBellatrix; import tech.pegasys.teku.spec.datastructures.execution.versions.capella.ExecutionPayloadHeaderCapella; import tech.pegasys.teku.spec.datastructures.execution.versions.deneb.ExecutionPayloadHeaderDeneb; +import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionPayloadHeaderElectra; public interface ExecutionPayloadHeader extends ExecutionPayloadSummary, SszContainer { @@ -34,6 +35,10 @@ default Optional toVersionCapella() { return Optional.empty(); } + default Optional toVersionElectra() { + return Optional.empty(); + } + default Optional toVersionDeneb() { return Optional.empty(); } diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/ExecutionPayloadHeaderBuilder.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/ExecutionPayloadHeaderBuilder.java index ead0c8f0bd4..547418a1cd4 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/ExecutionPayloadHeaderBuilder.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/ExecutionPayloadHeaderBuilder.java @@ -55,5 +55,8 @@ public interface ExecutionPayloadHeaderBuilder { ExecutionPayloadHeaderBuilder excessBlobGas(Supplier excessBlobGasSupplier); + ExecutionPayloadHeaderBuilder executionWitnessRoot( + Supplier executionWitnessRootSupplier); + ExecutionPayloadHeader build(); } diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/ExecutionPayloadSchema.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/ExecutionPayloadSchema.java index a7fb9238aa5..161b59e7e85 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/ExecutionPayloadSchema.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/ExecutionPayloadSchema.java @@ -20,6 +20,7 @@ import tech.pegasys.teku.infrastructure.ssz.schema.SszListSchema; import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode; import tech.pegasys.teku.spec.datastructures.builder.BuilderPayloadSchema; +import tech.pegasys.teku.spec.datastructures.execution.verkle.ExecutionWitnessSchema; import tech.pegasys.teku.spec.datastructures.execution.versions.capella.Withdrawal; import tech.pegasys.teku.spec.datastructures.execution.versions.capella.WithdrawalSchema; @@ -35,6 +36,8 @@ public interface ExecutionPayloadSchema WithdrawalSchema getWithdrawalSchemaRequired(); + ExecutionWitnessSchema getExecutionWitnessSchemaRequired(); + LongList getBlindedNodeGeneralizedIndices(); ExecutionPayload createExecutionPayload(Consumer builderConsumer); diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/verkle/ExecutionWitness.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/verkle/ExecutionWitness.java new file mode 100644 index 00000000000..874e91f9386 --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/verkle/ExecutionWitness.java @@ -0,0 +1,54 @@ +/* + * Copyright Consensys Software Inc., 2023 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.datastructures.execution.verkle; + +import java.util.List; +import org.apache.tuweni.bytes.Bytes32; +import tech.pegasys.teku.infrastructure.ssz.SszList; +import tech.pegasys.teku.infrastructure.ssz.containers.Container3; +import tech.pegasys.teku.infrastructure.ssz.primitive.SszBytes32; +import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode; + +public class ExecutionWitness + extends Container3, VerkleProof, SszBytes32> { + + ExecutionWitness( + final ExecutionWitnessSchema executionWitnessSchema, final TreeNode backingTreeNode) { + super(executionWitnessSchema, backingTreeNode); + } + + public ExecutionWitness( + final ExecutionWitnessSchema schema, + final List stateDiffList, + final VerkleProof verkleProof, + final Bytes32 parentStateRoot) { + super( + schema, + schema.getStateDiffSchema().createFromElements(stateDiffList), + verkleProof, + SszBytes32.of(parentStateRoot)); + } + + public List getStateDiffs() { + return getField0().asList(); + } + + public VerkleProof getVerkleProof() { + return getField1(); + } + + public Bytes32 getParentStateRoot() { + return getField2().get(); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/verkle/ExecutionWitnessSchema.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/verkle/ExecutionWitnessSchema.java new file mode 100644 index 00000000000..5a8e7bcc882 --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/verkle/ExecutionWitnessSchema.java @@ -0,0 +1,65 @@ +/* + * Copyright Consensys Software Inc., 2023 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.datastructures.execution.verkle; + +import java.util.List; +import org.apache.tuweni.bytes.Bytes32; +import tech.pegasys.teku.infrastructure.ssz.SszList; +import tech.pegasys.teku.infrastructure.ssz.containers.ContainerSchema3; +import tech.pegasys.teku.infrastructure.ssz.primitive.SszBytes32; +import tech.pegasys.teku.infrastructure.ssz.schema.SszFieldName; +import tech.pegasys.teku.infrastructure.ssz.schema.SszListSchema; +import tech.pegasys.teku.infrastructure.ssz.schema.SszPrimitiveSchemas; +import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode; + +public class ExecutionWitnessSchema + extends ContainerSchema3, VerkleProof, SszBytes32> { + + static final SszFieldName FIELD_STATE_DIFF = () -> "state_diff"; + static final SszFieldName FIELD_VERKLE_PROOF = () -> "verkle_proof"; + static final SszFieldName FIELD_PARENT_STATE_ROOT = () -> "parent_state_root"; + + public ExecutionWitnessSchema( + final int maxStems, + final StemStateDiffSchema stemStateDiffSchema, + final VerkleProofSchema verkleProofSchema) { + super( + "ExecutionWitness", + namedSchema(FIELD_STATE_DIFF, SszListSchema.create(stemStateDiffSchema, maxStems)), + namedSchema(FIELD_VERKLE_PROOF, verkleProofSchema), + namedSchema(FIELD_PARENT_STATE_ROOT, SszPrimitiveSchemas.BYTES32_SCHEMA)); + } + + @SuppressWarnings("unchecked") + public SszListSchema> getStateDiffSchema() { + return (SszListSchema>) + getChildSchema(getFieldIndex(FIELD_STATE_DIFF)); + } + + public VerkleProofSchema getVerkleProofSchema() { + return (VerkleProofSchema) getChildSchema(getFieldIndex(FIELD_VERKLE_PROOF)); + } + + public ExecutionWitness create( + final List stateDiffList, + final VerkleProof verkleProof, + final Bytes32 parentStateRoot) { + return new ExecutionWitness(this, stateDiffList, verkleProof, parentStateRoot); + } + + @Override + public ExecutionWitness createFromBackingNode(TreeNode node) { + return new ExecutionWitness(this, node); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/verkle/IpaProof.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/verkle/IpaProof.java new file mode 100644 index 00000000000..ae19fcad61f --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/verkle/IpaProof.java @@ -0,0 +1,65 @@ +/* + * Copyright Consensys Software Inc., 2023 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.datastructures.execution.verkle; + +import java.util.List; +import org.apache.tuweni.bytes.Bytes32; +import tech.pegasys.teku.infrastructure.ssz.SszVector; +import tech.pegasys.teku.infrastructure.ssz.containers.Container3; +import tech.pegasys.teku.infrastructure.ssz.primitive.SszBytes32; +import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode; + +public class IpaProof + extends Container3, SszVector, SszBytes32> { + + IpaProof(final IpaProofSchema ipaProofSchema, final TreeNode backingTreeNode) { + super(ipaProofSchema, backingTreeNode); + } + + public IpaProof( + final IpaProofSchema schema, + final List cl, + final List cr, + final SszBytes32 finalEvaluation) { + super( + schema, + schema.getClSchema().createFromElements(cl), + schema.getClSchema().createFromElements(cr), + finalEvaluation); + } + + public IpaProof( + final IpaProofSchema schema, + final List cl, + final List cr, + final Bytes32 finalEvaluation) { + this( + schema, + cl.stream().map(SszBytes32::of).toList(), + cr.stream().map(SszBytes32::of).toList(), + SszBytes32.of(finalEvaluation)); + } + + public List getCl() { + return getField0().stream().map(SszBytes32::get).toList(); + } + + public List getCr() { + return getField1().stream().map(SszBytes32::get).toList(); + } + + public Bytes32 getFinalEvaluation() { + return getField2().get(); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/verkle/IpaProofSchema.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/verkle/IpaProofSchema.java new file mode 100644 index 00000000000..4312fdcee3c --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/verkle/IpaProofSchema.java @@ -0,0 +1,56 @@ +/* + * Copyright Consensys Software Inc., 2023 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.datastructures.execution.verkle; + +import java.util.List; +import org.apache.tuweni.bytes.Bytes32; +import tech.pegasys.teku.infrastructure.ssz.SszVector; +import tech.pegasys.teku.infrastructure.ssz.containers.ContainerSchema3; +import tech.pegasys.teku.infrastructure.ssz.primitive.SszBytes32; +import tech.pegasys.teku.infrastructure.ssz.schema.SszFieldName; +import tech.pegasys.teku.infrastructure.ssz.schema.SszPrimitiveSchemas; +import tech.pegasys.teku.infrastructure.ssz.schema.SszVectorSchema; +import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode; + +public class IpaProofSchema + extends ContainerSchema3, SszVector, SszBytes32> { + + static final SszFieldName FIELD_CL = () -> "cl"; + + public IpaProofSchema(final int ipaProofDepth) { + super( + "IpaProof", + namedSchema( + FIELD_CL, SszVectorSchema.create(SszPrimitiveSchemas.BYTES32_SCHEMA, ipaProofDepth)), + namedSchema( + "cr", SszVectorSchema.create(SszPrimitiveSchemas.BYTES32_SCHEMA, ipaProofDepth)), + namedSchema("final_evaluation", SszPrimitiveSchemas.BYTES32_SCHEMA)); + } + + @SuppressWarnings("unchecked") + public SszVectorSchema> getClSchema() { + return (SszVectorSchema>) + getChildSchema(getFieldIndex(FIELD_CL)); + } + + public IpaProof create( + final List cl, final List cr, final Bytes32 finalEvaluation) { + return new IpaProof(this, cl, cr, finalEvaluation); + } + + @Override + public IpaProof createFromBackingNode(TreeNode node) { + return new IpaProof(this, node); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/verkle/StemStateDiff.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/verkle/StemStateDiff.java new file mode 100644 index 00000000000..6eddd2f34ba --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/verkle/StemStateDiff.java @@ -0,0 +1,51 @@ +/* + * Copyright Consensys Software Inc., 2023 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.datastructures.execution.verkle; + +import java.util.List; +import tech.pegasys.teku.infrastructure.bytes.Bytes31; +import tech.pegasys.teku.infrastructure.ssz.SszList; +import tech.pegasys.teku.infrastructure.ssz.collections.SszByteVector; +import tech.pegasys.teku.infrastructure.ssz.containers.Container2; +import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode; + +public class StemStateDiff + extends Container2> { + + StemStateDiff(final StemStateDiffSchema stemStateDiffSchema, final TreeNode backingTreeNode) { + super(stemStateDiffSchema, backingTreeNode); + } + + public StemStateDiff( + final StemStateDiffSchema schema, + final SszByteVector stem, + final List stateDiffs) { + super(schema, stem, schema.getSuffixDiffsSchema().createFromElements(stateDiffs)); + } + + public StemStateDiff( + final StemStateDiffSchema schema, + final Bytes31 stem, + final List stateDiffs) { + this(schema, SszByteVector.fromBytes(stem.getWrappedBytes()), stateDiffs); + } + + public Bytes31 getStem() { + return new Bytes31(getField0().getBytes()); + } + + public List getStateDiffs() { + return getField1().asList(); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/verkle/StemStateDiffSchema.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/verkle/StemStateDiffSchema.java new file mode 100644 index 00000000000..19af1d29f61 --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/verkle/StemStateDiffSchema.java @@ -0,0 +1,53 @@ +/* + * Copyright Consensys Software Inc., 2023 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.datastructures.execution.verkle; + +import java.util.List; +import tech.pegasys.teku.infrastructure.bytes.Bytes31; +import tech.pegasys.teku.infrastructure.ssz.SszList; +import tech.pegasys.teku.infrastructure.ssz.collections.SszByteVector; +import tech.pegasys.teku.infrastructure.ssz.containers.ContainerSchema2; +import tech.pegasys.teku.infrastructure.ssz.schema.SszFieldName; +import tech.pegasys.teku.infrastructure.ssz.schema.SszListSchema; +import tech.pegasys.teku.infrastructure.ssz.schema.collections.SszByteVectorSchema; +import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode; + +public class StemStateDiffSchema + extends ContainerSchema2> { + + static final SszFieldName FIELD_SUFFIX_DIFFS = () -> "suffix_diffs"; + + public StemStateDiffSchema(final int verkleWidth) { + super( + "StemStateDiff", + namedSchema("stem", SszByteVectorSchema.create(Bytes31.SIZE)), + namedSchema( + FIELD_SUFFIX_DIFFS, SszListSchema.create(SuffixStateDiffSchema.INSTANCE, verkleWidth))); + } + + @SuppressWarnings("unchecked") + public SszListSchema> getSuffixDiffsSchema() { + return (SszListSchema>) + getChildSchema(getFieldIndex(FIELD_SUFFIX_DIFFS)); + } + + public StemStateDiff create(final Bytes31 stem, final List stateDiffs) { + return new StemStateDiff(this, stem, stateDiffs); + } + + @Override + public StemStateDiff createFromBackingNode(TreeNode node) { + return new StemStateDiff(this, node); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/verkle/SuffixStateDiff.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/verkle/SuffixStateDiff.java new file mode 100644 index 00000000000..fc0ee7679f1 --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/verkle/SuffixStateDiff.java @@ -0,0 +1,65 @@ +/* + * Copyright Consensys Software Inc., 2023 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.datastructures.execution.verkle; + +import java.util.Optional; +import org.apache.tuweni.bytes.Bytes32; +import tech.pegasys.teku.infrastructure.ssz.SszOptional; +import tech.pegasys.teku.infrastructure.ssz.containers.Container3; +import tech.pegasys.teku.infrastructure.ssz.impl.AbstractSszPrimitive; +import tech.pegasys.teku.infrastructure.ssz.primitive.SszByte; +import tech.pegasys.teku.infrastructure.ssz.primitive.SszBytes32; +import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode; + +public class SuffixStateDiff + extends Container3, SszOptional> { + + SuffixStateDiff( + final SuffixStateDiffSchema suffixStateDiffSchema, final TreeNode backingTreeNode) { + super(suffixStateDiffSchema, backingTreeNode); + } + + public SuffixStateDiff( + final SuffixStateDiffSchema schema, + final SszByte suffix, + final Optional currentValue, + final Optional newValue) { + super( + schema, + suffix, + schema.getCurrentValueSchema().createFromValue(currentValue), + schema.getCurrentValueSchema().createFromValue(newValue)); + } + + public SuffixStateDiff( + final SuffixStateDiffSchema schema, + final Byte suffix, + final Optional currentValue, + final Optional newValue) { + this( + schema, SszByte.of(suffix), currentValue.map(SszBytes32::of), newValue.map(SszBytes32::of)); + } + + public Byte getSuffix() { + return getField0().get(); + } + + public Optional getCurrentValue() { + return getField1().getValue().map(AbstractSszPrimitive::get); + } + + public Optional getNewValue() { + return getField2().getValue().map(AbstractSszPrimitive::get); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/verkle/SuffixStateDiffSchema.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/verkle/SuffixStateDiffSchema.java new file mode 100644 index 00000000000..199d0a7c115 --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/verkle/SuffixStateDiffSchema.java @@ -0,0 +1,59 @@ +/* + * Copyright Consensys Software Inc., 2023 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.datastructures.execution.verkle; + +import java.util.Optional; +import org.apache.tuweni.bytes.Bytes32; +import tech.pegasys.teku.infrastructure.ssz.SszOptional; +import tech.pegasys.teku.infrastructure.ssz.containers.ContainerSchema3; +import tech.pegasys.teku.infrastructure.ssz.primitive.SszByte; +import tech.pegasys.teku.infrastructure.ssz.primitive.SszBytes32; +import tech.pegasys.teku.infrastructure.ssz.schema.SszFieldName; +import tech.pegasys.teku.infrastructure.ssz.schema.SszOptionalSchema; +import tech.pegasys.teku.infrastructure.ssz.schema.SszPrimitiveSchemas; +import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode; + +public class SuffixStateDiffSchema + extends ContainerSchema3< + SuffixStateDiff, SszByte, SszOptional, SszOptional> { + + static final SszFieldName FIELD_CURRENT_VALUE = () -> "current_value"; + + SuffixStateDiffSchema() { + super( + "SuffixStateDiff", + namedSchema("suffix", SszPrimitiveSchemas.BYTE_SCHEMA), + namedSchema( + FIELD_CURRENT_VALUE, SszOptionalSchema.create(SszPrimitiveSchemas.BYTES32_SCHEMA)), + namedSchema("new_value", SszOptionalSchema.create(SszPrimitiveSchemas.BYTES32_SCHEMA))); + } + + public static final SuffixStateDiffSchema INSTANCE = new SuffixStateDiffSchema(); + + @SuppressWarnings("unchecked") + public SszOptionalSchema> getCurrentValueSchema() { + return (SszOptionalSchema>) + getChildSchema(getFieldIndex(FIELD_CURRENT_VALUE)); + } + + public SuffixStateDiff create( + final Byte suffix, final Optional currentValue, final Optional newValue) { + return new SuffixStateDiff(this, suffix, currentValue, newValue); + } + + @Override + public SuffixStateDiff createFromBackingNode(TreeNode node) { + return new SuffixStateDiff(this, node); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/verkle/VerkleProof.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/verkle/VerkleProof.java new file mode 100644 index 00000000000..561485dd42f --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/verkle/VerkleProof.java @@ -0,0 +1,93 @@ +/* + * Copyright Consensys Software Inc., 2023 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.datastructures.execution.verkle; + +import java.util.List; +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; +import tech.pegasys.teku.infrastructure.bytes.Bytes31; +import tech.pegasys.teku.infrastructure.ssz.SszList; +import tech.pegasys.teku.infrastructure.ssz.collections.SszByteList; +import tech.pegasys.teku.infrastructure.ssz.collections.SszByteVector; +import tech.pegasys.teku.infrastructure.ssz.containers.Container5; +import tech.pegasys.teku.infrastructure.ssz.primitive.SszBytes32; +import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode; + +public class VerkleProof + extends Container5< + VerkleProof, + SszList, + SszByteList, + SszList, + SszBytes32, + IpaProof> { + + VerkleProof(final VerkleProofSchema verkleProofSchema, final TreeNode backingTreeNode) { + super(verkleProofSchema, backingTreeNode); + } + + public VerkleProof( + final VerkleProofSchema schema, + final List otherStems, + final SszByteList depthExtensionPresent, + final List commitmentsByPath, + final SszBytes32 d, + final IpaProof ipaProof) { + super( + schema, + schema.getOtherStemsSchema().createFromElements(otherStems), + depthExtensionPresent, + schema.getCommitmentsByPathSchema().createFromElements(commitmentsByPath), + d, + ipaProof); + } + + public VerkleProof( + final VerkleProofSchema schema, + final List otherStems, + final Bytes depthExtensionPresent, + final List commitmentsByPath, + final Bytes32 d, + final IpaProof ipaProof) { + this( + schema, + otherStems.stream() + .map(bytes31 -> SszByteVector.fromBytes(bytes31.getWrappedBytes())) + .toList(), + schema.getDepthExtensionPresentSchema().fromBytes(depthExtensionPresent), + commitmentsByPath.stream().map(SszBytes32::of).toList(), + SszBytes32.of(d), + ipaProof); + } + + public List getOtherStems() { + return getField0().stream().map(sszBytes -> new Bytes31(sszBytes.getBytes())).toList(); + } + + public Bytes getDepthExtensionPresent() { + return getField1().getBytes(); + } + + public List getCommitmentsByPath() { + return getField2().stream().map(SszBytes32::get).toList(); + } + + public Bytes32 getD() { + return getField3().get(); + } + + public IpaProof getIpaProof() { + return getField4(); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/verkle/VerkleProofSchema.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/verkle/VerkleProofSchema.java new file mode 100644 index 00000000000..3ea79f36a24 --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/verkle/VerkleProofSchema.java @@ -0,0 +1,95 @@ +/* + * Copyright Consensys Software Inc., 2023 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.datastructures.execution.verkle; + +import java.util.List; +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; +import tech.pegasys.teku.infrastructure.bytes.Bytes31; +import tech.pegasys.teku.infrastructure.ssz.SszList; +import tech.pegasys.teku.infrastructure.ssz.collections.SszByteList; +import tech.pegasys.teku.infrastructure.ssz.collections.SszByteVector; +import tech.pegasys.teku.infrastructure.ssz.containers.ContainerSchema5; +import tech.pegasys.teku.infrastructure.ssz.primitive.SszBytes32; +import tech.pegasys.teku.infrastructure.ssz.schema.SszFieldName; +import tech.pegasys.teku.infrastructure.ssz.schema.SszListSchema; +import tech.pegasys.teku.infrastructure.ssz.schema.SszPrimitiveSchemas; +import tech.pegasys.teku.infrastructure.ssz.schema.collections.SszByteListSchema; +import tech.pegasys.teku.infrastructure.ssz.schema.collections.SszByteVectorSchema; +import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode; + +public class VerkleProofSchema + extends ContainerSchema5< + VerkleProof, + SszList, + SszByteList, + SszList, + SszBytes32, + IpaProof> { + + static final SszFieldName FIELD_OTHER_STEMS = () -> "other_stems"; + static final SszFieldName FIELD_DEPTH_EXTENSION_PRESENT = () -> "depth_extension_present"; + static final SszFieldName FIELD_COMMITMENTS_BY_PATH = () -> "commitments_by_path"; + static final SszFieldName FIELD_IPA_PROOF = () -> "ipa_proof"; + + public VerkleProofSchema( + final IpaProofSchema ipaProofSchema, final int maxStems, final int maxCommitmentsPerStem) { + super( + "VerkleProof", + namedSchema( + FIELD_OTHER_STEMS, + SszListSchema.create(SszByteVectorSchema.create(Bytes31.SIZE), maxStems)), + namedSchema(FIELD_DEPTH_EXTENSION_PRESENT, SszByteListSchema.create(maxStems)), + namedSchema( + FIELD_COMMITMENTS_BY_PATH, + SszListSchema.create( + SszPrimitiveSchemas.BYTES32_SCHEMA, (long) maxStems * maxCommitmentsPerStem)), + namedSchema("d", SszPrimitiveSchemas.BYTES32_SCHEMA), + namedSchema(FIELD_IPA_PROOF, ipaProofSchema)); + } + + @SuppressWarnings("unchecked") + public SszListSchema> getOtherStemsSchema() { + return (SszListSchema>) + getChildSchema(getFieldIndex(FIELD_OTHER_STEMS)); + } + + public SszByteListSchema getDepthExtensionPresentSchema() { + return (SszByteListSchema) getChildSchema(getFieldIndex(FIELD_DEPTH_EXTENSION_PRESENT)); + } + + @SuppressWarnings("unchecked") + public SszListSchema> getCommitmentsByPathSchema() { + return (SszListSchema>) + getChildSchema(getFieldIndex(FIELD_COMMITMENTS_BY_PATH)); + } + + public IpaProofSchema getIpaProofSchema() { + return (IpaProofSchema) getChildSchema(getFieldIndex(FIELD_IPA_PROOF)); + } + + public VerkleProof create( + final List otherStems, + final Bytes depthExtensionPresent, + final List commitmentsByPath, + final Bytes32 d, + final IpaProof ipaProof) { + return new VerkleProof(this, otherStems, depthExtensionPresent, commitmentsByPath, d, ipaProof); + } + + @Override + public VerkleProof createFromBackingNode(TreeNode node) { + return new VerkleProof(this, node); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/verkle/package-info.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/verkle/package-info.java new file mode 100644 index 00000000000..17b75315b49 --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/verkle/package-info.java @@ -0,0 +1,5 @@ +/** + * Experimental implementation of Verkle Trees as of + * https://github.com/ethereum/consensus-specs/pull/3230 + */ +package tech.pegasys.teku.spec.datastructures.execution.verkle; diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/bellatrix/ExecutionPayloadBuilderBellatrix.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/bellatrix/ExecutionPayloadBuilderBellatrix.java index 58999ccbd8b..c982c2c1012 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/bellatrix/ExecutionPayloadBuilderBellatrix.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/bellatrix/ExecutionPayloadBuilderBellatrix.java @@ -28,6 +28,7 @@ import tech.pegasys.teku.infrastructure.unsigned.UInt64; import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayload; import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadBuilder; +import tech.pegasys.teku.spec.datastructures.execution.verkle.ExecutionWitness; import tech.pegasys.teku.spec.datastructures.execution.versions.capella.Withdrawal; public class ExecutionPayloadBuilderBellatrix implements ExecutionPayloadBuilder { @@ -142,6 +143,12 @@ public ExecutionPayloadBuilder withdrawals(final Supplier> with return this; } + @Override + public ExecutionPayloadBuilder executionWitness( + final Supplier executionWitnessSupplier) { + return this; + } + @Override public ExecutionPayloadBuilder blobGasUsed(final Supplier blobGasUsedSupplier) { return this; diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/bellatrix/ExecutionPayloadHeaderBuilderBellatrix.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/bellatrix/ExecutionPayloadHeaderBuilderBellatrix.java index 2df8d8af280..12a981abd58 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/bellatrix/ExecutionPayloadHeaderBuilderBellatrix.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/bellatrix/ExecutionPayloadHeaderBuilderBellatrix.java @@ -152,6 +152,12 @@ public ExecutionPayloadHeaderBuilder excessBlobGas(final Supplier excess return this; } + @Override + public ExecutionPayloadHeaderBuilder executionWitnessRoot( + final Supplier executionWitnessRootSupplier) { + return this; + } + protected void validateSchema() { checkNotNull(schema, "schema must be specified"); } diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/bellatrix/ExecutionPayloadSchemaBellatrix.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/bellatrix/ExecutionPayloadSchemaBellatrix.java index 1df2a1c9ea0..2dd55b6b7d3 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/bellatrix/ExecutionPayloadSchemaBellatrix.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/bellatrix/ExecutionPayloadSchemaBellatrix.java @@ -49,6 +49,7 @@ import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadSchema; import tech.pegasys.teku.spec.datastructures.execution.Transaction; import tech.pegasys.teku.spec.datastructures.execution.TransactionSchema; +import tech.pegasys.teku.spec.datastructures.execution.verkle.ExecutionWitnessSchema; import tech.pegasys.teku.spec.datastructures.execution.versions.capella.Withdrawal; import tech.pegasys.teku.spec.datastructures.execution.versions.capella.WithdrawalSchema; @@ -112,6 +113,11 @@ public WithdrawalSchema getWithdrawalSchemaRequired() { throw new IllegalStateException("Attempted to get a withdrawal schema from bellatrix"); } + @Override + public ExecutionWitnessSchema getExecutionWitnessSchemaRequired() { + throw new IllegalStateException("Attempted to get an execution witness schema from bellatrix"); + } + @Override public LongList getBlindedNodeGeneralizedIndices() { return LongList.of(getChildGeneralizedIndex(getFieldIndex(TRANSACTIONS))); diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/capella/ExecutionPayloadSchemaCapella.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/capella/ExecutionPayloadSchemaCapella.java index 78a0761b9fd..8039803da89 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/capella/ExecutionPayloadSchemaCapella.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/capella/ExecutionPayloadSchemaCapella.java @@ -50,6 +50,7 @@ import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadSchema; import tech.pegasys.teku.spec.datastructures.execution.Transaction; import tech.pegasys.teku.spec.datastructures.execution.TransactionSchema; +import tech.pegasys.teku.spec.datastructures.execution.verkle.ExecutionWitnessSchema; public class ExecutionPayloadSchemaCapella extends ContainerSchema15< @@ -158,4 +159,9 @@ public SszByteListSchema getExtraDataSchema() { public SszListSchema getWithdrawalsSchema() { return (SszListSchema) getFieldSchema14(); } + + @Override + public ExecutionWitnessSchema getExecutionWitnessSchemaRequired() { + throw new RuntimeException("Execution witness is not supported in Capella fork"); + } } diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/deneb/ExecutionPayloadBuilderDeneb.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/deneb/ExecutionPayloadBuilderDeneb.java index 6fb2e72aced..ad3769b7af2 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/deneb/ExecutionPayloadBuilderDeneb.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/deneb/ExecutionPayloadBuilderDeneb.java @@ -23,9 +23,9 @@ import tech.pegasys.teku.infrastructure.unsigned.UInt64; import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayload; import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadBuilder; -import tech.pegasys.teku.spec.datastructures.execution.versions.capella.ExecutionPayloadBuilderCapella; +import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionPayloadBuilderElectra; -public class ExecutionPayloadBuilderDeneb extends ExecutionPayloadBuilderCapella { +public class ExecutionPayloadBuilderDeneb extends ExecutionPayloadBuilderElectra { private ExecutionPayloadSchemaDeneb schema; protected UInt64 blobGasUsed; @@ -82,6 +82,7 @@ public ExecutionPayload build() { .map(schema.getTransactionSchema()::fromBytes) .collect(schema.getTransactionsSchema().collector()), schema.getWithdrawalsSchema().createFromElements(withdrawals), + executionWitness, SszUInt64.of(blobGasUsed), SszUInt64.of(excessBlobGas)); } diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/deneb/ExecutionPayloadDeneb.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/deneb/ExecutionPayloadDeneb.java index b5b3a76370c..b49b4a512e3 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/deneb/ExecutionPayloadDeneb.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/deneb/ExecutionPayloadDeneb.java @@ -17,9 +17,9 @@ import tech.pegasys.teku.infrastructure.unsigned.UInt64; import tech.pegasys.teku.spec.SpecMilestone; import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayload; -import tech.pegasys.teku.spec.datastructures.execution.versions.capella.ExecutionPayloadCapella; +import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionPayloadElectra; -public interface ExecutionPayloadDeneb extends ExecutionPayload, ExecutionPayloadCapella { +public interface ExecutionPayloadDeneb extends ExecutionPayloadElectra { static ExecutionPayloadDeneb required(final ExecutionPayload payload) { return payload diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/deneb/ExecutionPayloadDenebImpl.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/deneb/ExecutionPayloadDenebImpl.java index a85a82754b4..4c28c10c1a7 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/deneb/ExecutionPayloadDenebImpl.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/deneb/ExecutionPayloadDenebImpl.java @@ -22,18 +22,19 @@ import tech.pegasys.teku.infrastructure.ssz.SszList; import tech.pegasys.teku.infrastructure.ssz.collections.SszByteList; import tech.pegasys.teku.infrastructure.ssz.collections.SszByteVector; -import tech.pegasys.teku.infrastructure.ssz.containers.Container17; -import tech.pegasys.teku.infrastructure.ssz.containers.ContainerSchema17; +import tech.pegasys.teku.infrastructure.ssz.containers.Container18; +import tech.pegasys.teku.infrastructure.ssz.containers.ContainerSchema18; import tech.pegasys.teku.infrastructure.ssz.primitive.SszBytes32; import tech.pegasys.teku.infrastructure.ssz.primitive.SszUInt256; import tech.pegasys.teku.infrastructure.ssz.primitive.SszUInt64; import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode; import tech.pegasys.teku.infrastructure.unsigned.UInt64; import tech.pegasys.teku.spec.datastructures.execution.Transaction; +import tech.pegasys.teku.spec.datastructures.execution.verkle.ExecutionWitness; import tech.pegasys.teku.spec.datastructures.execution.versions.capella.Withdrawal; public class ExecutionPayloadDenebImpl - extends Container17< + extends Container18< ExecutionPayloadDenebImpl, SszBytes32, SszByteVector, @@ -50,12 +51,13 @@ public class ExecutionPayloadDenebImpl SszBytes32, SszList, SszList, + ExecutionWitness, SszUInt64, SszUInt64> implements ExecutionPayloadDeneb { public ExecutionPayloadDenebImpl( - ContainerSchema17< + ContainerSchema18< ExecutionPayloadDenebImpl, SszBytes32, SszByteVector, @@ -72,6 +74,7 @@ public ExecutionPayloadDenebImpl( SszBytes32, SszList, SszList, + ExecutionWitness, SszUInt64, SszUInt64> schema, @@ -96,6 +99,7 @@ public ExecutionPayloadDenebImpl( SszBytes32 blockHash, SszList transactions, SszList withdrawals, + ExecutionWitness executionWitness, SszUInt64 blobGasUsed, SszUInt64 excessBlobGas) { super( @@ -115,6 +119,7 @@ public ExecutionPayloadDenebImpl( blockHash, transactions, withdrawals, + executionWitness, blobGasUsed, excessBlobGas); } @@ -214,18 +219,26 @@ public SszList getWithdrawals() { return getField14(); } + @Override + public ExecutionWitness getExecutionWitness() { + return getField15(); + } + @Override public UInt64 getBlobGasUsed() { - return getField15().get(); + return getField16().get(); } @Override public UInt64 getExcessBlobGas() { - return getField16().get(); + return getField17().get(); } @Override public List getUnblindedTreeNodes() { - return List.of(getTransactions().getBackingNode(), getWithdrawals().getBackingNode()); + return List.of( + getTransactions().getBackingNode(), + getWithdrawals().getBackingNode(), + getExecutionWitness().getBackingNode()); } } diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/deneb/ExecutionPayloadHeaderBuilderDeneb.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/deneb/ExecutionPayloadHeaderBuilderDeneb.java index a2e691a516a..2008fedfd96 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/deneb/ExecutionPayloadHeaderBuilderDeneb.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/deneb/ExecutionPayloadHeaderBuilderDeneb.java @@ -23,9 +23,9 @@ import tech.pegasys.teku.infrastructure.unsigned.UInt64; import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadHeader; import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadHeaderBuilder; -import tech.pegasys.teku.spec.datastructures.execution.versions.capella.ExecutionPayloadHeaderBuilderCapella; +import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionPayloadHeaderBuilderElectra; -public class ExecutionPayloadHeaderBuilderDeneb extends ExecutionPayloadHeaderBuilderCapella { +public class ExecutionPayloadHeaderBuilderDeneb extends ExecutionPayloadHeaderBuilderElectra { private ExecutionPayloadHeaderSchemaDeneb schema; protected UInt64 blobGasUsed; @@ -81,6 +81,7 @@ public ExecutionPayloadHeader build() { SszBytes32.of(blockHash), SszBytes32.of(transactionsRoot), SszBytes32.of(withdrawalsRoot), + SszBytes32.of(executionWitnessRoot), SszUInt64.of(blobGasUsed), SszUInt64.of(excessBlobGas)); } diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/deneb/ExecutionPayloadHeaderDeneb.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/deneb/ExecutionPayloadHeaderDeneb.java index 809e6bf6185..f9ea32466d7 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/deneb/ExecutionPayloadHeaderDeneb.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/deneb/ExecutionPayloadHeaderDeneb.java @@ -15,9 +15,9 @@ import java.util.Optional; import tech.pegasys.teku.infrastructure.unsigned.UInt64; -import tech.pegasys.teku.spec.datastructures.execution.versions.capella.ExecutionPayloadHeaderCapella; +import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionPayloadHeaderElectra; -public interface ExecutionPayloadHeaderDeneb extends ExecutionPayloadHeaderCapella { +public interface ExecutionPayloadHeaderDeneb extends ExecutionPayloadHeaderElectra { UInt64 getBlobGasUsed(); diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/deneb/ExecutionPayloadHeaderDenebImpl.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/deneb/ExecutionPayloadHeaderDenebImpl.java index 5394769e9bf..49db5247853 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/deneb/ExecutionPayloadHeaderDenebImpl.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/deneb/ExecutionPayloadHeaderDenebImpl.java @@ -19,8 +19,8 @@ import tech.pegasys.teku.infrastructure.bytes.Bytes20; import tech.pegasys.teku.infrastructure.ssz.collections.SszByteList; import tech.pegasys.teku.infrastructure.ssz.collections.SszByteVector; -import tech.pegasys.teku.infrastructure.ssz.containers.Container17; -import tech.pegasys.teku.infrastructure.ssz.containers.ContainerSchema17; +import tech.pegasys.teku.infrastructure.ssz.containers.Container18; +import tech.pegasys.teku.infrastructure.ssz.containers.ContainerSchema18; import tech.pegasys.teku.infrastructure.ssz.primitive.SszBytes32; import tech.pegasys.teku.infrastructure.ssz.primitive.SszUInt256; import tech.pegasys.teku.infrastructure.ssz.primitive.SszUInt64; @@ -28,7 +28,7 @@ import tech.pegasys.teku.infrastructure.unsigned.UInt64; public class ExecutionPayloadHeaderDenebImpl - extends Container17< + extends Container18< ExecutionPayloadHeaderDenebImpl, SszBytes32, SszByteVector, @@ -45,12 +45,13 @@ public class ExecutionPayloadHeaderDenebImpl SszBytes32, SszBytes32, SszBytes32, + SszBytes32, SszUInt64, SszUInt64> implements ExecutionPayloadHeaderDeneb { protected ExecutionPayloadHeaderDenebImpl( - ContainerSchema17< + ContainerSchema18< ExecutionPayloadHeaderDenebImpl, SszBytes32, SszByteVector, @@ -67,6 +68,7 @@ protected ExecutionPayloadHeaderDenebImpl( SszBytes32, SszBytes32, SszBytes32, + SszBytes32, SszUInt64, SszUInt64> schema, @@ -91,6 +93,7 @@ public ExecutionPayloadHeaderDenebImpl( SszBytes32 blockHash, SszBytes32 transactionsRoot, SszBytes32 withdrawalsRoot, + SszBytes32 executionWitnessRoot, SszUInt64 blobGasUsed, SszUInt64 excessBlobGas) { super( @@ -110,6 +113,7 @@ public ExecutionPayloadHeaderDenebImpl( blockHash, transactionsRoot, withdrawalsRoot, + executionWitnessRoot, blobGasUsed, excessBlobGas); } @@ -210,12 +214,17 @@ public Bytes32 getWithdrawalsRoot() { } @Override - public UInt64 getBlobGasUsed() { + public Bytes32 getExecutionWitnessRoot() { return getField15().get(); } @Override - public UInt64 getExcessBlobGas() { + public UInt64 getBlobGasUsed() { return getField16().get(); } + + @Override + public UInt64 getExcessBlobGas() { + return getField17().get(); + } } diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/deneb/ExecutionPayloadHeaderSchemaDeneb.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/deneb/ExecutionPayloadHeaderSchemaDeneb.java index dc1dc227ea1..3c3ff98da5b 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/deneb/ExecutionPayloadHeaderSchemaDeneb.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/deneb/ExecutionPayloadHeaderSchemaDeneb.java @@ -18,6 +18,7 @@ import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.BLOCK_HASH; import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.BLOCK_NUMBER; import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.EXCESS_BLOB_GAS; +import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.EXECUTION_WITNESS_ROOT; import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.EXTRA_DATA; import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.FEE_RECIPIENT; import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.GAS_LIMIT; @@ -36,7 +37,7 @@ import tech.pegasys.teku.infrastructure.bytes.Bytes20; import tech.pegasys.teku.infrastructure.ssz.collections.SszByteList; import tech.pegasys.teku.infrastructure.ssz.collections.SszByteVector; -import tech.pegasys.teku.infrastructure.ssz.containers.ContainerSchema17; +import tech.pegasys.teku.infrastructure.ssz.containers.ContainerSchema18; import tech.pegasys.teku.infrastructure.ssz.primitive.SszBytes32; import tech.pegasys.teku.infrastructure.ssz.primitive.SszUInt256; import tech.pegasys.teku.infrastructure.ssz.primitive.SszUInt64; @@ -49,9 +50,10 @@ import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadHeader; import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadHeaderBuilder; import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadHeaderSchema; +import tech.pegasys.teku.spec.datastructures.execution.verkle.ExecutionWitnessSchema; public class ExecutionPayloadHeaderSchemaDeneb - extends ContainerSchema17< + extends ContainerSchema18< ExecutionPayloadHeaderDenebImpl, SszBytes32, SszByteVector, @@ -68,6 +70,7 @@ public class ExecutionPayloadHeaderSchemaDeneb SszBytes32, SszBytes32, SszBytes32, + SszBytes32, SszUInt64, SszUInt64> implements ExecutionPayloadHeaderSchema { @@ -75,7 +78,8 @@ public class ExecutionPayloadHeaderSchemaDeneb private final ExecutionPayloadHeaderDenebImpl defaultExecutionPayloadHeader; private final ExecutionPayloadHeaderDenebImpl executionPayloadHeaderOfDefaultPayload; - public ExecutionPayloadHeaderSchemaDeneb(final SpecConfigDeneb specConfig) { + public ExecutionPayloadHeaderSchemaDeneb( + final SpecConfigDeneb specConfig, final ExecutionWitnessSchema executionWitnessSchema) { super( "ExecutionPayloadHeaderDeneb", namedSchema(PARENT_HASH, SszPrimitiveSchemas.BYTES32_SCHEMA), @@ -93,11 +97,12 @@ public ExecutionPayloadHeaderSchemaDeneb(final SpecConfigDeneb specConfig) { namedSchema(BLOCK_HASH, SszPrimitiveSchemas.BYTES32_SCHEMA), namedSchema(TRANSACTIONS_ROOT, SszPrimitiveSchemas.BYTES32_SCHEMA), namedSchema(WITHDRAWALS_ROOT, SszPrimitiveSchemas.BYTES32_SCHEMA), + namedSchema(EXECUTION_WITNESS_ROOT, SszPrimitiveSchemas.BYTES32_SCHEMA), namedSchema(BLOB_GAS_USED, SszPrimitiveSchemas.UINT64_SCHEMA), namedSchema(EXCESS_BLOB_GAS, SszPrimitiveSchemas.UINT64_SCHEMA)); final ExecutionPayloadDenebImpl defaultExecutionPayload = - new ExecutionPayloadSchemaDeneb(specConfig).getDefault(); + new ExecutionPayloadSchemaDeneb(specConfig, executionWitnessSchema).getDefault(); this.executionPayloadHeaderOfDefaultPayload = createFromExecutionPayload(defaultExecutionPayload); @@ -113,7 +118,8 @@ public SszByteListSchema getExtraDataSchema() { public LongList getBlindedNodeGeneralizedIndices() { return LongList.of( getChildGeneralizedIndex(getFieldIndex(TRANSACTIONS_ROOT)), - getChildGeneralizedIndex(getFieldIndex(WITHDRAWALS_ROOT))); + getChildGeneralizedIndex(getFieldIndex(WITHDRAWALS_ROOT)), + getChildGeneralizedIndex(getFieldIndex(EXECUTION_WITNESS_ROOT))); } @Override @@ -161,6 +167,7 @@ public ExecutionPayloadHeaderDenebImpl createFromExecutionPayload( SszBytes32.of(executionPayload.getBlockHash()), SszBytes32.of(executionPayload.getTransactions().hashTreeRoot()), SszBytes32.of(executionPayload.getWithdrawals().hashTreeRoot()), + SszBytes32.of(executionPayload.getExecutionWitness().hashTreeRoot()), SszUInt64.of(executionPayload.getBlobGasUsed()), SszUInt64.of(executionPayload.getExcessBlobGas())); } diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/deneb/ExecutionPayloadSchemaDeneb.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/deneb/ExecutionPayloadSchemaDeneb.java index 0f909dc564e..7327c42a3f1 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/deneb/ExecutionPayloadSchemaDeneb.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/deneb/ExecutionPayloadSchemaDeneb.java @@ -18,6 +18,7 @@ import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.BLOCK_HASH; import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.BLOCK_NUMBER; import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.EXCESS_BLOB_GAS; +import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.EXECUTION_WITNESS; import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.EXTRA_DATA; import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.FEE_RECIPIENT; import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.GAS_LIMIT; @@ -37,7 +38,7 @@ import tech.pegasys.teku.infrastructure.ssz.SszList; import tech.pegasys.teku.infrastructure.ssz.collections.SszByteList; import tech.pegasys.teku.infrastructure.ssz.collections.SszByteVector; -import tech.pegasys.teku.infrastructure.ssz.containers.ContainerSchema17; +import tech.pegasys.teku.infrastructure.ssz.containers.ContainerSchema18; import tech.pegasys.teku.infrastructure.ssz.primitive.SszBytes32; import tech.pegasys.teku.infrastructure.ssz.primitive.SszUInt256; import tech.pegasys.teku.infrastructure.ssz.primitive.SszUInt64; @@ -52,11 +53,13 @@ import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadSchema; import tech.pegasys.teku.spec.datastructures.execution.Transaction; import tech.pegasys.teku.spec.datastructures.execution.TransactionSchema; +import tech.pegasys.teku.spec.datastructures.execution.verkle.ExecutionWitness; +import tech.pegasys.teku.spec.datastructures.execution.verkle.ExecutionWitnessSchema; import tech.pegasys.teku.spec.datastructures.execution.versions.capella.Withdrawal; import tech.pegasys.teku.spec.datastructures.execution.versions.capella.WithdrawalSchema; public class ExecutionPayloadSchemaDeneb - extends ContainerSchema17< + extends ContainerSchema18< ExecutionPayloadDenebImpl, SszBytes32, SszByteVector, @@ -73,13 +76,15 @@ public class ExecutionPayloadSchemaDeneb SszBytes32, SszList, SszList, + ExecutionWitness, SszUInt64, SszUInt64> implements ExecutionPayloadSchema { private final ExecutionPayloadDenebImpl defaultExecutionPayload; - public ExecutionPayloadSchemaDeneb(final SpecConfigDeneb specConfig) { + public ExecutionPayloadSchemaDeneb( + final SpecConfigDeneb specConfig, final ExecutionWitnessSchema executionWitnessSchema) { super( "ExecutionPayloadDeneb", namedSchema(PARENT_HASH, SszPrimitiveSchemas.BYTES32_SCHEMA), @@ -102,6 +107,7 @@ public ExecutionPayloadSchemaDeneb(final SpecConfigDeneb specConfig) { namedSchema( WITHDRAWALS, SszListSchema.create(Withdrawal.SSZ_SCHEMA, specConfig.getMaxWithdrawalsPerPayload())), + namedSchema(EXECUTION_WITNESS, executionWitnessSchema), namedSchema(BLOB_GAS_USED, SszPrimitiveSchemas.UINT64_SCHEMA), namedSchema(EXCESS_BLOB_GAS, SszPrimitiveSchemas.UINT64_SCHEMA)); this.defaultExecutionPayload = createFromBackingNode(getDefaultTree()); @@ -127,6 +133,11 @@ public WithdrawalSchema getWithdrawalSchemaRequired() { return getWithdrawalSchema(); } + @Override + public ExecutionWitnessSchema getExecutionWitnessSchemaRequired() { + return getExecutionWitnessSchema(); + } + public WithdrawalSchema getWithdrawalSchema() { return (WithdrawalSchema) getWithdrawalsSchema().getElementSchema(); } @@ -135,7 +146,8 @@ public WithdrawalSchema getWithdrawalSchema() { public LongList getBlindedNodeGeneralizedIndices() { return LongList.of( getChildGeneralizedIndex(getFieldIndex(TRANSACTIONS)), - getChildGeneralizedIndex(getFieldIndex(WITHDRAWALS))); + getChildGeneralizedIndex(getFieldIndex(WITHDRAWALS)), + getChildGeneralizedIndex(getFieldIndex(EXECUTION_WITNESS))); } @Override @@ -164,4 +176,8 @@ public SszByteListSchema getExtraDataSchema() { public SszListSchema getWithdrawalsSchema() { return (SszListSchema) getChildSchema(getFieldIndex(WITHDRAWALS)); } + + public ExecutionWitnessSchema getExecutionWitnessSchema() { + return (ExecutionWitnessSchema) getFieldSchema15(); + } } diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionPayloadBuilderElectra.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionPayloadBuilderElectra.java new file mode 100644 index 00000000000..a105853eafd --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionPayloadBuilderElectra.java @@ -0,0 +1,79 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.datastructures.execution.versions.electra; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.function.Supplier; +import tech.pegasys.teku.infrastructure.ssz.collections.SszByteVector; +import tech.pegasys.teku.infrastructure.ssz.primitive.SszBytes32; +import tech.pegasys.teku.infrastructure.ssz.primitive.SszUInt256; +import tech.pegasys.teku.infrastructure.ssz.primitive.SszUInt64; +import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayload; +import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadBuilder; +import tech.pegasys.teku.spec.datastructures.execution.verkle.ExecutionWitness; +import tech.pegasys.teku.spec.datastructures.execution.versions.capella.ExecutionPayloadBuilderCapella; + +public class ExecutionPayloadBuilderElectra extends ExecutionPayloadBuilderCapella { + private ExecutionPayloadSchemaElectra schema; + protected ExecutionWitness executionWitness; + + public ExecutionPayloadBuilderElectra schema(final ExecutionPayloadSchemaElectra schema) { + this.schema = schema; + return this; + } + + @Override + public ExecutionPayloadBuilder executionWitness( + final Supplier executionWitnessSupplier) { + this.executionWitness = executionWitnessSupplier.get(); + return this; + } + + @Override + protected void validateSchema() { + checkNotNull(schema, "schema must be specified"); + } + + @Override + protected void validate() { + super.validate(); + checkNotNull(executionWitness, "executionWitness must be specified"); + } + + @Override + public ExecutionPayload build() { + validate(); + return new ExecutionPayloadElectraImpl( + schema, + SszBytes32.of(parentHash), + SszByteVector.fromBytes(feeRecipient.getWrappedBytes()), + SszBytes32.of(stateRoot), + SszBytes32.of(receiptsRoot), + SszByteVector.fromBytes(logsBloom), + SszBytes32.of(prevRandao), + SszUInt64.of(blockNumber), + SszUInt64.of(gasLimit), + SszUInt64.of(gasUsed), + SszUInt64.of(timestamp), + schema.getExtraDataSchema().fromBytes(extraData), + SszUInt256.of(baseFeePerGas), + SszBytes32.of(blockHash), + transactions.stream() + .map(schema.getTransactionSchema()::fromBytes) + .collect(schema.getTransactionsSchema().collector()), + schema.getWithdrawalsSchema().createFromElements(withdrawals), + executionWitness); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionPayloadElectra.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionPayloadElectra.java new file mode 100644 index 00000000000..3976480936f --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionPayloadElectra.java @@ -0,0 +1,45 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.datastructures.execution.versions.electra; + +import java.util.Optional; +import tech.pegasys.teku.spec.SpecMilestone; +import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayload; +import tech.pegasys.teku.spec.datastructures.execution.verkle.ExecutionWitness; +import tech.pegasys.teku.spec.datastructures.execution.versions.capella.ExecutionPayloadCapella; + +public interface ExecutionPayloadElectra extends ExecutionPayloadCapella { + + static ExecutionPayloadElectra required(final ExecutionPayload payload) { + return payload + .toVersionElectra() + .orElseThrow( + () -> + new IllegalArgumentException( + "Expected electra execution payload but got " + + payload.getClass().getSimpleName())); + } + + ExecutionWitness getExecutionWitness(); + + @Override + default Optional toVersionElectra() { + return Optional.of(this); + } + + @Override + default SpecMilestone getMilestone() { + return SpecMilestone.ELECTRA; + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionPayloadElectraImpl.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionPayloadElectraImpl.java new file mode 100644 index 00000000000..efea5294c9f --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionPayloadElectraImpl.java @@ -0,0 +1,227 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.datastructures.execution.versions.electra; + +import java.util.List; +import java.util.Optional; +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; +import org.apache.tuweni.units.bigints.UInt256; +import tech.pegasys.teku.infrastructure.bytes.Bytes20; +import tech.pegasys.teku.infrastructure.ssz.SszList; +import tech.pegasys.teku.infrastructure.ssz.collections.SszByteList; +import tech.pegasys.teku.infrastructure.ssz.collections.SszByteVector; +import tech.pegasys.teku.infrastructure.ssz.containers.Container16; +import tech.pegasys.teku.infrastructure.ssz.containers.ContainerSchema16; +import tech.pegasys.teku.infrastructure.ssz.primitive.SszBytes32; +import tech.pegasys.teku.infrastructure.ssz.primitive.SszUInt256; +import tech.pegasys.teku.infrastructure.ssz.primitive.SszUInt64; +import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode; +import tech.pegasys.teku.infrastructure.unsigned.UInt64; +import tech.pegasys.teku.spec.datastructures.execution.Transaction; +import tech.pegasys.teku.spec.datastructures.execution.verkle.ExecutionWitness; +import tech.pegasys.teku.spec.datastructures.execution.versions.capella.Withdrawal; + +public class ExecutionPayloadElectraImpl + extends Container16< + ExecutionPayloadElectraImpl, + SszBytes32, + SszByteVector, + SszBytes32, + SszBytes32, + SszByteVector, + SszBytes32, + SszUInt64, + SszUInt64, + SszUInt64, + SszUInt64, + SszByteList, + SszUInt256, + SszBytes32, + SszList, + SszList, + ExecutionWitness> + implements ExecutionPayloadElectra { + + public ExecutionPayloadElectraImpl( + ContainerSchema16< + ExecutionPayloadElectraImpl, + SszBytes32, + SszByteVector, + SszBytes32, + SszBytes32, + SszByteVector, + SszBytes32, + SszUInt64, + SszUInt64, + SszUInt64, + SszUInt64, + SszByteList, + SszUInt256, + SszBytes32, + SszList, + SszList, + ExecutionWitness> + schema, + TreeNode backingNode) { + super(schema, backingNode); + } + + public ExecutionPayloadElectraImpl( + ExecutionPayloadSchemaElectra schema, + SszBytes32 parentHash, + SszByteVector feeRecipient, + SszBytes32 stateRoot, + SszBytes32 receiptsRoot, + SszByteVector logsBloom, + SszBytes32 prevRandao, + SszUInt64 blockNumber, + SszUInt64 gasLimit, + SszUInt64 gasUsed, + SszUInt64 timestamp, + SszByteList extraData, + SszUInt256 baseFeePerGas, + SszBytes32 blockHash, + SszList transactions, + SszList withdrawals, + ExecutionWitness executionWitness) { + super( + schema, + parentHash, + feeRecipient, + stateRoot, + receiptsRoot, + logsBloom, + prevRandao, + blockNumber, + gasLimit, + gasUsed, + timestamp, + extraData, + baseFeePerGas, + blockHash, + transactions, + withdrawals, + executionWitness); + } + + @Override + public boolean isDefaultPayload() { + return super.isDefault(); + } + + @Override + public Optional getOptionalWithdrawalsRoot() { + return Optional.of(getWithdrawals().hashTreeRoot()); + } + + @Override + public ExecutionPayloadSchemaElectra getSchema() { + return (ExecutionPayloadSchemaElectra) super.getSchema(); + } + + @Override + public Bytes32 getParentHash() { + return getField0().get(); + } + + @Override + public Bytes20 getFeeRecipient() { + return Bytes20.leftPad(getField1().getBytes()); + } + + @Override + public Bytes32 getStateRoot() { + return getField2().get(); + } + + @Override + public Bytes32 getReceiptsRoot() { + return getField3().get(); + } + + @Override + public Bytes getLogsBloom() { + return getField4().getBytes(); + } + + @Override + public Bytes32 getPrevRandao() { + return getField5().get(); + } + + @Override + public UInt64 getBlockNumber() { + return getField6().get(); + } + + @Override + public UInt64 getGasLimit() { + return getField7().get(); + } + + @Override + public UInt64 getGasUsed() { + return getField8().get(); + } + + @Override + public UInt64 getTimestamp() { + return getField9().get(); + } + + @Override + public Bytes getExtraData() { + return getField10().getBytes(); + } + + @Override + public UInt256 getBaseFeePerGas() { + return getField11().get(); + } + + @Override + public Bytes32 getBlockHash() { + return getField12().get(); + } + + @Override + public Bytes32 getPayloadHash() { + return hashTreeRoot(); + } + + @Override + public SszList getTransactions() { + return getField13(); + } + + @Override + public SszList getWithdrawals() { + return getField14(); + } + + @Override + public ExecutionWitness getExecutionWitness() { + return getField15(); + } + + // List generalisedIndex order + @Override + public List getUnblindedTreeNodes() { + return List.of( + getTransactions().getBackingNode(), + getWithdrawals().getBackingNode(), + getExecutionWitness().getBackingNode()); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionPayloadHeaderBuilderElectra.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionPayloadHeaderBuilderElectra.java new file mode 100644 index 00000000000..786a70f1472 --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionPayloadHeaderBuilderElectra.java @@ -0,0 +1,78 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.datastructures.execution.versions.electra; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.function.Supplier; +import org.apache.tuweni.bytes.Bytes32; +import tech.pegasys.teku.infrastructure.ssz.collections.SszByteVector; +import tech.pegasys.teku.infrastructure.ssz.primitive.SszBytes32; +import tech.pegasys.teku.infrastructure.ssz.primitive.SszUInt256; +import tech.pegasys.teku.infrastructure.ssz.primitive.SszUInt64; +import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadHeader; +import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadHeaderBuilder; +import tech.pegasys.teku.spec.datastructures.execution.versions.capella.ExecutionPayloadHeaderBuilderCapella; + +public class ExecutionPayloadHeaderBuilderElectra extends ExecutionPayloadHeaderBuilderCapella { + private ExecutionPayloadHeaderSchemaElectra schema; + protected Bytes32 executionWitnessRoot; + + public ExecutionPayloadHeaderBuilderElectra schema( + final ExecutionPayloadHeaderSchemaElectra schema) { + this.schema = schema; + return this; + } + + @Override + public ExecutionPayloadHeaderBuilder executionWitnessRoot( + final Supplier executionWitnessRootSupplier) { + this.executionWitnessRoot = executionWitnessRootSupplier.get(); + return this; + } + + @Override + protected void validateSchema() { + checkNotNull(schema, "schema must be specified"); + } + + @Override + protected void validate() { + super.validate(); + checkNotNull(executionWitnessRoot, "executionWitnessRoot must be specified"); + } + + @Override + public ExecutionPayloadHeader build() { + validate(); + return new ExecutionPayloadHeaderElectraImpl( + schema, + SszBytes32.of(parentHash), + SszByteVector.fromBytes(feeRecipient.getWrappedBytes()), + SszBytes32.of(stateRoot), + SszBytes32.of(receiptsRoot), + SszByteVector.fromBytes(logsBloom), + SszBytes32.of(prevRandao), + SszUInt64.of(blockNumber), + SszUInt64.of(gasLimit), + SszUInt64.of(gasUsed), + SszUInt64.of(timestamp), + schema.getExtraDataSchema().fromBytes(extraData), + SszUInt256.of(baseFeePerGas), + SszBytes32.of(blockHash), + SszBytes32.of(transactionsRoot), + SszBytes32.of(withdrawalsRoot), + SszBytes32.of(executionWitnessRoot)); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionPayloadHeaderElectra.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionPayloadHeaderElectra.java new file mode 100644 index 00000000000..fa3b9646a15 --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionPayloadHeaderElectra.java @@ -0,0 +1,28 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.datastructures.execution.versions.electra; + +import java.util.Optional; +import org.apache.tuweni.bytes.Bytes32; +import tech.pegasys.teku.spec.datastructures.execution.versions.capella.ExecutionPayloadHeaderCapella; + +public interface ExecutionPayloadHeaderElectra extends ExecutionPayloadHeaderCapella { + + Bytes32 getExecutionWitnessRoot(); + + @Override + default Optional toVersionElectra() { + return Optional.of(this); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionPayloadHeaderElectraImpl.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionPayloadHeaderElectraImpl.java new file mode 100644 index 00000000000..2eac39014d3 --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionPayloadHeaderElectraImpl.java @@ -0,0 +1,212 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.datastructures.execution.versions.electra; + +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; +import org.apache.tuweni.units.bigints.UInt256; +import tech.pegasys.teku.infrastructure.bytes.Bytes20; +import tech.pegasys.teku.infrastructure.ssz.collections.SszByteList; +import tech.pegasys.teku.infrastructure.ssz.collections.SszByteVector; +import tech.pegasys.teku.infrastructure.ssz.containers.Container16; +import tech.pegasys.teku.infrastructure.ssz.containers.ContainerSchema16; +import tech.pegasys.teku.infrastructure.ssz.primitive.SszBytes32; +import tech.pegasys.teku.infrastructure.ssz.primitive.SszUInt256; +import tech.pegasys.teku.infrastructure.ssz.primitive.SszUInt64; +import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode; +import tech.pegasys.teku.infrastructure.unsigned.UInt64; + +public class ExecutionPayloadHeaderElectraImpl + extends Container16< + ExecutionPayloadHeaderElectraImpl, + SszBytes32, + SszByteVector, + SszBytes32, + SszBytes32, + SszByteVector, + SszBytes32, + SszUInt64, + SszUInt64, + SszUInt64, + SszUInt64, + SszByteList, + SszUInt256, + SszBytes32, + SszBytes32, + SszBytes32, + SszBytes32> + implements ExecutionPayloadHeaderElectra { + + protected ExecutionPayloadHeaderElectraImpl( + ContainerSchema16< + ExecutionPayloadHeaderElectraImpl, + SszBytes32, + SszByteVector, + SszBytes32, + SszBytes32, + SszByteVector, + SszBytes32, + SszUInt64, + SszUInt64, + SszUInt64, + SszUInt64, + SszByteList, + SszUInt256, + SszBytes32, + SszBytes32, + SszBytes32, + SszBytes32> + schema, + TreeNode backingTree) { + super(schema, backingTree); + } + + public ExecutionPayloadHeaderElectraImpl( + ExecutionPayloadHeaderSchemaElectra schema, + SszBytes32 parentHash, + SszByteVector feeRecipient, + SszBytes32 stateRoot, + SszBytes32 receiptsRoot, + SszByteVector logsBloom, + SszBytes32 prevRandao, + SszUInt64 blockNumber, + SszUInt64 gasLimit, + SszUInt64 gasUsed, + SszUInt64 timestamp, + SszByteList extraData, + SszUInt256 baseFeePerGas, + SszBytes32 blockHash, + SszBytes32 transactionsRoot, + SszBytes32 withdrawalsRoot, + SszBytes32 executionWitnessRoot) { + super( + schema, + parentHash, + feeRecipient, + stateRoot, + receiptsRoot, + logsBloom, + prevRandao, + blockNumber, + gasLimit, + gasUsed, + timestamp, + extraData, + baseFeePerGas, + blockHash, + transactionsRoot, + withdrawalsRoot, + executionWitnessRoot); + } + + @Override + public boolean isDefaultPayload() { + return isHeaderOfDefaultPayload(); + } + + @Override + public ExecutionPayloadHeaderSchemaElectra getSchema() { + return (ExecutionPayloadHeaderSchemaElectra) super.getSchema(); + } + + @Override + public boolean isHeaderOfDefaultPayload() { + return equals(getSchema().getHeaderOfDefaultPayload()); + } + + @Override + public Bytes32 getParentHash() { + return getField0().get(); + } + + @Override + public Bytes20 getFeeRecipient() { + return Bytes20.leftPad(getField1().getBytes()); + } + + @Override + public Bytes32 getStateRoot() { + return getField2().get(); + } + + @Override + public Bytes32 getReceiptsRoot() { + return getField3().get(); + } + + @Override + public Bytes getLogsBloom() { + return getField4().getBytes(); + } + + @Override + public Bytes32 getPrevRandao() { + return getField5().get(); + } + + @Override + public UInt64 getBlockNumber() { + return getField6().get(); + } + + @Override + public UInt64 getGasLimit() { + return getField7().get(); + } + + @Override + public UInt64 getGasUsed() { + return getField8().get(); + } + + @Override + public UInt64 getTimestamp() { + return getField9().get(); + } + + @Override + public Bytes getExtraData() { + return getField10().getBytes(); + } + + @Override + public UInt256 getBaseFeePerGas() { + return getField11().get(); + } + + @Override + public Bytes32 getBlockHash() { + return getField12().get(); + } + + @Override + public Bytes32 getTransactionsRoot() { + return getField13().get(); + } + + @Override + public Bytes32 getPayloadHash() { + return hashTreeRoot(); + } + + @Override + public Bytes32 getWithdrawalsRoot() { + return getField14().get(); + } + + @Override + public Bytes32 getExecutionWitnessRoot() { + return getField15().get(); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionPayloadHeaderSchemaElectra.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionPayloadHeaderSchemaElectra.java new file mode 100644 index 00000000000..bb06974d4d6 --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionPayloadHeaderSchemaElectra.java @@ -0,0 +1,190 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.datastructures.execution.versions.electra; + +import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.BASE_FEE_PER_GAS; +import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.BLOCK_HASH; +import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.BLOCK_NUMBER; +import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.EXECUTION_WITNESS; +import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.EXECUTION_WITNESS_ROOT; +import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.EXTRA_DATA; +import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.FEE_RECIPIENT; +import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.GAS_LIMIT; +import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.GAS_USED; +import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.LOGS_BLOOM; +import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.PARENT_HASH; +import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.PREV_RANDAO; +import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.RECEIPTS_ROOT; +import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.STATE_ROOT; +import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.TIMESTAMP; +import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.TRANSACTIONS_ROOT; +import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.WITHDRAWALS_ROOT; + +import it.unimi.dsi.fastutil.longs.LongList; +import java.util.function.Consumer; +import tech.pegasys.teku.infrastructure.bytes.Bytes20; +import tech.pegasys.teku.infrastructure.ssz.collections.SszByteList; +import tech.pegasys.teku.infrastructure.ssz.collections.SszByteVector; +import tech.pegasys.teku.infrastructure.ssz.containers.ContainerSchema16; +import tech.pegasys.teku.infrastructure.ssz.primitive.SszBytes32; +import tech.pegasys.teku.infrastructure.ssz.primitive.SszUInt256; +import tech.pegasys.teku.infrastructure.ssz.primitive.SszUInt64; +import tech.pegasys.teku.infrastructure.ssz.schema.SszPrimitiveSchemas; +import tech.pegasys.teku.infrastructure.ssz.schema.collections.SszByteListSchema; +import tech.pegasys.teku.infrastructure.ssz.schema.collections.SszByteVectorSchema; +import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode; +import tech.pegasys.teku.spec.config.SpecConfigElectra; +import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayload; +import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadHeader; +import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadHeaderBuilder; +import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadHeaderSchema; +import tech.pegasys.teku.spec.datastructures.execution.verkle.ExecutionWitnessSchema; + +public class ExecutionPayloadHeaderSchemaElectra + extends ContainerSchema16< + ExecutionPayloadHeaderElectraImpl, + SszBytes32, + SszByteVector, + SszBytes32, + SszBytes32, + SszByteVector, + SszBytes32, + SszUInt64, + SszUInt64, + SszUInt64, + SszUInt64, + SszByteList, + SszUInt256, + SszBytes32, + SszBytes32, + SszBytes32, + SszBytes32> + implements ExecutionPayloadHeaderSchema { + + private final ExecutionPayloadHeaderElectraImpl defaultExecutionPayloadHeader; + private final ExecutionPayloadHeaderElectraImpl executionPayloadHeaderOfDefaultPayload; + + public ExecutionPayloadHeaderSchemaElectra( + final SpecConfigElectra specConfig, final ExecutionWitnessSchema executionWitnessSchema) { + super( + "ExecutionPayloadHeaderElectra", + namedSchema(PARENT_HASH, SszPrimitiveSchemas.BYTES32_SCHEMA), + namedSchema(FEE_RECIPIENT, SszByteVectorSchema.create(Bytes20.SIZE)), + namedSchema(STATE_ROOT, SszPrimitiveSchemas.BYTES32_SCHEMA), + namedSchema(RECEIPTS_ROOT, SszPrimitiveSchemas.BYTES32_SCHEMA), + namedSchema(LOGS_BLOOM, SszByteVectorSchema.create(specConfig.getBytesPerLogsBloom())), + namedSchema(PREV_RANDAO, SszPrimitiveSchemas.BYTES32_SCHEMA), + namedSchema(BLOCK_NUMBER, SszPrimitiveSchemas.UINT64_SCHEMA), + namedSchema(GAS_LIMIT, SszPrimitiveSchemas.UINT64_SCHEMA), + namedSchema(GAS_USED, SszPrimitiveSchemas.UINT64_SCHEMA), + namedSchema(TIMESTAMP, SszPrimitiveSchemas.UINT64_SCHEMA), + namedSchema(EXTRA_DATA, SszByteListSchema.create(specConfig.getMaxExtraDataBytes())), + namedSchema(BASE_FEE_PER_GAS, SszPrimitiveSchemas.UINT256_SCHEMA), + namedSchema(BLOCK_HASH, SszPrimitiveSchemas.BYTES32_SCHEMA), + namedSchema(TRANSACTIONS_ROOT, SszPrimitiveSchemas.BYTES32_SCHEMA), + namedSchema(WITHDRAWALS_ROOT, SszPrimitiveSchemas.BYTES32_SCHEMA), + namedSchema(EXECUTION_WITNESS_ROOT, SszPrimitiveSchemas.BYTES32_SCHEMA)); + + final ExecutionPayloadElectraImpl defaultExecutionPayload = + new ExecutionPayloadSchemaElectra(specConfig, executionWitnessSchema).getDefault(); + + this.executionPayloadHeaderOfDefaultPayload = + createFromExecutionPayload(defaultExecutionPayload); + + this.defaultExecutionPayloadHeader = createFromBackingNode(getDefaultTree()); + } + + public ExecutionPayloadHeaderElectraImpl createFromExecutionPayload( + final ExecutionPayloadElectraImpl executionPayload) { + return new ExecutionPayloadHeaderElectraImpl( + this, + SszBytes32.of(executionPayload.getParentHash()), + SszByteVector.fromBytes(executionPayload.getFeeRecipient().getWrappedBytes()), + SszBytes32.of(executionPayload.getStateRoot()), + SszBytes32.of(executionPayload.getReceiptsRoot()), + SszByteVector.fromBytes(executionPayload.getLogsBloom()), + SszBytes32.of(executionPayload.getPrevRandao()), + SszUInt64.of(executionPayload.getBlockNumber()), + SszUInt64.of(executionPayload.getGasLimit()), + SszUInt64.of(executionPayload.getGasUsed()), + SszUInt64.of(executionPayload.getTimestamp()), + getExtraDataSchema().fromBytes(executionPayload.getExtraData()), + SszUInt256.of(executionPayload.getBaseFeePerGas()), + SszBytes32.of(executionPayload.getBlockHash()), + SszBytes32.of(executionPayload.getTransactions().hashTreeRoot()), + SszBytes32.of(executionPayload.getWithdrawals().hashTreeRoot()), + SszBytes32.of(executionPayload.getExecutionWitness().hashTreeRoot())); + } + + public SszByteListSchema getExtraDataSchema() { + return (SszByteListSchema) getFieldSchema10(); + } + + // note needs generalized index order + @Override + public LongList getBlindedNodeGeneralizedIndices() { + return LongList.of( + getChildGeneralizedIndex(getFieldIndex(TRANSACTIONS_ROOT)), + getChildGeneralizedIndex(getFieldIndex(WITHDRAWALS_ROOT)), + getChildGeneralizedIndex(getFieldIndex(EXECUTION_WITNESS))); + } + + @Override + public ExecutionPayloadHeader createExecutionPayloadHeader( + final Consumer builderConsumer) { + final ExecutionPayloadHeaderBuilderElectra builder = + new ExecutionPayloadHeaderBuilderElectra().schema(this); + builderConsumer.accept(builder); + return builder.build(); + } + + @Override + public ExecutionPayloadHeaderElectraImpl getDefault() { + return defaultExecutionPayloadHeader; + } + + @Override + public ExecutionPayloadHeaderElectra getHeaderOfDefaultPayload() { + return executionPayloadHeaderOfDefaultPayload; + } + + @Override + public ExecutionPayloadHeaderElectraImpl createFromBackingNode(TreeNode node) { + return new ExecutionPayloadHeaderElectraImpl(this, node); + } + + @Override + public ExecutionPayloadHeaderElectraImpl createFromExecutionPayload( + final ExecutionPayload payload) { + final ExecutionPayloadElectra executionPayload = ExecutionPayloadElectra.required(payload); + return new ExecutionPayloadHeaderElectraImpl( + this, + SszBytes32.of(executionPayload.getParentHash()), + SszByteVector.fromBytes(executionPayload.getFeeRecipient().getWrappedBytes()), + SszBytes32.of(executionPayload.getStateRoot()), + SszBytes32.of(executionPayload.getReceiptsRoot()), + SszByteVector.fromBytes(executionPayload.getLogsBloom()), + SszBytes32.of(executionPayload.getPrevRandao()), + SszUInt64.of(executionPayload.getBlockNumber()), + SszUInt64.of(executionPayload.getGasLimit()), + SszUInt64.of(executionPayload.getGasUsed()), + SszUInt64.of(executionPayload.getTimestamp()), + getExtraDataSchema().fromBytes(executionPayload.getExtraData()), + SszUInt256.of(executionPayload.getBaseFeePerGas()), + SszBytes32.of(executionPayload.getBlockHash()), + SszBytes32.of(executionPayload.getTransactions().hashTreeRoot()), + SszBytes32.of(executionPayload.getWithdrawals().hashTreeRoot()), + SszBytes32.of(executionPayload.getExecutionWitness().hashTreeRoot())); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionPayloadSchemaElectra.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionPayloadSchemaElectra.java new file mode 100644 index 00000000000..7236bb5a2ac --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionPayloadSchemaElectra.java @@ -0,0 +1,179 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.datastructures.execution.versions.electra; + +import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.BASE_FEE_PER_GAS; +import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.BLOCK_HASH; +import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.BLOCK_NUMBER; +import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.EXECUTION_WITNESS; +import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.EXTRA_DATA; +import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.FEE_RECIPIENT; +import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.GAS_LIMIT; +import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.GAS_USED; +import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.LOGS_BLOOM; +import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.PARENT_HASH; +import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.PREV_RANDAO; +import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.RECEIPTS_ROOT; +import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.STATE_ROOT; +import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.TIMESTAMP; +import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.TRANSACTIONS; +import static tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadFields.WITHDRAWALS; + +import it.unimi.dsi.fastutil.longs.LongList; +import java.util.function.Consumer; +import tech.pegasys.teku.infrastructure.bytes.Bytes20; +import tech.pegasys.teku.infrastructure.ssz.SszList; +import tech.pegasys.teku.infrastructure.ssz.collections.SszByteList; +import tech.pegasys.teku.infrastructure.ssz.collections.SszByteVector; +import tech.pegasys.teku.infrastructure.ssz.containers.ContainerSchema16; +import tech.pegasys.teku.infrastructure.ssz.primitive.SszBytes32; +import tech.pegasys.teku.infrastructure.ssz.primitive.SszUInt256; +import tech.pegasys.teku.infrastructure.ssz.primitive.SszUInt64; +import tech.pegasys.teku.infrastructure.ssz.schema.SszListSchema; +import tech.pegasys.teku.infrastructure.ssz.schema.SszPrimitiveSchemas; +import tech.pegasys.teku.infrastructure.ssz.schema.collections.SszByteListSchema; +import tech.pegasys.teku.infrastructure.ssz.schema.collections.SszByteVectorSchema; +import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode; +import tech.pegasys.teku.spec.config.SpecConfigElectra; +import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayload; +import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadBuilder; +import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadSchema; +import tech.pegasys.teku.spec.datastructures.execution.Transaction; +import tech.pegasys.teku.spec.datastructures.execution.TransactionSchema; +import tech.pegasys.teku.spec.datastructures.execution.verkle.ExecutionWitness; +import tech.pegasys.teku.spec.datastructures.execution.verkle.ExecutionWitnessSchema; +import tech.pegasys.teku.spec.datastructures.execution.versions.capella.Withdrawal; +import tech.pegasys.teku.spec.datastructures.execution.versions.capella.WithdrawalSchema; + +public class ExecutionPayloadSchemaElectra + extends ContainerSchema16< + ExecutionPayloadElectraImpl, + SszBytes32, + SszByteVector, + SszBytes32, + SszBytes32, + SszByteVector, + SszBytes32, + SszUInt64, + SszUInt64, + SszUInt64, + SszUInt64, + SszByteList, + SszUInt256, + SszBytes32, + SszList, + SszList, + ExecutionWitness> + implements ExecutionPayloadSchema { + + private final ExecutionPayloadElectraImpl defaultExecutionPayload; + + public ExecutionPayloadSchemaElectra( + final SpecConfigElectra specConfig, final ExecutionWitnessSchema executionWitnessSchema) { + super( + "ExecutionPayloadElectra", + namedSchema(PARENT_HASH, SszPrimitiveSchemas.BYTES32_SCHEMA), + namedSchema(FEE_RECIPIENT, SszByteVectorSchema.create(Bytes20.SIZE)), + namedSchema(STATE_ROOT, SszPrimitiveSchemas.BYTES32_SCHEMA), + namedSchema(RECEIPTS_ROOT, SszPrimitiveSchemas.BYTES32_SCHEMA), + namedSchema(LOGS_BLOOM, SszByteVectorSchema.create(specConfig.getBytesPerLogsBloom())), + namedSchema(PREV_RANDAO, SszPrimitiveSchemas.BYTES32_SCHEMA), + namedSchema(BLOCK_NUMBER, SszPrimitiveSchemas.UINT64_SCHEMA), + namedSchema(GAS_LIMIT, SszPrimitiveSchemas.UINT64_SCHEMA), + namedSchema(GAS_USED, SszPrimitiveSchemas.UINT64_SCHEMA), + namedSchema(TIMESTAMP, SszPrimitiveSchemas.UINT64_SCHEMA), + namedSchema(EXTRA_DATA, SszByteListSchema.create(specConfig.getMaxExtraDataBytes())), + namedSchema(BASE_FEE_PER_GAS, SszPrimitiveSchemas.UINT256_SCHEMA), + namedSchema(BLOCK_HASH, SszPrimitiveSchemas.BYTES32_SCHEMA), + namedSchema( + TRANSACTIONS, + SszListSchema.create( + new TransactionSchema(specConfig), specConfig.getMaxTransactionsPerPayload())), + namedSchema( + WITHDRAWALS, + SszListSchema.create(Withdrawal.SSZ_SCHEMA, specConfig.getMaxWithdrawalsPerPayload())), + namedSchema(EXECUTION_WITNESS, executionWitnessSchema)); + this.defaultExecutionPayload = createFromBackingNode(getDefaultTree()); + } + + @Override + public ExecutionPayloadElectraImpl getDefault() { + return defaultExecutionPayload; + } + + @Override + public TransactionSchema getTransactionSchema() { + return (TransactionSchema) getTransactionsSchema().getElementSchema(); + } + + @Override + public SszListSchema> getWithdrawalsSchemaRequired() { + return getWithdrawalsSchema(); + } + + @Override + public WithdrawalSchema getWithdrawalSchemaRequired() { + return getWithdrawalSchema(); + } + + @Override + public ExecutionWitnessSchema getExecutionWitnessSchemaRequired() { + return getExecutionWitnessSchema(); + } + + public WithdrawalSchema getWithdrawalSchema() { + return (WithdrawalSchema) getWithdrawalsSchema().getElementSchema(); + } + + @Override + public LongList getBlindedNodeGeneralizedIndices() { + return LongList.of( + getChildGeneralizedIndex(getFieldIndex(TRANSACTIONS)), + getChildGeneralizedIndex(getFieldIndex(WITHDRAWALS)), + getChildGeneralizedIndex(getFieldIndex(EXECUTION_WITNESS))); + } + + @Override + public ExecutionPayload createExecutionPayload( + final Consumer builderConsumer) { + final ExecutionPayloadBuilderElectra builder = + new ExecutionPayloadBuilderElectra().schema(this); + builderConsumer.accept(builder); + return builder.build(); + } + + @Override + public ExecutionPayloadElectraImpl createFromBackingNode(TreeNode node) { + return new ExecutionPayloadElectraImpl(this, node); + } + + @SuppressWarnings("unchecked") + public SszByteListSchema getExtraDataSchema() { + return (SszByteListSchema) getFieldSchema10(); + } + + @SuppressWarnings("unchecked") + public SszListSchema getTransactionsSchema() { + return (SszListSchema) getFieldSchema13(); + } + + @SuppressWarnings("unchecked") + public SszListSchema getWithdrawalsSchema() { + return (SszListSchema) getFieldSchema14(); + } + + public ExecutionWitnessSchema getExecutionWitnessSchema() { + return (ExecutionWitnessSchema) getFieldSchema15(); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/BeaconState.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/BeaconState.java index 03ecdf6544c..26cc3a90bea 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/BeaconState.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/BeaconState.java @@ -39,6 +39,7 @@ import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.bellatrix.BeaconStateBellatrix; import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.capella.BeaconStateCapella; import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.deneb.BeaconStateDeneb; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.electra.BeaconStateElectra; import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.phase0.BeaconStatePhase0; public interface BeaconState extends SszContainer, ValidatorStats { @@ -184,6 +185,10 @@ default Optional toVersionCapella() { return Optional.empty(); } + default Optional toVersionElectra() { + return Optional.empty(); + } + default Optional toVersionDeneb() { return Optional.empty(); } diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/MutableBeaconState.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/MutableBeaconState.java index 6915ba9e836..46b34aaacd9 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/MutableBeaconState.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/MutableBeaconState.java @@ -40,6 +40,7 @@ import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.bellatrix.MutableBeaconStateBellatrix; import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.capella.MutableBeaconStateCapella; import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.deneb.MutableBeaconStateDeneb; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.electra.MutableBeaconStateElectra; import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.phase0.MutableBeaconStatePhase0; public interface MutableBeaconState extends BeaconState, SszMutableRefContainer { @@ -215,6 +216,10 @@ default Optional toMutableVersionCapella() { return Optional.empty(); } + default Optional toMutableVersionElectra() { + return Optional.empty(); + } + default Optional toMutableVersionDeneb() { return Optional.empty(); } diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/versions/deneb/BeaconStateDeneb.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/versions/deneb/BeaconStateDeneb.java index ea135073b5f..4f43f489edc 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/versions/deneb/BeaconStateDeneb.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/versions/deneb/BeaconStateDeneb.java @@ -16,9 +16,9 @@ import com.google.common.base.MoreObjects; import java.util.Optional; import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconState; -import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.capella.BeaconStateCapella; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.electra.BeaconStateElectra; -public interface BeaconStateDeneb extends BeaconStateCapella { +public interface BeaconStateDeneb extends BeaconStateElectra { static BeaconStateDeneb required(final BeaconState state) { return state .toVersionDeneb() @@ -29,8 +29,8 @@ static BeaconStateDeneb required(final BeaconState state) { } static void describeCustomDenebFields( - MoreObjects.ToStringHelper stringBuilder, BeaconStateCapella state) { - BeaconStateCapella.describeCustomCapellaFields(stringBuilder, state); + MoreObjects.ToStringHelper stringBuilder, BeaconStateElectra state) { + BeaconStateElectra.describeCustomElectraFields(stringBuilder, state); // no new fields } diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/versions/deneb/BeaconStateSchemaDeneb.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/versions/deneb/BeaconStateSchemaDeneb.java index 71e064dac27..684269121bf 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/versions/deneb/BeaconStateSchemaDeneb.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/versions/deneb/BeaconStateSchemaDeneb.java @@ -31,6 +31,7 @@ import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode; import tech.pegasys.teku.spec.config.SpecConfig; import tech.pegasys.teku.spec.config.SpecConfigDeneb; +import tech.pegasys.teku.spec.datastructures.execution.verkle.ExecutionWitnessSchema; import tech.pegasys.teku.spec.datastructures.execution.versions.deneb.ExecutionPayloadHeaderSchemaDeneb; import tech.pegasys.teku.spec.datastructures.state.SyncCommittee; import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconStateSchema; @@ -43,18 +44,22 @@ public class BeaconStateSchemaDeneb extends AbstractBeaconStateSchema { @VisibleForTesting - BeaconStateSchemaDeneb(final SpecConfig specConfig) { - super("BeaconStateDeneb", getUniqueFields(specConfig), specConfig); + BeaconStateSchemaDeneb( + final SpecConfig specConfig, final ExecutionWitnessSchema executionWitnessSchema) { + super("BeaconStateDeneb", getUniqueFields(specConfig, executionWitnessSchema), specConfig); } - private static List getUniqueFields(final SpecConfig specConfig) { + private static List getUniqueFields( + final SpecConfig specConfig, final ExecutionWitnessSchema executionWitnessSchema) { final HistoricalSummary.HistoricalSummarySchema historicalSummarySchema = new HistoricalSummary.HistoricalSummarySchema(); final SszField latestExecutionPayloadHeaderField = new SszField( LATEST_EXECUTION_PAYLOAD_HEADER_FIELD_INDEX, BeaconStateFields.LATEST_EXECUTION_PAYLOAD_HEADER, - () -> new ExecutionPayloadHeaderSchemaDeneb(SpecConfigDeneb.required(specConfig))); + () -> + new ExecutionPayloadHeaderSchemaDeneb( + SpecConfigDeneb.required(specConfig), executionWitnessSchema)); final SszField nextWithdrawalIndexField = new SszField( NEXT_WITHDRAWAL_INDEX, @@ -120,8 +125,9 @@ public MutableBeaconStateDeneb createBuilder() { return new MutableBeaconStateDenebImpl(createEmptyBeaconStateImpl(), true); } - public static BeaconStateSchemaDeneb create(final SpecConfig specConfig) { - return new BeaconStateSchemaDeneb(specConfig); + public static BeaconStateSchemaDeneb create( + final SpecConfig specConfig, final ExecutionWitnessSchema executionWitnessSchema) { + return new BeaconStateSchemaDeneb(specConfig, executionWitnessSchema); } public static BeaconStateSchemaDeneb required(final BeaconStateSchema schema) { diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/versions/deneb/MutableBeaconStateDeneb.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/versions/deneb/MutableBeaconStateDeneb.java index 55ac321f916..6da550ee7c5 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/versions/deneb/MutableBeaconStateDeneb.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/versions/deneb/MutableBeaconStateDeneb.java @@ -15,9 +15,9 @@ import java.util.Optional; import tech.pegasys.teku.spec.datastructures.state.beaconstate.MutableBeaconState; -import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.capella.MutableBeaconStateCapella; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.electra.MutableBeaconStateElectra; -public interface MutableBeaconStateDeneb extends MutableBeaconStateCapella, BeaconStateDeneb { +public interface MutableBeaconStateDeneb extends MutableBeaconStateElectra, BeaconStateDeneb { static MutableBeaconStateDeneb required(final MutableBeaconState state) { return state .toMutableVersionDeneb() diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/versions/electra/BeaconStateElectra.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/versions/electra/BeaconStateElectra.java new file mode 100644 index 00000000000..ff2f88399a2 --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/versions/electra/BeaconStateElectra.java @@ -0,0 +1,51 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.electra; + +import com.google.common.base.MoreObjects; +import java.util.Optional; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconState; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.capella.BeaconStateCapella; + +public interface BeaconStateElectra extends BeaconStateCapella { + static BeaconStateElectra required(final BeaconState state) { + return state + .toVersionElectra() + .orElseThrow( + () -> + new IllegalArgumentException( + "Expected an electra state but got: " + state.getClass().getSimpleName())); + } + + static void describeCustomElectraFields( + MoreObjects.ToStringHelper stringBuilder, BeaconStateCapella state) { + BeaconStateCapella.describeCustomCapellaFields(stringBuilder, state); + } + + @Override + MutableBeaconStateElectra createWritableCopy(); + + default + BeaconStateElectra updatedElectra(Mutator mutator) + throws E1, E2, E3 { + MutableBeaconStateElectra writableCopy = createWritableCopy(); + mutator.mutate(writableCopy); + return writableCopy.commitChanges(); + } + + @Override + default Optional toVersionElectra() { + return Optional.of(this); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/versions/electra/BeaconStateElectraImpl.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/versions/electra/BeaconStateElectraImpl.java new file mode 100644 index 00000000000..9dd9521222d --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/versions/electra/BeaconStateElectraImpl.java @@ -0,0 +1,66 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.electra; + +import com.google.common.base.MoreObjects; +import tech.pegasys.teku.infrastructure.ssz.SszContainer; +import tech.pegasys.teku.infrastructure.ssz.SszData; +import tech.pegasys.teku.infrastructure.ssz.cache.IntCache; +import tech.pegasys.teku.infrastructure.ssz.schema.SszCompositeSchema; +import tech.pegasys.teku.infrastructure.ssz.schema.impl.AbstractSszContainerSchema; +import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconStateCache; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconStateSchema; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.common.AbstractBeaconState; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.common.SlotCaches; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.common.TransitionCaches; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.altair.ValidatorStatsAltair; + +public class BeaconStateElectraImpl extends AbstractBeaconState + implements BeaconStateElectra, BeaconStateCache, ValidatorStatsAltair { + + BeaconStateElectraImpl( + final BeaconStateSchema schema) { + super(schema); + } + + BeaconStateElectraImpl( + SszCompositeSchema type, + TreeNode backingNode, + IntCache cache, + TransitionCaches transitionCaches, + SlotCaches slotCaches) { + super(type, backingNode, cache, transitionCaches, slotCaches); + } + + BeaconStateElectraImpl( + AbstractSszContainerSchema type, TreeNode backingNode) { + super(type, backingNode); + } + + @Override + public BeaconStateSchemaElectra getBeaconStateSchema() { + return (BeaconStateSchemaElectra) getSchema(); + } + + @Override + public MutableBeaconStateElectra createWritableCopy() { + return new MutableBeaconStateElectraImpl(this); + } + + @Override + protected void describeCustomFields(MoreObjects.ToStringHelper stringBuilder) { + BeaconStateElectra.describeCustomElectraFields(stringBuilder, this); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/versions/electra/BeaconStateSchemaElectra.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/versions/electra/BeaconStateSchemaElectra.java new file mode 100644 index 00000000000..1804c054d3c --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/versions/electra/BeaconStateSchemaElectra.java @@ -0,0 +1,160 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.electra; + +import static com.google.common.base.Preconditions.checkArgument; +import static tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.bellatrix.BeaconStateSchemaBellatrix.LATEST_EXECUTION_PAYLOAD_HEADER_FIELD_INDEX; +import static tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.capella.BeaconStateSchemaCapella.HISTORICAL_SUMMARIES_INDEX; +import static tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.capella.BeaconStateSchemaCapella.NEXT_WITHDRAWAL_INDEX; +import static tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.capella.BeaconStateSchemaCapella.NEXT_WITHDRAWAL_VALIDATOR_INDEX; + +import com.google.common.annotations.VisibleForTesting; +import java.util.List; +import java.util.stream.Stream; +import tech.pegasys.teku.infrastructure.ssz.primitive.SszByte; +import tech.pegasys.teku.infrastructure.ssz.schema.SszListSchema; +import tech.pegasys.teku.infrastructure.ssz.schema.SszPrimitiveSchemas; +import tech.pegasys.teku.infrastructure.ssz.schema.collections.SszPrimitiveListSchema; +import tech.pegasys.teku.infrastructure.ssz.schema.collections.SszUInt64ListSchema; +import tech.pegasys.teku.infrastructure.ssz.sos.SszField; +import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode; +import tech.pegasys.teku.spec.config.SpecConfig; +import tech.pegasys.teku.spec.config.SpecConfigElectra; +import tech.pegasys.teku.spec.datastructures.execution.verkle.ExecutionWitnessSchema; +import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionPayloadHeaderSchemaElectra; +import tech.pegasys.teku.spec.datastructures.state.SyncCommittee; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconStateSchema; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.common.AbstractBeaconStateSchema; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.common.BeaconStateFields; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.altair.BeaconStateSchemaAltair; +import tech.pegasys.teku.spec.datastructures.state.versions.capella.HistoricalSummary; + +public class BeaconStateSchemaElectra + extends AbstractBeaconStateSchema { + + @VisibleForTesting + BeaconStateSchemaElectra( + final SpecConfig specConfig, final ExecutionWitnessSchema executionWitnessSchema) { + super("BeaconStateElectra", getUniqueFields(specConfig, executionWitnessSchema), specConfig); + } + + private static List getUniqueFields( + final SpecConfig specConfig, final ExecutionWitnessSchema executionWitnessSchema) { + final HistoricalSummary.HistoricalSummarySchema historicalSummarySchema = + new HistoricalSummary.HistoricalSummarySchema(); + final SszField latestExecutionPayloadHeaderField = + new SszField( + LATEST_EXECUTION_PAYLOAD_HEADER_FIELD_INDEX, + BeaconStateFields.LATEST_EXECUTION_PAYLOAD_HEADER, + () -> + new ExecutionPayloadHeaderSchemaElectra( + SpecConfigElectra.required(specConfig), executionWitnessSchema)); + final SszField nextWithdrawalIndexField = + new SszField( + NEXT_WITHDRAWAL_INDEX, + BeaconStateFields.NEXT_WITHDRAWAL_INDEX, + () -> SszPrimitiveSchemas.UINT64_SCHEMA); + final SszField nextWithdrawalValidatorIndexField = + new SszField( + NEXT_WITHDRAWAL_VALIDATOR_INDEX, + BeaconStateFields.NEXT_WITHDRAWAL_VALIDATOR_INDEX, + () -> SszPrimitiveSchemas.UINT64_SCHEMA); + + final SszField historicalSummariesField = + new SszField( + HISTORICAL_SUMMARIES_INDEX, + BeaconStateFields.HISTORICAL_SUMMARIES, + () -> + SszListSchema.create( + historicalSummarySchema, specConfig.getHistoricalRootsLimit())); + return Stream.concat( + BeaconStateSchemaAltair.getUniqueFields(specConfig).stream(), + Stream.of( + latestExecutionPayloadHeaderField, + nextWithdrawalIndexField, + nextWithdrawalValidatorIndexField, + historicalSummariesField)) + .toList(); + } + + @SuppressWarnings("unchecked") + public SszPrimitiveListSchema getPreviousEpochParticipationSchema() { + return (SszPrimitiveListSchema) + getChildSchema(getFieldIndex(BeaconStateFields.PREVIOUS_EPOCH_PARTICIPATION)); + } + + @SuppressWarnings("unchecked") + public SszPrimitiveListSchema getCurrentEpochParticipationSchema() { + return (SszPrimitiveListSchema) + getChildSchema(getFieldIndex(BeaconStateFields.CURRENT_EPOCH_PARTICIPATION)); + } + + public SszUInt64ListSchema getInactivityScoresSchema() { + return (SszUInt64ListSchema) + getChildSchema(getFieldIndex(BeaconStateFields.INACTIVITY_SCORES)); + } + + @SuppressWarnings("unchecked") + public SszListSchema getHistoricalSummariesSchema() { + return (SszListSchema) + getChildSchema(getFieldIndex(BeaconStateFields.HISTORICAL_SUMMARIES)); + } + + public SyncCommittee.SyncCommitteeSchema getCurrentSyncCommitteeSchema() { + return (SyncCommittee.SyncCommitteeSchema) + getChildSchema(getFieldIndex(BeaconStateFields.CURRENT_SYNC_COMMITTEE)); + } + + public SyncCommittee.SyncCommitteeSchema getNextSyncCommitteeSchema() { + return (SyncCommittee.SyncCommitteeSchema) + getChildSchema(getFieldIndex(BeaconStateFields.NEXT_SYNC_COMMITTEE)); + } + + public ExecutionPayloadHeaderSchemaElectra getLastExecutionPayloadHeaderSchema() { + return (ExecutionPayloadHeaderSchemaElectra) + getChildSchema(getFieldIndex(BeaconStateFields.LATEST_EXECUTION_PAYLOAD_HEADER)); + } + + @Override + public MutableBeaconStateElectra createBuilder() { + return new MutableBeaconStateElectraImpl(createEmptyBeaconStateImpl(), true); + } + + public static BeaconStateSchemaElectra create( + final SpecConfig specConfig, final ExecutionWitnessSchema executionWitnessSchema) { + return new BeaconStateSchemaElectra(specConfig, executionWitnessSchema); + } + + public static BeaconStateSchemaElectra required(final BeaconStateSchema schema) { + checkArgument( + schema instanceof BeaconStateSchemaElectra, + "Expected a BeaconStateSchemaElectra but was %s", + schema.getClass()); + return (BeaconStateSchemaElectra) schema; + } + + @Override + public BeaconStateElectra createEmpty() { + return createEmptyBeaconStateImpl(); + } + + private BeaconStateElectraImpl createEmptyBeaconStateImpl() { + return new BeaconStateElectraImpl(this); + } + + @Override + public BeaconStateElectra createFromBackingNode(TreeNode node) { + return new BeaconStateElectraImpl(this, node); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/versions/electra/MutableBeaconStateElectra.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/versions/electra/MutableBeaconStateElectra.java new file mode 100644 index 00000000000..a54db894586 --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/versions/electra/MutableBeaconStateElectra.java @@ -0,0 +1,37 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.electra; + +import java.util.Optional; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.MutableBeaconState; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.capella.MutableBeaconStateCapella; + +public interface MutableBeaconStateElectra extends MutableBeaconStateCapella, BeaconStateElectra { + static MutableBeaconStateElectra required(final MutableBeaconState state) { + return state + .toMutableVersionElectra() + .orElseThrow( + () -> + new IllegalArgumentException( + "Expected a capella state but got: " + state.getClass().getSimpleName())); + } + + @Override + BeaconStateElectra commitChanges(); + + @Override + default Optional toMutableVersionElectra() { + return Optional.of(this); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/versions/electra/MutableBeaconStateElectraImpl.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/versions/electra/MutableBeaconStateElectraImpl.java new file mode 100644 index 00000000000..92d55786311 --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/versions/electra/MutableBeaconStateElectraImpl.java @@ -0,0 +1,62 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.electra; + +import com.google.common.base.MoreObjects; +import tech.pegasys.teku.infrastructure.ssz.SszData; +import tech.pegasys.teku.infrastructure.ssz.cache.IntCache; +import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconStateCache; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.common.AbstractMutableBeaconState; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.common.SlotCaches; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.common.TransitionCaches; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.altair.ValidatorStatsAltair; + +public class MutableBeaconStateElectraImpl + extends AbstractMutableBeaconState + implements MutableBeaconStateElectra, BeaconStateCache, ValidatorStatsAltair { + + MutableBeaconStateElectraImpl(BeaconStateElectraImpl backingImmutableView) { + super(backingImmutableView); + } + + MutableBeaconStateElectraImpl(BeaconStateElectraImpl backingImmutableView, boolean builder) { + super(backingImmutableView, builder); + } + + @Override + protected BeaconStateElectraImpl createImmutableBeaconState( + final TreeNode backingNode, + final IntCache viewCache, + final TransitionCaches transitionCaches, + final SlotCaches slotCaches) { + return new BeaconStateElectraImpl( + getSchema(), backingNode, viewCache, transitionCaches, slotCaches); + } + + @Override + protected void addCustomFields(final MoreObjects.ToStringHelper stringBuilder) { + BeaconStateElectra.describeCustomElectraFields(stringBuilder, this); + } + + @Override + public BeaconStateElectra commitChanges() { + return (BeaconStateElectra) super.commitChanges(); + } + + @Override + public MutableBeaconStateElectra createWritableCopy() { + return (MutableBeaconStateElectra) super.createWritableCopy(); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/executionlayer/ExecutionLayerChannelStub.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/executionlayer/ExecutionLayerChannelStub.java index 01521587c33..90159d89039 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/executionlayer/ExecutionLayerChannelStub.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/executionlayer/ExecutionLayerChannelStub.java @@ -65,6 +65,7 @@ import tech.pegasys.teku.spec.schemas.SchemaDefinitions; import tech.pegasys.teku.spec.schemas.SchemaDefinitionsBellatrix; import tech.pegasys.teku.spec.schemas.SchemaDefinitionsDeneb; +import tech.pegasys.teku.spec.schemas.SchemaDefinitionsElectra; public class ExecutionLayerChannelStub implements ExecutionLayerChannel { private static final Logger LOG = LogManager.getLogger(); @@ -263,6 +264,27 @@ public SafeFuture engineGetPayload( .baseFeePerGas(UInt256.ONE) .blockHash(Bytes32.random()) .transactions(transactions) + .executionWitness( + () -> { + final SchemaDefinitionsElectra schemaDefinitionsElectra = + SchemaDefinitionsElectra.required( + spec.atSlot(slot).getSchemaDefinitions()); + return schemaDefinitionsElectra + .getExecutionWitnessSchema() + .create( + List.of(), + schemaDefinitionsElectra + .getVerkleProofSchema() + .create( + List.of(), + Bytes.EMPTY, + List.of(), + Bytes32.ZERO, + schemaDefinitionsElectra + .getIpaProofSchema() + .create(List.of(), List.of(), Bytes32.ZERO)), + Bytes32.ZERO); + }) .withdrawals(() -> payloadAttributes.getWithdrawals().orElse(List.of())) .blobGasUsed(() -> UInt64.ZERO) .excessBlobGas(() -> UInt64.ZERO)); diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/deneb/block/BlockProcessorDeneb.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/deneb/block/BlockProcessorDeneb.java index 28d5c25de46..29f4f5c4b5b 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/deneb/block/BlockProcessorDeneb.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/deneb/block/BlockProcessorDeneb.java @@ -34,13 +34,13 @@ import tech.pegasys.teku.spec.logic.common.util.ValidatorsUtil; import tech.pegasys.teku.spec.logic.versions.altair.helpers.BeaconStateAccessorsAltair; import tech.pegasys.teku.spec.logic.versions.bellatrix.block.OptimisticExecutionPayloadExecutor; -import tech.pegasys.teku.spec.logic.versions.capella.block.BlockProcessorCapella; import tech.pegasys.teku.spec.logic.versions.deneb.helpers.MiscHelpersDeneb; import tech.pegasys.teku.spec.logic.versions.deneb.types.VersionedHash; -import tech.pegasys.teku.spec.schemas.SchemaDefinitionsCapella; +import tech.pegasys.teku.spec.logic.versions.electra.block.BlockProcessorElectra; import tech.pegasys.teku.spec.schemas.SchemaDefinitionsDeneb; +import tech.pegasys.teku.spec.schemas.SchemaDefinitionsElectra; -public class BlockProcessorDeneb extends BlockProcessorCapella { +public class BlockProcessorDeneb extends BlockProcessorElectra { public BlockProcessorDeneb( final SpecConfigDeneb specConfig, @@ -67,7 +67,7 @@ public BlockProcessorDeneb( attestationUtil, validatorsUtil, operationValidator, - SchemaDefinitionsCapella.required(schemaDefinitions)); + SchemaDefinitionsElectra.required(schemaDefinitions)); } @Override diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/deneb/forktransition/DenebStateUpgrade.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/deneb/forktransition/DenebStateUpgrade.java index c124ff15876..1a7f7772319 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/deneb/forktransition/DenebStateUpgrade.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/deneb/forktransition/DenebStateUpgrade.java @@ -16,12 +16,12 @@ import tech.pegasys.teku.infrastructure.unsigned.UInt64; import tech.pegasys.teku.spec.config.SpecConfigDeneb; import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadHeader; -import tech.pegasys.teku.spec.datastructures.execution.versions.capella.ExecutionPayloadHeaderCapella; +import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionPayloadHeaderElectra; import tech.pegasys.teku.spec.datastructures.state.Fork; import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconState; import tech.pegasys.teku.spec.datastructures.state.beaconstate.common.BeaconStateFields; -import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.capella.BeaconStateCapella; import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.deneb.BeaconStateDeneb; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.electra.BeaconStateElectra; import tech.pegasys.teku.spec.logic.common.forktransition.StateUpgrade; import tech.pegasys.teku.spec.logic.versions.altair.helpers.BeaconStateAccessorsAltair; import tech.pegasys.teku.spec.schemas.SchemaDefinitionsDeneb; @@ -44,7 +44,7 @@ public DenebStateUpgrade( @Override public BeaconStateDeneb upgrade(final BeaconState preState) { final UInt64 epoch = beaconStateAccessors.getCurrentEpoch(preState); - final BeaconStateCapella preStateCapella = BeaconStateCapella.required(preState); + final BeaconStateElectra preStateElectra = BeaconStateElectra.required(preState); return schemaDefinitions .getBeaconStateSchema() .createEmpty() @@ -52,11 +52,11 @@ public BeaconStateDeneb upgrade(final BeaconState preState) { state -> { BeaconStateFields.copyCommonFieldsFromSource(state, preState); - state.setCurrentEpochParticipation(preStateCapella.getCurrentEpochParticipation()); - state.setPreviousEpochParticipation(preStateCapella.getPreviousEpochParticipation()); - state.setCurrentSyncCommittee(preStateCapella.getCurrentSyncCommittee()); - state.setNextSyncCommittee(preStateCapella.getNextSyncCommittee()); - state.setInactivityScores(preStateCapella.getInactivityScores()); + state.setCurrentEpochParticipation(preStateElectra.getCurrentEpochParticipation()); + state.setPreviousEpochParticipation(preStateElectra.getPreviousEpochParticipation()); + state.setCurrentSyncCommittee(preStateElectra.getCurrentSyncCommittee()); + state.setNextSyncCommittee(preStateElectra.getNextSyncCommittee()); + state.setInactivityScores(preStateElectra.getInactivityScores()); state.setFork( new Fork( @@ -64,10 +64,10 @@ public BeaconStateDeneb upgrade(final BeaconState preState) { specConfig.getDenebForkVersion(), epoch)); - final ExecutionPayloadHeaderCapella capellaHeader = - preStateCapella + final ExecutionPayloadHeaderElectra electraHeader = + preStateElectra .getLatestExecutionPayloadHeader() - .toVersionCapella() + .toVersionElectra() .orElseThrow(); final ExecutionPayloadHeader upgradedExecutionPayloadHeader = schemaDefinitions @@ -75,30 +75,31 @@ public BeaconStateDeneb upgrade(final BeaconState preState) { .createExecutionPayloadHeader( builder -> builder - .parentHash(capellaHeader.getParentHash()) - .feeRecipient(capellaHeader.getFeeRecipient()) - .stateRoot(capellaHeader.getStateRoot()) - .receiptsRoot(capellaHeader.getReceiptsRoot()) - .logsBloom(capellaHeader.getLogsBloom()) - .prevRandao(capellaHeader.getPrevRandao()) - .blockNumber(capellaHeader.getBlockNumber()) - .gasLimit(capellaHeader.getGasLimit()) - .gasUsed(capellaHeader.getGasUsed()) - .timestamp(capellaHeader.getTimestamp()) - .extraData(capellaHeader.getExtraData()) - .baseFeePerGas(capellaHeader.getBaseFeePerGas()) - .blockHash(capellaHeader.getBlockHash()) - .transactionsRoot(capellaHeader.getTransactionsRoot()) - .withdrawalsRoot(capellaHeader::getWithdrawalsRoot) + .parentHash(electraHeader.getParentHash()) + .feeRecipient(electraHeader.getFeeRecipient()) + .stateRoot(electraHeader.getStateRoot()) + .receiptsRoot(electraHeader.getReceiptsRoot()) + .logsBloom(electraHeader.getLogsBloom()) + .prevRandao(electraHeader.getPrevRandao()) + .blockNumber(electraHeader.getBlockNumber()) + .gasLimit(electraHeader.getGasLimit()) + .gasUsed(electraHeader.getGasUsed()) + .timestamp(electraHeader.getTimestamp()) + .extraData(electraHeader.getExtraData()) + .baseFeePerGas(electraHeader.getBaseFeePerGas()) + .blockHash(electraHeader.getBlockHash()) + .transactionsRoot(electraHeader.getTransactionsRoot()) + .withdrawalsRoot(electraHeader::getWithdrawalsRoot) + .executionWitnessRoot(electraHeader::getExecutionWitnessRoot) .blobGasUsed(() -> UInt64.ZERO) .excessBlobGas(() -> UInt64.ZERO)); state.setLatestExecutionPayloadHeader(upgradedExecutionPayloadHeader); state.setNextWithdrawalValidatorIndex( - preStateCapella.getNextWithdrawalValidatorIndex()); - state.setNextWithdrawalIndex(preStateCapella.getNextWithdrawalIndex()); - state.setHistoricalSummaries(preStateCapella.getHistoricalSummaries()); + preStateElectra.getNextWithdrawalValidatorIndex()); + state.setNextWithdrawalIndex(preStateElectra.getNextWithdrawalIndex()); + state.setHistoricalSummaries(preStateElectra.getHistoricalSummaries()); }); } } diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/SpecLogicElectra.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/SpecLogicElectra.java new file mode 100644 index 00000000000..fefe432cc9d --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/SpecLogicElectra.java @@ -0,0 +1,208 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.logic.versions.electra; + +import java.util.Optional; +import tech.pegasys.teku.spec.config.SpecConfigElectra; +import tech.pegasys.teku.spec.logic.common.AbstractSpecLogic; +import tech.pegasys.teku.spec.logic.common.helpers.Predicates; +import tech.pegasys.teku.spec.logic.common.operations.OperationSignatureVerifier; +import tech.pegasys.teku.spec.logic.common.operations.validation.AttestationDataValidator; +import tech.pegasys.teku.spec.logic.common.operations.validation.OperationValidator; +import tech.pegasys.teku.spec.logic.common.util.AttestationUtil; +import tech.pegasys.teku.spec.logic.common.util.BeaconStateUtil; +import tech.pegasys.teku.spec.logic.common.util.BlindBlockUtil; +import tech.pegasys.teku.spec.logic.common.util.BlockProposalUtil; +import tech.pegasys.teku.spec.logic.common.util.ForkChoiceUtil; +import tech.pegasys.teku.spec.logic.common.util.LightClientUtil; +import tech.pegasys.teku.spec.logic.common.util.SyncCommitteeUtil; +import tech.pegasys.teku.spec.logic.common.util.ValidatorsUtil; +import tech.pegasys.teku.spec.logic.versions.altair.helpers.BeaconStateAccessorsAltair; +import tech.pegasys.teku.spec.logic.versions.altair.statetransition.epoch.ValidatorStatusFactoryAltair; +import tech.pegasys.teku.spec.logic.versions.altair.util.AttestationUtilAltair; +import tech.pegasys.teku.spec.logic.versions.bellatrix.helpers.BeaconStateMutatorsBellatrix; +import tech.pegasys.teku.spec.logic.versions.bellatrix.helpers.BellatrixTransitionHelpers; +import tech.pegasys.teku.spec.logic.versions.bellatrix.statetransition.epoch.EpochProcessorBellatrix; +import tech.pegasys.teku.spec.logic.versions.bellatrix.util.BlindBlockUtilBellatrix; +import tech.pegasys.teku.spec.logic.versions.capella.helpers.MiscHelpersCapella; +import tech.pegasys.teku.spec.logic.versions.capella.operations.validation.OperationValidatorCapella; +import tech.pegasys.teku.spec.logic.versions.capella.statetransition.epoch.EpochProcessorCapella; +import tech.pegasys.teku.spec.logic.versions.electra.block.BlockProcessorElectra; +import tech.pegasys.teku.spec.logic.versions.electra.forktransition.ElectraStateUpgrade; +import tech.pegasys.teku.spec.logic.versions.phase0.operations.validation.AttestationDataValidatorPhase0; +import tech.pegasys.teku.spec.schemas.SchemaDefinitionsElectra; + +public class SpecLogicElectra extends AbstractSpecLogic { + private final Optional syncCommitteeUtil; + private final Optional lightClientUtil; + private final BellatrixTransitionHelpers bellatrixTransitionHelpers; + + private SpecLogicElectra( + final Predicates predicates, + final MiscHelpersCapella miscHelpers, + final BeaconStateAccessorsAltair beaconStateAccessors, + final BeaconStateMutatorsBellatrix beaconStateMutators, + final OperationSignatureVerifier operationSignatureVerifier, + final ValidatorsUtil validatorsUtil, + final BeaconStateUtil beaconStateUtil, + final AttestationUtil attestationUtil, + final OperationValidator operationValidator, + final ValidatorStatusFactoryAltair validatorStatusFactory, + final EpochProcessorBellatrix epochProcessor, + final BlockProcessorElectra blockProcessor, + final ForkChoiceUtil forkChoiceUtil, + final BlockProposalUtil blockProposalUtil, + final BlindBlockUtil blindBlockUtil, + final SyncCommitteeUtil syncCommitteeUtil, + final LightClientUtil lightClientUtil, + final ElectraStateUpgrade stateUpgrade, + final BellatrixTransitionHelpers bellatrixTransitionHelpers) { + super( + predicates, + miscHelpers, + beaconStateAccessors, + beaconStateMutators, + operationSignatureVerifier, + validatorsUtil, + beaconStateUtil, + attestationUtil, + operationValidator, + validatorStatusFactory, + epochProcessor, + blockProcessor, + forkChoiceUtil, + blockProposalUtil, + Optional.of(blindBlockUtil), + Optional.of(stateUpgrade)); + this.syncCommitteeUtil = Optional.of(syncCommitteeUtil); + this.lightClientUtil = Optional.of(lightClientUtil); + this.bellatrixTransitionHelpers = bellatrixTransitionHelpers; + } + + public static SpecLogicElectra create( + final SpecConfigElectra config, final SchemaDefinitionsElectra schemaDefinitions) { + // Helpers + final Predicates predicates = new Predicates(config); + final MiscHelpersCapella miscHelpers = new MiscHelpersCapella(config); + final BeaconStateAccessorsAltair beaconStateAccessors = + new BeaconStateAccessorsAltair(config, predicates, miscHelpers); + final BeaconStateMutatorsBellatrix beaconStateMutators = + new BeaconStateMutatorsBellatrix(config, miscHelpers, beaconStateAccessors); + + // Operation validation + final OperationSignatureVerifier operationSignatureVerifier = + new OperationSignatureVerifier(miscHelpers, beaconStateAccessors); + + // Util + final ValidatorsUtil validatorsUtil = + new ValidatorsUtil(config, miscHelpers, beaconStateAccessors); + final BeaconStateUtil beaconStateUtil = + new BeaconStateUtil( + config, schemaDefinitions, predicates, miscHelpers, beaconStateAccessors); + final AttestationUtil attestationUtil = + new AttestationUtilAltair(config, schemaDefinitions, beaconStateAccessors, miscHelpers); + final AttestationDataValidator attestationDataValidator = + new AttestationDataValidatorPhase0(config, miscHelpers, beaconStateAccessors); + final OperationValidator operationValidator = + new OperationValidatorCapella( + config, predicates, beaconStateAccessors, attestationDataValidator, attestationUtil); + final ValidatorStatusFactoryAltair validatorStatusFactory = + new ValidatorStatusFactoryAltair( + config, + beaconStateUtil, + attestationUtil, + predicates, + miscHelpers, + beaconStateAccessors); + final EpochProcessorCapella epochProcessor = + new EpochProcessorCapella( + config, + miscHelpers, + beaconStateAccessors, + beaconStateMutators, + validatorsUtil, + beaconStateUtil, + validatorStatusFactory, + schemaDefinitions); + final SyncCommitteeUtil syncCommitteeUtil = + new SyncCommitteeUtil( + beaconStateAccessors, validatorsUtil, config, miscHelpers, schemaDefinitions); + final LightClientUtil lightClientUtil = + new LightClientUtil(beaconStateAccessors, syncCommitteeUtil, schemaDefinitions); + final BlockProcessorElectra blockProcessor = + new BlockProcessorElectra( + config, + predicates, + miscHelpers, + syncCommitteeUtil, + beaconStateAccessors, + beaconStateMutators, + operationSignatureVerifier, + beaconStateUtil, + attestationUtil, + validatorsUtil, + operationValidator, + schemaDefinitions); + final ForkChoiceUtil forkChoiceUtil = + new ForkChoiceUtil( + config, beaconStateAccessors, epochProcessor, attestationUtil, miscHelpers); + final BlockProposalUtil blockProposalUtil = + new BlockProposalUtil(schemaDefinitions, blockProcessor); + + final BlindBlockUtilBellatrix blindBlockUtil = new BlindBlockUtilBellatrix(schemaDefinitions); + + // State upgrade + final ElectraStateUpgrade stateUpgrade = + new ElectraStateUpgrade(config, schemaDefinitions, beaconStateAccessors); + + final BellatrixTransitionHelpers bellatrixTransitionHelpers = + new BellatrixTransitionHelpers(config, miscHelpers); + + return new SpecLogicElectra( + predicates, + miscHelpers, + beaconStateAccessors, + beaconStateMutators, + operationSignatureVerifier, + validatorsUtil, + beaconStateUtil, + attestationUtil, + operationValidator, + validatorStatusFactory, + epochProcessor, + blockProcessor, + forkChoiceUtil, + blockProposalUtil, + blindBlockUtil, + syncCommitteeUtil, + lightClientUtil, + stateUpgrade, + bellatrixTransitionHelpers); + } + + @Override + public Optional getSyncCommitteeUtil() { + return syncCommitteeUtil; + } + + @Override + public Optional getLightClientUtil() { + return lightClientUtil; + } + + @Override + public Optional getBellatrixTransitionHelpers() { + return Optional.of(bellatrixTransitionHelpers); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectra.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectra.java new file mode 100644 index 00000000000..c263099e2f3 --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectra.java @@ -0,0 +1,115 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.logic.versions.electra.block; + +import java.util.List; +import java.util.Optional; +import tech.pegasys.teku.infrastructure.bytes.Bytes31; +import tech.pegasys.teku.spec.config.SpecConfigElectra; +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.BeaconBlockBody; +import tech.pegasys.teku.spec.datastructures.execution.verkle.ExecutionWitness; +import tech.pegasys.teku.spec.datastructures.execution.verkle.StemStateDiff; +import tech.pegasys.teku.spec.datastructures.execution.verkle.SuffixStateDiff; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconState; +import tech.pegasys.teku.spec.logic.common.helpers.BeaconStateMutators; +import tech.pegasys.teku.spec.logic.common.helpers.Predicates; +import tech.pegasys.teku.spec.logic.common.operations.OperationSignatureVerifier; +import tech.pegasys.teku.spec.logic.common.operations.validation.OperationValidator; +import tech.pegasys.teku.spec.logic.common.statetransition.exceptions.BlockProcessingException; +import tech.pegasys.teku.spec.logic.common.util.AttestationUtil; +import tech.pegasys.teku.spec.logic.common.util.BeaconStateUtil; +import tech.pegasys.teku.spec.logic.common.util.SyncCommitteeUtil; +import tech.pegasys.teku.spec.logic.common.util.ValidatorsUtil; +import tech.pegasys.teku.spec.logic.versions.altair.helpers.BeaconStateAccessorsAltair; +import tech.pegasys.teku.spec.logic.versions.bellatrix.block.OptimisticExecutionPayloadExecutor; +import tech.pegasys.teku.spec.logic.versions.capella.block.BlockProcessorCapella; +import tech.pegasys.teku.spec.logic.versions.capella.helpers.MiscHelpersCapella; +import tech.pegasys.teku.spec.schemas.SchemaDefinitionsCapella; +import tech.pegasys.teku.spec.schemas.SchemaDefinitionsElectra; + +public class BlockProcessorElectra extends BlockProcessorCapella { + + public BlockProcessorElectra( + final SpecConfigElectra specConfig, + final Predicates predicates, + final MiscHelpersCapella miscHelpers, + final SyncCommitteeUtil syncCommitteeUtil, + final BeaconStateAccessorsAltair beaconStateAccessors, + final BeaconStateMutators beaconStateMutators, + final OperationSignatureVerifier operationSignatureVerifier, + final BeaconStateUtil beaconStateUtil, + final AttestationUtil attestationUtil, + final ValidatorsUtil validatorsUtil, + final OperationValidator operationValidator, + final SchemaDefinitionsElectra schemaDefinitions) { + super( + specConfig, + predicates, + miscHelpers, + syncCommitteeUtil, + beaconStateAccessors, + beaconStateMutators, + operationSignatureVerifier, + beaconStateUtil, + attestationUtil, + validatorsUtil, + operationValidator, + SchemaDefinitionsCapella.required(schemaDefinitions)); + } + + @Override + public void validateExecutionPayload( + final BeaconState genericState, + final BeaconBlockBody beaconBlockBody, + final Optional payloadExecutor) + throws BlockProcessingException { + final ExecutionWitness executionWitness = extractExecutionWitness(beaconBlockBody); + final List stemStateDiffs = executionWitness.getStateDiffs(); + Optional lastStem = Optional.empty(); + + for (final StemStateDiff stemStateDiff : stemStateDiffs) { + // only valid if list is sorted by stems + final Bytes31 currentStem = stemStateDiff.getStem(); + if (lastStem.isPresent()) { + if (currentStem.toUnsignedBigInteger().compareTo(lastStem.get().toUnsignedBigInteger()) + <= 0) { + throw new BlockProcessingException("StemStateDiffs are not sorted by stems"); + } + } + lastStem = Optional.of(currentStem); + + final List stateDiffs = stemStateDiff.getStateDiffs(); + Optional lastSuffix = Optional.empty(); + for (final SuffixStateDiff suffixStateDiff : stateDiffs) { + // only valid if list is sorted by suffixes + final int suffix = Byte.toUnsignedInt(suffixStateDiff.getSuffix()); + if (lastSuffix.isPresent()) { + if (suffix <= lastSuffix.get()) { + throw new BlockProcessingException("SuffixStateDiffs are not sorted by suffixes"); + } + } + lastSuffix = Optional.of(suffix); + } + } + + super.validateExecutionPayload(genericState, beaconBlockBody, payloadExecutor); + } + + public ExecutionWitness extractExecutionWitness(final BeaconBlockBody beaconBlockBody) + throws BlockProcessingException { + return beaconBlockBody + .getOptionalExecutionWitness() + .orElseThrow(() -> new BlockProcessingException("ExecutionWitness expected")); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/forktransition/ElectraStateUpgrade.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/forktransition/ElectraStateUpgrade.java new file mode 100644 index 00000000000..94f3a152f83 --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/forktransition/ElectraStateUpgrade.java @@ -0,0 +1,104 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.logic.versions.electra.forktransition; + +import org.apache.tuweni.bytes.Bytes32; +import tech.pegasys.teku.infrastructure.unsigned.UInt64; +import tech.pegasys.teku.spec.config.SpecConfigElectra; +import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadHeader; +import tech.pegasys.teku.spec.datastructures.execution.versions.capella.ExecutionPayloadHeaderCapella; +import tech.pegasys.teku.spec.datastructures.state.Fork; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconState; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.common.BeaconStateFields; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.capella.BeaconStateCapella; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.electra.BeaconStateElectra; +import tech.pegasys.teku.spec.logic.common.forktransition.StateUpgrade; +import tech.pegasys.teku.spec.logic.versions.altair.helpers.BeaconStateAccessorsAltair; +import tech.pegasys.teku.spec.schemas.SchemaDefinitionsElectra; + +public class ElectraStateUpgrade implements StateUpgrade { + + private final SpecConfigElectra specConfig; + private final SchemaDefinitionsElectra schemaDefinitions; + private final BeaconStateAccessorsAltair beaconStateAccessors; + + public ElectraStateUpgrade( + final SpecConfigElectra specConfig, + final SchemaDefinitionsElectra schemaDefinitions, + final BeaconStateAccessorsAltair beaconStateAccessors) { + this.specConfig = specConfig; + this.schemaDefinitions = schemaDefinitions; + this.beaconStateAccessors = beaconStateAccessors; + } + + @Override + public BeaconStateElectra upgrade(final BeaconState preState) { + final UInt64 epoch = beaconStateAccessors.getCurrentEpoch(preState); + BeaconStateCapella preStateCapella = BeaconStateCapella.required(preState); + return schemaDefinitions + .getBeaconStateSchema() + .createEmpty() + .updatedElectra( + state -> { + BeaconStateFields.copyCommonFieldsFromSource(state, preState); + + state.setCurrentEpochParticipation(preStateCapella.getCurrentEpochParticipation()); + state.setPreviousEpochParticipation(preStateCapella.getPreviousEpochParticipation()); + state.setCurrentSyncCommittee(preStateCapella.getCurrentSyncCommittee()); + state.setNextSyncCommittee(preStateCapella.getNextSyncCommittee()); + state.setInactivityScores(preStateCapella.getInactivityScores()); + + state.setFork( + new Fork( + preState.getFork().getCurrentVersion(), + specConfig.getElectraForkVersion(), + epoch)); + + final ExecutionPayloadHeaderCapella capellaHeader = + preStateCapella + .getLatestExecutionPayloadHeader() + .toVersionCapella() + .orElseThrow(); + final ExecutionPayloadHeader upgradedExecutionPayloadHeader = + schemaDefinitions + .getExecutionPayloadHeaderSchema() + .createExecutionPayloadHeader( + builder -> + builder + .parentHash(capellaHeader.getParentHash()) + .feeRecipient(capellaHeader.getFeeRecipient()) + .stateRoot(capellaHeader.getStateRoot()) + .receiptsRoot(capellaHeader.getReceiptsRoot()) + .logsBloom(capellaHeader.getLogsBloom()) + .prevRandao(capellaHeader.getPrevRandao()) + .blockNumber(capellaHeader.getBlockNumber()) + .gasLimit(capellaHeader.getGasLimit()) + .gasUsed(capellaHeader.getGasUsed()) + .timestamp(capellaHeader.getTimestamp()) + .extraData(capellaHeader.getExtraData()) + .baseFeePerGas(capellaHeader.getBaseFeePerGas()) + .blockHash(capellaHeader.getBlockHash()) + .transactionsRoot(capellaHeader.getTransactionsRoot()) + .withdrawalsRoot(capellaHeader::getWithdrawalsRoot) + .executionWitnessRoot(() -> Bytes32.ZERO)); + + state.setLatestExecutionPayloadHeader(upgradedExecutionPayloadHeader); + + state.setNextWithdrawalValidatorIndex( + preStateCapella.getNextWithdrawalValidatorIndex()); + state.setNextWithdrawalIndex(preStateCapella.getNextWithdrawalIndex()); + state.setHistoricalSummaries(preStateCapella.getHistoricalSummaries()); + }); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/schemas/SchemaDefinitions.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/schemas/SchemaDefinitions.java index 262d15c79f9..97cdaa52eba 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/schemas/SchemaDefinitions.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/schemas/SchemaDefinitions.java @@ -105,6 +105,11 @@ default Optional toVersionCapella() { return Optional.empty(); } + @NonSchema + default Optional toVersionElectra() { + return Optional.empty(); + } + @NonSchema default Optional toVersionDeneb() { return Optional.empty(); diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/schemas/SchemaDefinitionsDeneb.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/schemas/SchemaDefinitionsDeneb.java index c57a80031e0..fd4d9e4b571 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/schemas/SchemaDefinitionsDeneb.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/schemas/SchemaDefinitionsDeneb.java @@ -54,7 +54,7 @@ import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.deneb.BeaconStateSchemaDeneb; import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.deneb.MutableBeaconStateDeneb; -public class SchemaDefinitionsDeneb extends SchemaDefinitionsCapella { +public class SchemaDefinitionsDeneb extends SchemaDefinitionsElectra { private final BeaconStateSchemaDeneb beaconStateSchema; @@ -85,11 +85,12 @@ public class SchemaDefinitionsDeneb extends SchemaDefinitionsCapella { public SchemaDefinitionsDeneb(final SpecConfigDeneb specConfig) { super(specConfig); - this.executionPayloadSchemaDeneb = new ExecutionPayloadSchemaDeneb(specConfig); + this.executionPayloadSchemaDeneb = + new ExecutionPayloadSchemaDeneb(specConfig, getExecutionWitnessSchema()); final SignedBlsToExecutionChangeSchema signedBlsToExecutionChangeSchema = new SignedBlsToExecutionChangeSchema(); - this.beaconStateSchema = BeaconStateSchemaDeneb.create(specConfig); + this.beaconStateSchema = BeaconStateSchemaDeneb.create(specConfig, getExecutionWitnessSchema()); this.executionPayloadHeaderSchemaDeneb = beaconStateSchema.getLastExecutionPayloadHeaderSchema(); this.blobKzgCommitmentsSchema = new BlobKzgCommitmentsSchema(specConfig); @@ -99,6 +100,7 @@ public SchemaDefinitionsDeneb(final SpecConfigDeneb specConfig) { getAttesterSlashingSchema(), signedBlsToExecutionChangeSchema, blobKzgCommitmentsSchema, + getExecutionWitnessSchema(), "BeaconBlockBodyDeneb"); this.blindedBeaconBlockBodySchema = BlindedBeaconBlockBodySchemaDenebImpl.create( @@ -106,6 +108,7 @@ public SchemaDefinitionsDeneb(final SpecConfigDeneb specConfig) { getAttesterSlashingSchema(), signedBlsToExecutionChangeSchema, blobKzgCommitmentsSchema, + getExecutionWitnessSchema(), "BlindedBlockBodyDeneb"); this.beaconBlockSchema = new BeaconBlockSchema(beaconBlockBodySchema, "BeaconBlockDeneb"); this.blindedBeaconBlockSchema = diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/schemas/SchemaDefinitionsElectra.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/schemas/SchemaDefinitionsElectra.java new file mode 100644 index 00000000000..d65f0e9d8e2 --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/schemas/SchemaDefinitionsElectra.java @@ -0,0 +1,236 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.schemas; + +import static com.google.common.base.Preconditions.checkArgument; + +import java.util.Optional; +import tech.pegasys.teku.spec.config.SpecConfigElectra; +import tech.pegasys.teku.spec.datastructures.blocks.BeaconBlockSchema; +import tech.pegasys.teku.spec.datastructures.blocks.BlockContainer; +import tech.pegasys.teku.spec.datastructures.blocks.BlockContainerSchema; +import tech.pegasys.teku.spec.datastructures.blocks.SignedBeaconBlockSchema; +import tech.pegasys.teku.spec.datastructures.blocks.SignedBlockContainer; +import tech.pegasys.teku.spec.datastructures.blocks.SignedBlockContainerSchema; +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.BeaconBlockBodyBuilder; +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.BeaconBlockBodySchema; +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.electra.BeaconBlockBodyBuilderElectra; +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.electra.BeaconBlockBodySchemaElectraImpl; +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.electra.BlindedBeaconBlockBodySchemaElectraImpl; +import tech.pegasys.teku.spec.datastructures.builder.BuilderBidSchema; +import tech.pegasys.teku.spec.datastructures.builder.SignedBuilderBidSchema; +import tech.pegasys.teku.spec.datastructures.builder.versions.bellatrix.BuilderBidSchemaBellatrix; +import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadHeaderSchema; +import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadSchema; +import tech.pegasys.teku.spec.datastructures.execution.verkle.ExecutionWitnessSchema; +import tech.pegasys.teku.spec.datastructures.execution.verkle.IpaProofSchema; +import tech.pegasys.teku.spec.datastructures.execution.verkle.StemStateDiffSchema; +import tech.pegasys.teku.spec.datastructures.execution.verkle.SuffixStateDiffSchema; +import tech.pegasys.teku.spec.datastructures.execution.verkle.VerkleProofSchema; +import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionPayloadHeaderSchemaElectra; +import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionPayloadSchemaElectra; +import tech.pegasys.teku.spec.datastructures.operations.SignedBlsToExecutionChangeSchema; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconStateSchema; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.electra.BeaconStateElectra; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.electra.BeaconStateSchemaElectra; +import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.electra.MutableBeaconStateElectra; + +public class SchemaDefinitionsElectra extends SchemaDefinitionsCapella { + + private final BeaconStateSchemaElectra beaconStateSchema; + + private final ExecutionPayloadSchemaElectra executionPayloadSchemaElectra; + private final ExecutionPayloadHeaderSchemaElectra executionPayloadHeaderSchemaElectra; + + private final BeaconBlockBodySchemaElectraImpl beaconBlockBodySchema; + private final BlindedBeaconBlockBodySchemaElectraImpl blindedBeaconBlockBodySchema; + + private final BeaconBlockSchema beaconBlockSchema; + private final BeaconBlockSchema blindedBeaconBlockSchema; + private final SignedBeaconBlockSchema signedBeaconBlockSchema; + private final SignedBeaconBlockSchema signedBlindedBeaconBlockSchema; + private final SignedBlsToExecutionChangeSchema signedBlsToExecutionChangeSchema; + private final BuilderBidSchema builderBidSchemaElectra; + private final SignedBuilderBidSchema signedBuilderBidSchemaElectra; + + // Experimental implementation of Verkle Trees as of + // https://github.com/ethereum/consensus-specs/pull/3230 + private final SuffixStateDiffSchema suffixStateDiffSchema; + private final StemStateDiffSchema stemStateDiffSchema; + private final IpaProofSchema ipaProofSchema; + private final VerkleProofSchema verkleProofSchema; + private final ExecutionWitnessSchema executionWitnessSchema; + + public SchemaDefinitionsElectra(final SpecConfigElectra specConfig) { + super(specConfig); + + this.suffixStateDiffSchema = SuffixStateDiffSchema.INSTANCE; + this.stemStateDiffSchema = new StemStateDiffSchema(specConfig.getVerkleWidth()); + this.ipaProofSchema = new IpaProofSchema(specConfig.getIpaProofDepth()); + this.verkleProofSchema = + new VerkleProofSchema( + ipaProofSchema, specConfig.getMaxStems(), specConfig.getMaxCommitmentsPerStem()); + this.executionWitnessSchema = + new ExecutionWitnessSchema( + specConfig.getMaxStems(), stemStateDiffSchema, verkleProofSchema); + + this.executionPayloadSchemaElectra = + new ExecutionPayloadSchemaElectra(specConfig, executionWitnessSchema); + this.signedBlsToExecutionChangeSchema = new SignedBlsToExecutionChangeSchema(); + + this.beaconStateSchema = BeaconStateSchemaElectra.create(specConfig, executionWitnessSchema); + this.executionPayloadHeaderSchemaElectra = + beaconStateSchema.getLastExecutionPayloadHeaderSchema(); + this.beaconBlockBodySchema = + BeaconBlockBodySchemaElectraImpl.create( + specConfig, + getAttesterSlashingSchema(), + signedBlsToExecutionChangeSchema, + executionWitnessSchema, + "BeaconBlockBodyElectra"); + this.blindedBeaconBlockBodySchema = + BlindedBeaconBlockBodySchemaElectraImpl.create( + specConfig, + getAttesterSlashingSchema(), + signedBlsToExecutionChangeSchema, + executionWitnessSchema, + "BlindedBlockBodyElectra"); + this.beaconBlockSchema = new BeaconBlockSchema(beaconBlockBodySchema, "BeaconBlockElectra"); + this.blindedBeaconBlockSchema = + new BeaconBlockSchema(blindedBeaconBlockBodySchema, "BlindedBlockElectra"); + this.signedBeaconBlockSchema = + new SignedBeaconBlockSchema(beaconBlockSchema, "SignedBeaconBlockElectra"); + this.signedBlindedBeaconBlockSchema = + new SignedBeaconBlockSchema(blindedBeaconBlockSchema, "SignedBlindedBlockElectra"); + this.builderBidSchemaElectra = + new BuilderBidSchemaBellatrix("BuilderBidElectra", executionPayloadHeaderSchemaElectra); + this.signedBuilderBidSchemaElectra = + new SignedBuilderBidSchema("SignedBuilderBidElectra", builderBidSchemaElectra); + } + + public static SchemaDefinitionsElectra required(final SchemaDefinitions schemaDefinitions) { + checkArgument( + schemaDefinitions instanceof SchemaDefinitionsElectra, + "Expected definitions of type %s by got %s", + SchemaDefinitionsElectra.class, + schemaDefinitions.getClass()); + return (SchemaDefinitionsElectra) schemaDefinitions; + } + + @Override + public BeaconStateSchema + getBeaconStateSchema() { + return beaconStateSchema; + } + + @Override + public BeaconBlockBodySchema getBeaconBlockBodySchema() { + return beaconBlockBodySchema; + } + + @Override + public BeaconBlockBodySchema getBlindedBeaconBlockBodySchema() { + return blindedBeaconBlockBodySchema; + } + + @Override + public BeaconBlockSchema getBeaconBlockSchema() { + return beaconBlockSchema; + } + + @Override + public BeaconBlockSchema getBlindedBeaconBlockSchema() { + return blindedBeaconBlockSchema; + } + + @Override + public SignedBeaconBlockSchema getSignedBeaconBlockSchema() { + return signedBeaconBlockSchema; + } + + @Override + public SignedBeaconBlockSchema getSignedBlindedBeaconBlockSchema() { + return signedBlindedBeaconBlockSchema; + } + + @Override + public BlockContainerSchema getBlockContainerSchema() { + return getBeaconBlockSchema().castTypeToBlockContainer(); + } + + @Override + public BlockContainerSchema getBlindedBlockContainerSchema() { + return getBlindedBeaconBlockSchema().castTypeToBlockContainer(); + } + + @Override + public SignedBlockContainerSchema getSignedBlockContainerSchema() { + return getSignedBeaconBlockSchema().castTypeToSignedBlockContainer(); + } + + @Override + public SignedBlockContainerSchema getSignedBlindedBlockContainerSchema() { + return getSignedBlindedBeaconBlockSchema().castTypeToSignedBlockContainer(); + } + + @Override + public ExecutionPayloadSchema getExecutionPayloadSchema() { + return executionPayloadSchemaElectra; + } + + @Override + public ExecutionPayloadHeaderSchema getExecutionPayloadHeaderSchema() { + return executionPayloadHeaderSchemaElectra; + } + + @Override + public BeaconBlockBodyBuilder createBeaconBlockBodyBuilder() { + return new BeaconBlockBodyBuilderElectra(beaconBlockBodySchema, blindedBeaconBlockBodySchema); + } + + @Override + public BuilderBidSchema getBuilderBidSchema() { + return builderBidSchemaElectra; + } + + @Override + public SignedBuilderBidSchema getSignedBuilderBidSchema() { + return signedBuilderBidSchemaElectra; + } + + public SuffixStateDiffSchema getSuffixStateDiffSchema() { + return suffixStateDiffSchema; + } + + public StemStateDiffSchema getStemStateDiffSchema() { + return stemStateDiffSchema; + } + + public IpaProofSchema getIpaProofSchema() { + return ipaProofSchema; + } + + public VerkleProofSchema getVerkleProofSchema() { + return verkleProofSchema; + } + + public ExecutionWitnessSchema getExecutionWitnessSchema() { + return executionWitnessSchema; + } + + @Override + public Optional toVersionElectra() { + return Optional.of(this); + } +} diff --git a/ethereum/spec/src/main/resources/tech/pegasys/teku/spec/config/configs/mainnet.yaml b/ethereum/spec/src/main/resources/tech/pegasys/teku/spec/config/configs/mainnet.yaml index 1680d18af0d..095f219ae26 100644 --- a/ethereum/spec/src/main/resources/tech/pegasys/teku/spec/config/configs/mainnet.yaml +++ b/ethereum/spec/src/main/resources/tech/pegasys/teku/spec/config/configs/mainnet.yaml @@ -56,7 +56,9 @@ EIP6110_FORK_EPOCH: 18446744073709551615 # WHISK WHISK_FORK_VERSION: 0x06000000 # temporary stub WHISK_FORK_EPOCH: 18446744073709551615 - +# Electra +ELECTRA_FORK_VERSION: 0x07000000 # Verkle trees experimental +ELECTRA_FORK_EPOCH: 18446744073709551615 # Time parameters # --------------------------------------------------------------- diff --git a/ethereum/spec/src/main/resources/tech/pegasys/teku/spec/config/configs/minimal.yaml b/ethereum/spec/src/main/resources/tech/pegasys/teku/spec/config/configs/minimal.yaml index d7a965b87e5..37fdfc6fb5a 100644 --- a/ethereum/spec/src/main/resources/tech/pegasys/teku/spec/config/configs/minimal.yaml +++ b/ethereum/spec/src/main/resources/tech/pegasys/teku/spec/config/configs/minimal.yaml @@ -55,6 +55,9 @@ EIP6110_FORK_EPOCH: 18446744073709551615 # WHISK WHISK_FORK_VERSION: 0x06000001 WHISK_FORK_EPOCH: 18446744073709551615 +# Electra +ELECTRA_FORK_VERSION: 0x07000001 +ELECTRA_FORK_EPOCH: 18446744073709551615 # Time parameters diff --git a/ethereum/spec/src/main/resources/tech/pegasys/teku/spec/config/configs/swift.yaml b/ethereum/spec/src/main/resources/tech/pegasys/teku/spec/config/configs/swift.yaml index c6306fc7d67..9ef74807959 100644 --- a/ethereum/spec/src/main/resources/tech/pegasys/teku/spec/config/configs/swift.yaml +++ b/ethereum/spec/src/main/resources/tech/pegasys/teku/spec/config/configs/swift.yaml @@ -43,6 +43,9 @@ CAPELLA_FORK_EPOCH: 18446744073709551615 # Deneb DENEB_FORK_VERSION: 0x04000001 DENEB_FORK_EPOCH: 18446744073709551615 +# Electra +ELECTRA_FORK_VERSION: 0x07000001 +ELECTRA_FORK_EPOCH: 18446744073709551615 # Time parameters diff --git a/ethereum/spec/src/main/resources/tech/pegasys/teku/spec/config/presets/mainnet/electra.yaml b/ethereum/spec/src/main/resources/tech/pegasys/teku/spec/config/presets/mainnet/electra.yaml new file mode 100644 index 00000000000..d482ebcf82a --- /dev/null +++ b/ethereum/spec/src/main/resources/tech/pegasys/teku/spec/config/presets/mainnet/electra.yaml @@ -0,0 +1,10 @@ +# Experimental feature: `Verkle trees` as of https://github.com/ethereum/consensus-specs/pull/3230/ +# --------------------------------------------------------------- +# `uint64(2**16)` +MAX_STEMS: 65536 +# `uint64(33)` +MAX_COMMITMENTS_PER_STEM: 33 +# `uint64(256)` +VERKLE_WIDTH: 256 +# `uint64(8)` +IPA_PROOF_DEPTH: 8 \ No newline at end of file diff --git a/ethereum/spec/src/main/resources/tech/pegasys/teku/spec/config/presets/minimal/electra.yaml b/ethereum/spec/src/main/resources/tech/pegasys/teku/spec/config/presets/minimal/electra.yaml new file mode 100644 index 00000000000..d482ebcf82a --- /dev/null +++ b/ethereum/spec/src/main/resources/tech/pegasys/teku/spec/config/presets/minimal/electra.yaml @@ -0,0 +1,10 @@ +# Experimental feature: `Verkle trees` as of https://github.com/ethereum/consensus-specs/pull/3230/ +# --------------------------------------------------------------- +# `uint64(2**16)` +MAX_STEMS: 65536 +# `uint64(33)` +MAX_COMMITMENTS_PER_STEM: 33 +# `uint64(256)` +VERKLE_WIDTH: 256 +# `uint64(8)` +IPA_PROOF_DEPTH: 8 \ No newline at end of file diff --git a/ethereum/spec/src/main/resources/tech/pegasys/teku/spec/config/presets/swift/electra.yaml b/ethereum/spec/src/main/resources/tech/pegasys/teku/spec/config/presets/swift/electra.yaml new file mode 100644 index 00000000000..d482ebcf82a --- /dev/null +++ b/ethereum/spec/src/main/resources/tech/pegasys/teku/spec/config/presets/swift/electra.yaml @@ -0,0 +1,10 @@ +# Experimental feature: `Verkle trees` as of https://github.com/ethereum/consensus-specs/pull/3230/ +# --------------------------------------------------------------- +# `uint64(2**16)` +MAX_STEMS: 65536 +# `uint64(33)` +MAX_COMMITMENTS_PER_STEM: 33 +# `uint64(256)` +VERKLE_WIDTH: 256 +# `uint64(8)` +IPA_PROOF_DEPTH: 8 \ No newline at end of file diff --git a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/config/SpecConfigBuilderTest.java b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/config/SpecConfigBuilderTest.java index 36e854363c9..c5ba2b70b23 100644 --- a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/config/SpecConfigBuilderTest.java +++ b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/config/SpecConfigBuilderTest.java @@ -32,6 +32,7 @@ import tech.pegasys.teku.spec.config.builder.BellatrixBuilder; import tech.pegasys.teku.spec.config.builder.CapellaBuilder; import tech.pegasys.teku.spec.config.builder.DenebBuilder; +import tech.pegasys.teku.spec.config.builder.ElectraBuilder; import tech.pegasys.teku.spec.config.builder.SpecConfigBuilder; import tech.pegasys.teku.spec.util.DataStructureUtil; @@ -45,6 +46,7 @@ class SpecConfigBuilderTest { AltairBuilder.class, BellatrixBuilder.class, CapellaBuilder.class, + ElectraBuilder.class, DenebBuilder.class); /** diff --git a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/config/SpecConfigDenebTest.java b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/config/SpecConfigDenebTest.java index 6e73567060c..c9fbe404a8f 100644 --- a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/config/SpecConfigDenebTest.java +++ b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/config/SpecConfigDenebTest.java @@ -35,10 +35,10 @@ public void equals_mainnet() { @Test public void equals_sameRandomValues() { - SpecConfigCapella specConfigCapella = - SpecConfigLoader.loadConfig("mainnet").toVersionCapella().orElseThrow(); - SpecConfigDeneb configA = createRandomDenebConfig(specConfigCapella, 1); - SpecConfigDeneb configB = createRandomDenebConfig(specConfigCapella, 1); + SpecConfigElectra specConfigElectra = + SpecConfigLoader.loadConfig("mainnet").toVersionElectra().orElseThrow(); + SpecConfigDeneb configA = createRandomDenebConfig(specConfigElectra, 1); + SpecConfigDeneb configB = createRandomDenebConfig(specConfigElectra, 1); assertThat(configA).isEqualTo(configB); assertThat(configA.hashCode()).isEqualTo(configB.hashCode()); @@ -46,10 +46,10 @@ public void equals_sameRandomValues() { @Test public void equals_differentRandomValues() { - SpecConfigCapella specConfigCapella = - SpecConfigLoader.loadConfig("mainnet").toVersionCapella().orElseThrow(); - SpecConfigDeneb configA = createRandomDenebConfig(specConfigCapella, 1); - SpecConfigDeneb configB = createRandomDenebConfig(specConfigCapella, 2); + SpecConfigElectra specConfigElectra = + SpecConfigLoader.loadConfig("mainnet").toVersionElectra().orElseThrow(); + SpecConfigDeneb configA = createRandomDenebConfig(specConfigElectra, 1); + SpecConfigDeneb configB = createRandomDenebConfig(specConfigElectra, 2); assertThat(configA).isNotEqualTo(configB); assertThat(configA.hashCode()).isNotEqualTo(configB.hashCode()); @@ -57,32 +57,32 @@ public void equals_differentRandomValues() { @Test public void equals_capellaConfigDiffer() { - SpecConfigCapella capellaA = - SpecConfigLoader.loadConfig("mainnet").toVersionCapella().orElseThrow(); - SpecConfigCapella capellaB = + SpecConfigElectra electraA = + SpecConfigLoader.loadConfig("mainnet").toVersionElectra().orElseThrow(); + SpecConfigElectra electraB = SpecConfigLoader.loadConfig( "mainnet", b -> b.capellaBuilder( cb -> cb.maxWithdrawalsPerPayload( - capellaA.getMaxWithdrawalsPerPayload() + 4))) - .toVersionCapella() + electraA.getMaxWithdrawalsPerPayload() + 4))) + .toVersionElectra() .orElseThrow(); - SpecConfigDeneb configA = createRandomDenebConfig(capellaA, 1); - SpecConfigDeneb configB = createRandomDenebConfig(capellaB, 1); + SpecConfigDeneb configA = createRandomDenebConfig(electraA, 1); + SpecConfigDeneb configB = createRandomDenebConfig(electraB, 1); assertThat(configA).isNotEqualTo(configB); assertThat(configA.hashCode()).isNotEqualTo(configB.hashCode()); } private SpecConfigDeneb createRandomDenebConfig( - final SpecConfigCapella capellaConfig, final int seed) { + final SpecConfigElectra electraConfig, final int seed) { final DataStructureUtil dataStructureUtil = new DataStructureUtil(seed, spec); return new SpecConfigDenebImpl( - capellaConfig, + electraConfig, dataStructureUtil.randomBytes4(), dataStructureUtil.randomUInt64(), dataStructureUtil.randomPositiveInt(), diff --git a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/execution/verkle/ExecutionWitnessTest.java b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/execution/verkle/ExecutionWitnessTest.java new file mode 100644 index 00000000000..c2a8ba99e2f --- /dev/null +++ b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/execution/verkle/ExecutionWitnessTest.java @@ -0,0 +1,134 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.spec.datastructures.execution.verkle; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; +import java.util.Optional; +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; +import org.junit.jupiter.api.Test; +import tech.pegasys.teku.infrastructure.ssz.SszDataAssert; +import tech.pegasys.teku.spec.Spec; +import tech.pegasys.teku.spec.SpecMilestone; +import tech.pegasys.teku.spec.TestSpecFactory; +import tech.pegasys.teku.spec.config.SpecConfigElectra; +import tech.pegasys.teku.spec.util.DataStructureUtil; + +class ExecutionWitnessTest { + private final Spec spec = TestSpecFactory.createMinimalElectra(); + private final SpecConfigElectra specConfigElectra = + SpecConfigElectra.required(spec.forMilestone(SpecMilestone.ELECTRA).getConfig()); + private final SuffixStateDiffSchema suffixStateDiffSchema = SuffixStateDiffSchema.INSTANCE; + private final StemStateDiffSchema stemStateDiffSchema = + new StemStateDiffSchema(specConfigElectra.getVerkleWidth()); + private final IpaProofSchema ipaProofSchema = + new IpaProofSchema(specConfigElectra.getIpaProofDepth()); + private final VerkleProofSchema verkleProofSchema = + new VerkleProofSchema( + ipaProofSchema, + specConfigElectra.getMaxStems(), + specConfigElectra.getMaxCommitmentsPerStem()); + private final ExecutionWitnessSchema executionWitnessSchema = + new ExecutionWitnessSchema( + specConfigElectra.getMaxStems(), stemStateDiffSchema, verkleProofSchema); + private final DataStructureUtil dataStructureUtil = new DataStructureUtil(spec); + private final SuffixStateDiff suffixStateDiff1 = + suffixStateDiffSchema.create( + (byte) 13, Optional.of(dataStructureUtil.randomBytes32()), Optional.empty()); + private final SuffixStateDiff suffixStateDiff2 = + suffixStateDiffSchema.create( + (byte) 14, Optional.empty(), Optional.of(dataStructureUtil.randomBytes32())); + private final SuffixStateDiff suffixStateDiff3 = + suffixStateDiffSchema.create( + (byte) 15, + Optional.of(dataStructureUtil.randomBytes32()), + Optional.of(dataStructureUtil.randomBytes32())); + private final StemStateDiff stemStateDiff1 = + stemStateDiffSchema.create( + dataStructureUtil.randomBytes31(), + List.of(suffixStateDiff1, suffixStateDiff2, suffixStateDiff3)); + private final StemStateDiff stemStateDiff2 = + stemStateDiffSchema.create(dataStructureUtil.randomBytes31(), List.of(suffixStateDiff2)); + private final IpaProof ipaProof = + ipaProofSchema.create( + List.of( + dataStructureUtil.randomBytes32(), + dataStructureUtil.randomBytes32(), + dataStructureUtil.randomBytes32()), + List.of( + dataStructureUtil.randomBytes32(), + dataStructureUtil.randomBytes32(), + dataStructureUtil.randomBytes32()), + dataStructureUtil.randomBytes32()); + private final VerkleProof verkleProof = + verkleProofSchema.create( + List.of(dataStructureUtil.randomBytes31(), dataStructureUtil.randomBytes31()), + Bytes.fromHexString("0A45"), + List.of(dataStructureUtil.randomBytes32(), dataStructureUtil.randomBytes32()), + dataStructureUtil.randomBytes32(), + ipaProof); + private final Bytes32 parentStateRoot = dataStructureUtil.randomBytes32(); + + @Test + public void objectEquality() { + final ExecutionWitness executionWitness1 = + executionWitnessSchema.create( + List.of(stemStateDiff1, stemStateDiff2), verkleProof, parentStateRoot); + final ExecutionWitness executionWitness2 = + executionWitnessSchema.create( + List.of(stemStateDiff1, stemStateDiff2), verkleProof, parentStateRoot); + + assertThat(executionWitness1).isEqualTo(executionWitness2); + SszDataAssert.assertThatSszData(executionWitness1).isEqualByAllMeansTo(executionWitness2); + } + + @Test + public void objectNonEquality() { + final ExecutionWitness executionWitness1 = + executionWitnessSchema.create( + List.of(stemStateDiff1, stemStateDiff2), verkleProof, parentStateRoot); + final ExecutionWitness executionWitness2 = + executionWitnessSchema.create( + List.of(stemStateDiff2, stemStateDiff1), verkleProof, parentStateRoot); + + assertThat(executionWitness1).isNotEqualTo(executionWitness2); + } + + @Test + public void objectAccessorMethods() { + final ExecutionWitness executionWitness = + executionWitnessSchema.create( + List.of(stemStateDiff1, stemStateDiff2), verkleProof, parentStateRoot); + + assertThat(executionWitness.getStateDiffs()).isEqualTo(List.of(stemStateDiff1, stemStateDiff2)); + assertThat(executionWitness.getVerkleProof()).isEqualTo(verkleProof); + assertThat(executionWitness.getParentStateRoot()).isEqualTo(parentStateRoot); + } + + @Test + public void roundTripSSZ() { + final ExecutionWitness executionWitness = + executionWitnessSchema.create( + List.of(stemStateDiff1, stemStateDiff2), verkleProof, parentStateRoot); + + final Bytes executionWitnessBytes = executionWitness.sszSerialize(); + final ExecutionWitness deserializedObject = + executionWitnessSchema.sszDeserialize(executionWitnessBytes); + + assertThat(executionWitness).isEqualTo(deserializedObject); + SszDataAssert.assertThatSszData(executionWitness).isEqualByAllMeansTo(deserializedObject); + } +} diff --git a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/common/AbstractBeaconStateTest.java b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/common/AbstractBeaconStateTest.java index bc4a60e9c50..3b635e4fcd2 100644 --- a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/common/AbstractBeaconStateTest.java +++ b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/common/AbstractBeaconStateTest.java @@ -20,7 +20,6 @@ import org.junit.jupiter.api.extension.ExtendWith; import tech.pegasys.teku.infrastructure.unsigned.UInt64; import tech.pegasys.teku.spec.Spec; -import tech.pegasys.teku.spec.config.SpecConfig; import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconState; import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconStateSchema; import tech.pegasys.teku.spec.datastructures.state.beaconstate.MutableBeaconState; @@ -34,11 +33,11 @@ public abstract class AbstractBeaconStateTest< protected abstract Spec createSpec(); - private final SpecConfig genesisConfig = spec.getGenesisSpecConfig(); - private final BeaconStateSchema schema = getSchema(genesisConfig); - protected DataStructureUtil dataStructureUtil = new DataStructureUtil(spec); + @SuppressWarnings("unchecked") + private final BeaconStateSchema schema = + (BeaconStateSchema) spec.getGenesisSchemaDefinitions().getBeaconStateSchema(); - protected abstract BeaconStateSchema getSchema(final SpecConfig specConfig); + protected DataStructureUtil dataStructureUtil = new DataStructureUtil(spec); protected abstract T randomState(); diff --git a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/versions/altair/BeaconStateAltairTest.java b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/versions/altair/BeaconStateAltairTest.java index b41b409958f..41fe8a87d25 100644 --- a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/versions/altair/BeaconStateAltairTest.java +++ b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/versions/altair/BeaconStateAltairTest.java @@ -15,8 +15,6 @@ import tech.pegasys.teku.spec.Spec; import tech.pegasys.teku.spec.TestSpecFactory; -import tech.pegasys.teku.spec.config.SpecConfig; -import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconStateSchema; import tech.pegasys.teku.spec.datastructures.state.beaconstate.common.AbstractBeaconStateTest; public class BeaconStateAltairTest @@ -27,12 +25,6 @@ protected Spec createSpec() { return TestSpecFactory.createMinimalAltair(); } - @Override - protected BeaconStateSchema getSchema( - final SpecConfig specConfig) { - return BeaconStateSchemaAltair.create(specConfig); - } - @Override protected BeaconStateAltair randomState() { return dataStructureUtil.stateBuilderAltair().build(); diff --git a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/versions/capella/BeaconStateCapellaTest.java b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/versions/capella/BeaconStateCapellaTest.java index 6732d27e343..7368d6d10bf 100644 --- a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/versions/capella/BeaconStateCapellaTest.java +++ b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/versions/capella/BeaconStateCapellaTest.java @@ -15,8 +15,6 @@ import tech.pegasys.teku.spec.Spec; import tech.pegasys.teku.spec.TestSpecFactory; -import tech.pegasys.teku.spec.config.SpecConfig; -import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconStateSchema; import tech.pegasys.teku.spec.datastructures.state.beaconstate.common.AbstractBeaconStateTest; public class BeaconStateCapellaTest @@ -26,12 +24,6 @@ protected Spec createSpec() { return TestSpecFactory.createMinimalCapella(); } - @Override - protected BeaconStateSchema getSchema( - final SpecConfig specConfig) { - return BeaconStateSchemaCapella.create(specConfig); - } - @Override protected BeaconStateCapella randomState() { return dataStructureUtil.stateBuilderCapella().build(); diff --git a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/versions/phase0/BeaconStatePhase0Test.java b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/versions/phase0/BeaconStatePhase0Test.java index ed7436a957c..5d34305bf5b 100644 --- a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/versions/phase0/BeaconStatePhase0Test.java +++ b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/versions/phase0/BeaconStatePhase0Test.java @@ -15,8 +15,6 @@ import tech.pegasys.teku.spec.Spec; import tech.pegasys.teku.spec.TestSpecFactory; -import tech.pegasys.teku.spec.config.SpecConfig; -import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconStateSchema; import tech.pegasys.teku.spec.datastructures.state.beaconstate.common.AbstractBeaconStateTest; public class BeaconStatePhase0Test @@ -27,12 +25,6 @@ protected Spec createSpec() { return TestSpecFactory.createMinimalPhase0(); } - @Override - protected BeaconStateSchema getSchema( - final SpecConfig specConfig) { - return BeaconStateSchemaPhase0.create(specConfig); - } - @Override protected BeaconStatePhase0 randomState() { return dataStructureUtil.stateBuilderPhase0().build(); diff --git a/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/TestSpecFactory.java b/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/TestSpecFactory.java index ee93d220d95..0fe79030079 100644 --- a/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/TestSpecFactory.java +++ b/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/TestSpecFactory.java @@ -21,6 +21,7 @@ import tech.pegasys.teku.spec.config.SpecConfigBellatrix; import tech.pegasys.teku.spec.config.SpecConfigCapella; import tech.pegasys.teku.spec.config.SpecConfigDeneb; +import tech.pegasys.teku.spec.config.SpecConfigElectra; import tech.pegasys.teku.spec.config.SpecConfigLoader; import tech.pegasys.teku.spec.config.builder.SpecConfigBuilder; import tech.pegasys.teku.spec.networks.Eth2Network; @@ -43,6 +44,7 @@ public static Spec createMinimal(final SpecMilestone specMilestone) { case ALTAIR -> createMinimalAltair(); case BELLATRIX -> createMinimalBellatrix(); case CAPELLA -> createMinimalCapella(); + case ELECTRA -> createMinimalElectra(); case DENEB -> createMinimalDeneb(); }; } @@ -53,6 +55,7 @@ public static Spec createMainnet(final SpecMilestone specMilestone) { case ALTAIR -> createMainnetAltair(); case BELLATRIX -> createMainnetBellatrix(); case CAPELLA -> createMainnetCapella(); + case ELECTRA -> createMainnetElectra(); case DENEB -> createMainnetDeneb(); }; } @@ -90,6 +93,11 @@ public static Spec createMinimalCapella() { return create(specConfig, SpecMilestone.CAPELLA); } + public static Spec createMinimalElectra() { + final SpecConfigElectra specConfig = getElectraSpecConfig(Eth2Network.MINIMAL); + return create(specConfig, SpecMilestone.ELECTRA); + } + public static Spec createMinimalDeneb() { final SpecConfigDeneb specConfig = getDenebSpecConfig(Eth2Network.MINIMAL); return create(specConfig, SpecMilestone.DENEB); @@ -167,6 +175,11 @@ public static Spec createMainnetCapella() { return create(specConfig, SpecMilestone.CAPELLA); } + public static Spec createMainnetElectra() { + final SpecConfigElectra specConfig = getElectraSpecConfig(Eth2Network.MAINNET); + return create(specConfig, SpecMilestone.ELECTRA); + } + public static Spec createMainnetDeneb() { final SpecConfigBellatrix specConfig = getDenebSpecConfig(Eth2Network.MAINNET); return create(specConfig, SpecMilestone.DENEB); @@ -218,11 +231,18 @@ public static Spec create( .altairBuilder(a -> a.altairForkEpoch(UInt64.ZERO)) .bellatrixBuilder(b -> b.bellatrixForkEpoch(UInt64.ZERO)) .capellaBuilder(c -> c.capellaForkEpoch(UInt64.ZERO)); + case ELECTRA -> builder -> + builder + .altairBuilder(a -> a.altairForkEpoch(UInt64.ZERO)) + .bellatrixBuilder(b -> b.bellatrixForkEpoch(UInt64.ZERO)) + .capellaBuilder(c -> c.capellaForkEpoch(UInt64.ZERO)) + .electraBuilder(e -> e.electraForkEpoch(UInt64.ZERO)); case DENEB -> builder -> builder .altairBuilder(a -> a.altairForkEpoch(UInt64.ZERO)) .bellatrixBuilder(b -> b.bellatrixForkEpoch(UInt64.ZERO)) .capellaBuilder(c -> c.capellaForkEpoch(UInt64.ZERO)) + .electraBuilder(e -> e.electraForkEpoch(UInt64.ZERO)) .denebBuilder(d -> d.denebForkEpoch(UInt64.ZERO)); }; return create( @@ -303,6 +323,37 @@ private static SpecConfigCapella getCapellaSpecConfig( })); } + private static SpecConfigElectra getElectraSpecConfig(final Eth2Network network) { + return getElectraSpecConfig(network, UInt64.ZERO); + } + + private static SpecConfigElectra getElectraSpecConfig( + final Eth2Network network, final UInt64 electraForkEpoch) { + return getElectraSpecConfig( + network, + builder -> + builder + .altairBuilder(a -> a.altairForkEpoch(UInt64.ZERO)) + .bellatrixBuilder(b -> b.bellatrixForkEpoch(UInt64.ZERO)) + .capellaBuilder(c -> c.capellaForkEpoch(UInt64.ZERO)) + .electraBuilder(e -> e.electraForkEpoch(electraForkEpoch))); + } + + private static SpecConfigElectra getElectraSpecConfig( + final Eth2Network network, final Consumer configAdapter) { + return SpecConfigElectra.required( + SpecConfigLoader.loadConfig( + network.configName(), + builder -> { + builder + .altairBuilder(a -> a.altairForkEpoch(UInt64.ZERO)) + .bellatrixBuilder(b -> b.bellatrixForkEpoch(UInt64.ZERO)) + .capellaBuilder(c -> c.capellaForkEpoch(UInt64.ZERO)) + .electraBuilder(e -> e.electraForkEpoch(UInt64.ZERO)); + configAdapter.accept(builder); + })); + } + private static SpecConfigDeneb getDenebSpecConfig(final Eth2Network network) { return getDenebSpecConfig(network, UInt64.ZERO, UInt64.ZERO); } diff --git a/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/datastructures/interop/MergedGenesisTestBuilder.java b/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/datastructures/interop/MergedGenesisTestBuilder.java index 4067ce24f24..33296e8a3be 100644 --- a/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/datastructures/interop/MergedGenesisTestBuilder.java +++ b/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/datastructures/interop/MergedGenesisTestBuilder.java @@ -17,9 +17,11 @@ import org.hyperledger.besu.config.GenesisConfigFile; import org.hyperledger.besu.config.GenesisConfigOptions; import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.chain.BadBlockManager; import org.hyperledger.besu.ethereum.chain.GenesisState; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.mainnet.MainnetProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import tech.pegasys.teku.infrastructure.bytes.Bytes20; @@ -35,8 +37,10 @@ public static ExecutionPayloadHeader createPayloadForBesuGenesis( final GenesisConfigFile configFile = GenesisConfigFile.fromConfig(genesisConfigFile); final GenesisConfigOptions genesisConfigOptions = configFile.getConfigOptions(Collections.emptyMap()); + final BadBlockManager badBlockManager = new BadBlockManager(); final ProtocolSchedule protocolSchedule = - MainnetProtocolSchedule.fromConfig(genesisConfigOptions); + MainnetProtocolSchedule.fromConfig( + genesisConfigOptions, MiningParameters.MINING_DISABLED, badBlockManager); final GenesisState genesisState = GenesisState.fromConfig(configFile, protocolSchedule); final Block genesisBlock = genesisState.getBlock(); final BlockHeader header = genesisBlock.getHeader(); diff --git a/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/generator/BlockProposalTestUtil.java b/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/generator/BlockProposalTestUtil.java index 4b914df0f00..3143491c874 100644 --- a/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/generator/BlockProposalTestUtil.java +++ b/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/generator/BlockProposalTestUtil.java @@ -267,6 +267,7 @@ private ExecutionPayload createExecutionPayload( .blockHash(dataStructureUtil.randomBytes32()) .transactions(transactions.orElse(Collections.emptyList())) .withdrawals(List::of) + .executionWitness(dataStructureUtil::randomExecutionWitness) .blobGasUsed(() -> UInt64.ZERO) .excessBlobGas(() -> UInt64.ZERO)); } diff --git a/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/util/BeaconStateBuilderDeneb.java b/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/util/BeaconStateBuilderDeneb.java index 7623ad31580..b28d5b10f6c 100644 --- a/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/util/BeaconStateBuilderDeneb.java +++ b/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/util/BeaconStateBuilderDeneb.java @@ -27,6 +27,7 @@ import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.deneb.BeaconStateDeneb; import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.deneb.BeaconStateSchemaDeneb; import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.deneb.MutableBeaconStateDeneb; +import tech.pegasys.teku.spec.schemas.SchemaDefinitionsDeneb; public class BeaconStateBuilderDeneb extends AbstractBeaconStateBuilder< @@ -51,7 +52,11 @@ protected BeaconStateBuilderDeneb( @Override protected BeaconStateDeneb getEmptyState() { - return BeaconStateSchemaDeneb.create(spec.getConfig()).createEmpty(); + return BeaconStateSchemaDeneb.create( + spec.getConfig(), + SchemaDefinitionsDeneb.required(spec.getSchemaDefinitions()) + .getExecutionWitnessSchema()) + .createEmpty(); } @Override diff --git a/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/util/DataStructureUtil.java b/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/util/DataStructureUtil.java index 3cd12a04c3c..30877dc9fe7 100644 --- a/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/util/DataStructureUtil.java +++ b/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/util/DataStructureUtil.java @@ -50,6 +50,7 @@ import tech.pegasys.teku.ethereum.pow.api.MinGenesisTimeBlockEvent; import tech.pegasys.teku.infrastructure.async.SafeFuture; import tech.pegasys.teku.infrastructure.bytes.Bytes20; +import tech.pegasys.teku.infrastructure.bytes.Bytes31; import tech.pegasys.teku.infrastructure.bytes.Bytes4; import tech.pegasys.teku.infrastructure.bytes.Bytes8; import tech.pegasys.teku.infrastructure.ssz.SszData; @@ -120,6 +121,11 @@ import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadHeader; import tech.pegasys.teku.spec.datastructures.execution.Transaction; import tech.pegasys.teku.spec.datastructures.execution.TransactionSchema; +import tech.pegasys.teku.spec.datastructures.execution.verkle.ExecutionWitness; +import tech.pegasys.teku.spec.datastructures.execution.verkle.IpaProof; +import tech.pegasys.teku.spec.datastructures.execution.verkle.StemStateDiff; +import tech.pegasys.teku.spec.datastructures.execution.verkle.SuffixStateDiff; +import tech.pegasys.teku.spec.datastructures.execution.verkle.VerkleProof; import tech.pegasys.teku.spec.datastructures.execution.versions.capella.Withdrawal; import tech.pegasys.teku.spec.datastructures.forkchoice.VoteTracker; import tech.pegasys.teku.spec.datastructures.lightclient.LightClientBootstrap; @@ -184,6 +190,7 @@ import tech.pegasys.teku.spec.schemas.SchemaDefinitionsBellatrix; import tech.pegasys.teku.spec.schemas.SchemaDefinitionsCapella; import tech.pegasys.teku.spec.schemas.SchemaDefinitionsDeneb; +import tech.pegasys.teku.spec.schemas.SchemaDefinitionsElectra; public final class DataStructureUtil { @@ -257,6 +264,10 @@ public Bytes20 randomBytes20() { return new Bytes20(randomBytes32().slice(0, 20)); } + public Bytes31 randomBytes31() { + return new Bytes31(randomBytes32().slice(0, 31)); + } + public Bytes randomBytes256() { return randomBytes(256); } @@ -569,6 +580,7 @@ public ExecutionPayloadHeader randomExecutionPayloadHeader( .blockHash(randomBytes32()) .transactionsRoot(randomBytes32()) .withdrawalsRoot(() -> withdrawalsRoot) + .executionWitnessRoot(this::randomBytes32) .blobGasUsed(this::randomUInt64) .excessBlobGas(this::randomUInt64)); } @@ -679,12 +691,80 @@ public ExecutionPayload randomExecutionPayload( .blockHash(randomBytes32()) .transactions(randomExecutionPayloadTransactions()) .withdrawals(this::randomExecutionPayloadWithdrawals) + .executionWitness(this::randomExecutionWitness) .blobGasUsed(this::randomUInt64) .excessBlobGas(this::randomUInt64); postRandomModifications.accept(executionPayloadBuilder); }); } + public ExecutionWitness randomExecutionWitness() { + final SchemaDefinitionsElectra schemaDefinitionsElectra = + SchemaDefinitionsElectra.required( + spec.forMilestone(SpecMilestone.ELECTRA).getSchemaDefinitions()); + return schemaDefinitionsElectra + .getExecutionWitnessSchema() + .create( + List.of(randomStemStateDiff(5), randomStemStateDiff(2)), + randomVerkleProof(6, 6, 3, 4), + randomBytes32()); + } + + private VerkleProof randomVerkleProof( + final int otherStems, final int present, final int commitments, final int proofs) { + final IpaProof ipaProof = randomIpaProof(proofs); + final SchemaDefinitionsElectra schemaDefinitionsElectra = + SchemaDefinitionsElectra.required( + spec.forMilestone(SpecMilestone.ELECTRA).getSchemaDefinitions()); + return schemaDefinitionsElectra + .getVerkleProofSchema() + .create( + IntStream.range(0, otherStems).mapToObj(__ -> randomBytes31()).toList(), + randomBytes(present), + IntStream.range(0, commitments).mapToObj(__ -> randomBytes32()).toList(), + randomBytes32(), + ipaProof); + } + + private IpaProof randomIpaProof(final int proofs) { + final SchemaDefinitionsElectra schemaDefinitionsElectra = + SchemaDefinitionsElectra.required( + spec.forMilestone(SpecMilestone.ELECTRA).getSchemaDefinitions()); + return schemaDefinitionsElectra + .getIpaProofSchema() + .create( + IntStream.range(0, proofs).mapToObj(__ -> randomBytes32()).toList(), + IntStream.range(0, proofs).mapToObj(__ -> randomBytes32()).toList(), + randomBytes32()); + } + + private StemStateDiff randomStemStateDiff(final int elements) { + final SchemaDefinitionsElectra schemaDefinitionsElectra = + SchemaDefinitionsElectra.required( + spec.forMilestone(SpecMilestone.ELECTRA).getSchemaDefinitions()); + final List suffixStateDiffList = + IntStream.range(0, elements).mapToObj(__ -> randomSuffixStateDiff()).toList(); + return schemaDefinitionsElectra + .getStemStateDiffSchema() + .create(randomBytes31(), suffixStateDiffList); + } + + private SuffixStateDiff randomSuffixStateDiff() { + final SchemaDefinitionsElectra schemaDefinitionsElectra = + SchemaDefinitionsElectra.required( + spec.forMilestone(SpecMilestone.ELECTRA).getSchemaDefinitions()); + return schemaDefinitionsElectra + .getSuffixStateDiffSchema() + .create( + randomByte(), randomOptional(this::randomBytes32), randomOptional(this::randomBytes32)); + } + + private Optional randomOptional(final Supplier elementSupplier) { + return new Random(nextSeed()).nextBoolean() + ? Optional.of(elementSupplier.get()) + : Optional.empty(); + } + public Transaction randomExecutionPayloadTransaction() { final TransactionSchema schema = getBellatrixSchemaDefinitions(randomSlot()) @@ -1894,6 +1974,7 @@ public BeaconState randomBeaconState(final int validatorCount, final int numItem case ALTAIR -> stateBuilderAltair(validatorCount, numItemsInSszLists); case BELLATRIX -> stateBuilderBellatrix(validatorCount, numItemsInSszLists); case CAPELLA -> stateBuilderCapella(validatorCount, numItemsInSszLists); + case ELECTRA -> throw new RuntimeException("not implemented"); case DENEB -> stateBuilderDeneb(validatorCount, numItemsInSszLists); }; } diff --git a/fork-choice-tests/src/integration-test/java/tech/pegasys/teku/forkChoiceTests/ForkChoiceIntegrationTest.java b/fork-choice-tests/src/integration-test/java/tech/pegasys/teku/forkChoiceTests/ForkChoiceIntegrationTest.java index 59fa4472fad..a9d4582cf2d 100644 --- a/fork-choice-tests/src/integration-test/java/tech/pegasys/teku/forkChoiceTests/ForkChoiceIntegrationTest.java +++ b/fork-choice-tests/src/integration-test/java/tech/pegasys/teku/forkChoiceTests/ForkChoiceIntegrationTest.java @@ -151,9 +151,11 @@ private static ForkChoiceTestStep getStepKind(Map ss) { } private static T resolvePart( - Class clazz, SszSchema type, File testFile, Object value) { - if (value instanceof String) { - String path = (String) value; + final Class clazz, + final SszSchema type, + final File testFile, + final Object value) { + if (value instanceof String path) { if (path.endsWith(".yaml") || path.endsWith(".ssz")) { Path partPath = Paths.get(testFile.getParentFile().getParent(), "cache", path); try { @@ -218,9 +220,9 @@ void runForkChoiceTests( if (!processAttestation(forkChoice, (Attestation) step)) { attestationBuffer.add((Attestation) step); } - } else if (step instanceof Map) { + } else if (step instanceof Map rawChecks) { @SuppressWarnings("unchecked") - Map checks = (Map) step; + Map checks = (Map) rawChecks; for (Map.Entry e : checks.entrySet()) { String check = e.getKey(); switch (check) { diff --git a/fuzz/src/test/java/tech/pegasys/teku/fuzz/FuzzUtilTest.java b/fuzz/src/test/java/tech/pegasys/teku/fuzz/FuzzUtilTest.java index 800de9da4da..01538698e13 100644 --- a/fuzz/src/test/java/tech/pegasys/teku/fuzz/FuzzUtilTest.java +++ b/fuzz/src/test/java/tech/pegasys/teku/fuzz/FuzzUtilTest.java @@ -22,6 +22,7 @@ import java.util.Optional; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.junit.BouncyCastleExtension; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.xerial.snappy.Snappy; @@ -60,6 +61,8 @@ import tech.pegasys.teku.spec.schemas.SchemaDefinitionsCapella; @ExtendWith(BouncyCastleExtension.class) +// TODO Verkle trees +@Disabled("requires update of ssz fixtures") class FuzzUtilTest { private final Spec spec = TestSpecFactory.createMinimalCapella(); diff --git a/gradle/license-report-config/allowed-licenses.json b/gradle/license-report-config/allowed-licenses.json index 816a4ac9062..b582f112e64 100644 --- a/gradle/license-report-config/allowed-licenses.json +++ b/gradle/license-report-config/allowed-licenses.json @@ -24,6 +24,10 @@ "moduleLicense": "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.1", "moduleName": ".*" }, + { + "moduleLicense": "CDDL-1.0", + "moduleName": ".*" + }, { "moduleLicense": "Creative Commons Legal Code", "moduleName": ".*" @@ -224,6 +228,10 @@ { "moduleName": "com.google.guava:guava-parent", "moduleLicense": "Apache License, Version 2.0" + }, + { + "moduleName": "org.jupnp:org.jupnp", + "moduleLicense": "CDDL-1.0" } ] } diff --git a/gradle/versions.gradle b/gradle/versions.gradle index b73c9a69c18..f05464e50f2 100644 --- a/gradle/versions.gradle +++ b/gradle/versions.gradle @@ -1,11 +1,11 @@ dependencyManagement { dependencies { - dependency 'com.fasterxml.jackson.core:jackson-databind:2.16.1' - dependency 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.16.1' - dependency 'com.fasterxml.jackson.dataformat:jackson-dataformat-toml:2.16.1' - dependency 'com.fasterxml.jackson.module:jackson-module-kotlin:2.16.1' + dependency 'com.fasterxml.jackson.core:jackson-databind:2.17.2' + dependency 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.17.2' + dependency 'com.fasterxml.jackson.dataformat:jackson-dataformat-toml:2.17.2' + dependency 'com.fasterxml.jackson.module:jackson-module-kotlin:2.17.2' - dependencySet(group: 'com.google.errorprone', version: '2.24.1') { + dependencySet(group: 'com.google.errorprone', version: '2.28.0') { entry 'error_prone_annotation' entry 'error_prone_check_api' entry 'error_prone_core' @@ -14,9 +14,9 @@ dependencyManagement { dependency 'tech.pegasys.tools.epchecks:errorprone-checks:1.1.1' - dependency 'com.google.guava:guava:33.0.0-jre' + dependency 'com.google.guava:guava:33.1.0-jre' - dependency 'org.jsoup:jsoup:1.17.2' + dependency 'org.jsoup:jsoup:1.18.1' dependency 'com.launchdarkly:okhttp-eventsource:4.1.1' @@ -25,48 +25,52 @@ dependencyManagement { entry 'mockwebserver' } - dependency 'info.picocli:picocli:4.7.5' + dependency 'info.picocli:picocli:4.7.6' - dependency 'io.javalin:javalin:5.6.3' - dependency 'io.javalin:javalin-rendering:5.6.2' + dependencySet(group: 'io.javalin', version: '6.1.6') { + entry 'javalin' + entry 'javalin-rendering' + } - dependency 'io.libp2p:jvm-libp2p:1.1.0-RELEASE' - dependency 'tech.pegasys:jblst:0.3.11' - dependency 'tech.pegasys:jc-kzg-4844:0.8.0' + dependency 'io.libp2p:jvm-libp2p:1.1.1-RELEASE' + dependency 'tech.pegasys:jblst:0.3.12' + dependency 'tech.pegasys:jc-kzg-4844:1.0.0' - dependency 'org.hdrhistogram:HdrHistogram:2.1.12' + dependency 'org.hdrhistogram:HdrHistogram:2.2.2' - dependency 'org.jetbrains.kotlin:kotlin-stdlib:1.9.21' + dependency 'org.jetbrains.kotlin:kotlin-stdlib:2.0.0' dependency 'org.mock-server:mockserver-junit-jupiter:5.15.0' - dependencySet(group: 'io.swagger.core.v3', version: '2.2.20') { + dependencySet(group: 'io.swagger.core.v3', version: '2.2.22') { entry 'swagger-parser' entry 'swagger-core' entry 'swagger-models' entry 'swagger-annotations' } + // On update don't forget to change version in tech.pegasys.teku.infrastructure.restapi.SwaggerUIBuilder - dependency 'org.webjars:swagger-ui:5.10.3' + dependency 'org.webjars:swagger-ui:5.17.14' + dependency 'org.thymeleaf:thymeleaf:3.1.2.RELEASE' - dependency 'io.github.classgraph:classgraph:4.8.165' - dependencySet(group: 'com.github.oshi', version: '6.4.11') { + dependency 'io.github.classgraph:classgraph:4.8.174' + dependencySet(group: 'com.github.oshi', version: '6.6.1') { entry 'oshi-core' entry 'oshi-core-java11' } - dependencySet(group: 'io.netty', version: '4.1.100.Final') { + dependencySet(group: 'io.netty', version: '4.1.111.Final') { entry 'netty-handler' entry 'netty-codec-http' } - dependencySet(group: 'io.vertx', version: '4.5.2') { + dependencySet(group: 'io.vertx', version: '4.5.8') { entry 'vertx-codegen' entry 'vertx-core' entry 'vertx-unit' entry 'vertx-web' } - dependency 'io.projectreactor:reactor-core:3.6.2' + dependency 'io.projectreactor:reactor-core:3.6.8' dependency 'it.unimi.dsi:fastutil:8.5.12' @@ -80,12 +84,12 @@ dependencyManagement { entry 'tuweni-units' } - dependency 'org.apache.commons:commons-text:1.11.0' + dependency 'org.apache.commons:commons-text:1.12.0' dependency 'org.apache.commons:commons-lang3:3.14.0' - dependency 'commons-io:commons-io:2.15.1' + dependency 'commons-io:commons-io:2.16.1' dependency 'org.commonjava.mimeparse:mimeparse:0.1.3.3' - dependencySet(group: 'org.apache.logging.log4j', version: '2.22.0') { + dependencySet(group: 'org.apache.logging.log4j', version: '2.23.1') { entry 'log4j-api' entry 'log4j-core' entry 'log4j-slf4j-impl' @@ -94,22 +98,22 @@ dependencyManagement { dependency 'org.apiguardian:apiguardian-api:1.1.2' - dependency 'org.assertj:assertj-core:3.25.3' + dependency 'org.assertj:assertj-core:3.26.3' - dependency 'org.awaitility:awaitility:4.2.0' + dependency 'org.awaitility:awaitility:4.2.1' - dependencySet(group: 'org.bouncycastle', version: '1.77') { + dependencySet(group: 'org.bouncycastle', version: '1.78.1') { entry 'bcprov-jdk18on' entry 'bcpkix-jdk18on' } - dependencySet(group: 'org.junit.jupiter', version: '5.10.2') { + dependencySet(group: 'org.junit.jupiter', version: '5.10.3') { entry 'junit-jupiter-api' entry 'junit-jupiter-engine' entry 'junit-jupiter-params' } - dependencySet(group: 'org.mockito', version: '5.10.0') { + dependencySet(group: 'org.mockito', version: '5.12.0') { entry 'mockito-core' entry 'mockito-junit-jupiter' } @@ -124,7 +128,7 @@ dependencyManagement { dependency 'org.fusesource.leveldbjni:leveldbjni-win32:1.8' dependency 'tech.pegasys:leveldb-native:0.3.1' - dependencySet(group: "org.web3j", version: "4.10.3") { + dependencySet(group: "org.web3j", version: "4.12.0") { entry 'core' entry 'abi' entry 'crypto' @@ -133,43 +137,43 @@ dependencyManagement { dependency 'org.xerial.snappy:snappy-java:1.1.10.5' - dependency 'io.prometheus:simpleclient:0.9.0' + dependency 'io.prometheus:simpleclient:0.16.0' - dependencySet(group: 'org.hyperledger.besu.internal', version: '24.1.1') { + dependencySet(group: 'org.hyperledger.besu.internal', version: '24.7.0') { entry('metrics-core') entry('core') entry('config') } - dependencySet(group: 'org.hyperledger.besu', version: '24.1.1') { + dependencySet(group: 'org.hyperledger.besu', version: '24.7.0') { entry('besu-datatypes') entry('evm') entry('plugin-api') } - dependencySet(group: 'org.testcontainers', version: '1.19.4') { + dependencySet(group: 'org.testcontainers', version: '1.19.8') { entry "testcontainers" entry "junit-jupiter" } // discovery includes tuweni libraries under a different name so version resolution doesn't work // exclude them here and leave them to be included on the classpath by the version we use - dependency('tech.pegasys.discovery:discovery:22.12.0') { + dependency('tech.pegasys.discovery:discovery:24.6.0') { exclude 'org.apache.tuweni:bytes' exclude 'org.apache.tuweni:crypto' exclude 'org.apache.tuweni:units' } - dependencySet(group: 'org.jupnp', version: '2.7.1') { + dependencySet(group: 'org.jupnp', version: '3.0.2') { entry "org.jupnp" entry "org.jupnp.support" } - dependencySet(group: 'io.jsonwebtoken', version: '0.12.5') { + dependencySet(group: 'io.jsonwebtoken', version: '0.12.6') { entry 'jjwt-api' entry 'jjwt-impl' entry 'jjwt-jackson' } - dependency 'net.jqwik:jqwik:1.8.2' + dependency 'net.jqwik:jqwik:1.9.0' } } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 7f93135c49b..2c3521197d7 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 46671acb6e1..68e8816d71c 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=3e1af3ae886920c3ac87f7a91f816c0c7c436f276a6eefdb3da152100fef72ae -distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip +distributionSha256Sum=d725d707bfabd4dfdc958c624003b3c80accc03f7037b5122c4b1d0ef15cecab +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 1aa94a42690..f5feea6d6b1 100755 --- a/gradlew +++ b/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -84,7 +86,8 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum diff --git a/gradlew.bat b/gradlew.bat index 6689b85beec..9b42019c791 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @@ -43,11 +45,11 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -57,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail diff --git a/infrastructure/bytes/src/main/java/tech/pegasys/teku/infrastructure/bytes/Bytes31.java b/infrastructure/bytes/src/main/java/tech/pegasys/teku/infrastructure/bytes/Bytes31.java new file mode 100644 index 00000000000..b25ee58ab91 --- /dev/null +++ b/infrastructure/bytes/src/main/java/tech/pegasys/teku/infrastructure/bytes/Bytes31.java @@ -0,0 +1,117 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.infrastructure.bytes; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.math.BigInteger; +import java.util.Objects; +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.MutableBytes; + +public class Bytes31 { + public static final int SIZE = 31; + public static final Bytes31 ZERO = new Bytes31(Bytes.wrap(new byte[SIZE])); + + private final Bytes bytes; + + public Bytes31(Bytes bytes) { + checkArgument( + bytes.size() == SIZE, "Bytes31 should be 31 bytes, but was %s bytes.", bytes.size()); + this.bytes = bytes; + } + + public static Bytes31 fromHexString(String value) { + return new Bytes31(Bytes.fromHexString(value)); + } + + public String toHexString() { + return bytes.toHexString(); + } + + /** + * Left pad a {@link Bytes} value with zero bytes to create a {@link Bytes31}. + * + * @param value The bytes value pad. + * @return A {@link Bytes31} that exposes the left-padded bytes of {@code value}. + * @throws IllegalArgumentException if {@code value.size() > 31}. + */ + public static Bytes31 leftPad(Bytes value) { + checkNotNull(value); + if (value instanceof Bytes31) { + return (Bytes31) value; + } + checkArgument(value.size() <= SIZE, "Expected at most %s bytes but got %s", SIZE, value.size()); + MutableBytes result = MutableBytes.create(SIZE); + value.copyTo(result, SIZE - value.size()); + return new Bytes31(result); + } + + /** + * Right pad a {@link Bytes} value with zero bytes to create a {@link Bytes31}. + * + * @param value The bytes value pad. + * @return A {@link Bytes31} that exposes the right-padded bytes of {@code value}. + * @throws IllegalArgumentException if {@code value.size() > 31}. + */ + public static Bytes31 rightPad(Bytes value) { + checkNotNull(value); + if (value instanceof Bytes31) { + return (Bytes31) value; + } + checkArgument(value.size() <= SIZE, "Expected at most %s bytes but got %s", SIZE, value.size()); + MutableBytes result = MutableBytes.create(SIZE); + value.copyTo(result, 0); + return new Bytes31(result); + } + + public Bytes getWrappedBytes() { + return bytes; + } + + public Bytes31 copy() { + return new Bytes31(bytes.copy()); + } + + public BigInteger toUnsignedBigInteger() { + return bytes.toUnsignedBigInteger(); + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final Bytes31 bytes31 = (Bytes31) o; + return bytes.equals(bytes31.bytes); + } + + @Override + public int hashCode() { + return Objects.hash(bytes); + } + + public String toUnprefixedHexString() { + return bytes.toUnprefixedHexString(); + } + + @Override + public String toString() { + return bytes.toString(); + } +} diff --git a/infrastructure/restapi/src/main/java/tech/pegasys/teku/infrastructure/restapi/AuthorizationManager.java b/infrastructure/restapi/src/main/java/tech/pegasys/teku/infrastructure/restapi/AuthorizationHandler.java similarity index 89% rename from infrastructure/restapi/src/main/java/tech/pegasys/teku/infrastructure/restapi/AuthorizationManager.java rename to infrastructure/restapi/src/main/java/tech/pegasys/teku/infrastructure/restapi/AuthorizationHandler.java index 1b44803315f..9e97fe338ee 100644 --- a/infrastructure/restapi/src/main/java/tech/pegasys/teku/infrastructure/restapi/AuthorizationManager.java +++ b/infrastructure/restapi/src/main/java/tech/pegasys/teku/infrastructure/restapi/AuthorizationHandler.java @@ -17,26 +17,23 @@ import io.javalin.http.Context; import io.javalin.http.Handler; -import io.javalin.security.AccessManager; -import io.javalin.security.RouteRole; import java.io.File; import java.io.IOException; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import java.util.Set; import java.util.stream.Stream; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import tech.pegasys.teku.infrastructure.exceptions.InvalidConfigurationException; -public class AuthorizationManager implements AccessManager { +public class AuthorizationHandler implements Handler { private static final Logger LOG = LogManager.getLogger(); private static final String BEARER_PREFIX = "Bearer "; private final String bearer; - public AuthorizationManager(final Path path) { + public AuthorizationHandler(final Path path) { bearer = readPasswordFile(path); } @@ -88,13 +85,12 @@ private void unauthorized(final Context ctx, final String message) { LOG.debug(message); ctx.json("{\n \"status\": 401, \n \"message\":\"Unauthorized\"\n}"); ctx.status(SC_UNAUTHORIZED); + ctx.skipRemainingHandlers(); } @Override - public void manage(final Handler handler, final Context ctx, final Set set) - throws Exception { - if (ctx.matchedPath().equals("/swagger-docs")) { - handler.handle(ctx); + public void handle(final Context ctx) throws Exception { + if (ctx.path().startsWith("/swagger-") || ctx.path().startsWith("/webjars")) { return; } @@ -108,11 +104,9 @@ public void manage(final Handler handler, final Context ctx, final Set doStart() { // throwing it here will terminate the process effectively. LOG.error("Failed to start Rest API", e); throw e; - } else if (app.jettyServer() == null || !app.jettyServer().started) { + } else if (app.jettyServer() == null || !app.jettyServer().started()) { // failing to create the jetty server or start the jetty server is fatal. throw new IllegalStateException("Rest API failed to start", e); } else { @@ -95,7 +95,7 @@ private void checkAccessFile(final Path path) { throw new IllegalStateException("Failed to initialise access file for validator-api."); } } - app.updateConfig(config -> config.accessManager(new AuthorizationManager(path))); + app.beforeMatched(new AuthorizationHandler(path)); } @Override diff --git a/infrastructure/restapi/src/main/java/tech/pegasys/teku/infrastructure/restapi/RestApiBuilder.java b/infrastructure/restapi/src/main/java/tech/pegasys/teku/infrastructure/restapi/RestApiBuilder.java index edd959d336f..86dce1ea507 100644 --- a/infrastructure/restapi/src/main/java/tech/pegasys/teku/infrastructure/restapi/RestApiBuilder.java +++ b/infrastructure/restapi/src/main/java/tech/pegasys/teku/infrastructure/restapi/RestApiBuilder.java @@ -20,6 +20,7 @@ import static tech.pegasys.teku.infrastructure.json.types.CoreTypes.HTTP_ERROR_RESPONSE_TYPE; import io.javalin.Javalin; +import io.javalin.compression.CompressionStrategy; import io.javalin.config.JavalinConfig; import io.javalin.plugin.bundled.CorsPluginConfig; import io.javalin.util.JavalinLogger; @@ -131,14 +132,16 @@ public RestApi build() { config -> { config.http.defaultContentType = "application/json"; config.showJavalinBanner = false; - config.compression.gzipOnly(); + config.startupWatcherEnabled = false; // Work around a bug in Javalin where it decides whether to compress on each call to // write which could result in a mix of compressed and uncompressed content // and means it doesn't evaluate the length of the response correctly. - config.pvt.compressionStrategy.setMinSizeForCompression(0); + CompressionStrategy strategy = CompressionStrategy.GZIP; + strategy.setDefaultMinSizeForCompression(0); + config.http.customCompression(strategy); configureCors(config); swaggerBuilder.configureUI(config); - config.jetty.server(this::createJettyServer); + config.jetty.modifyServer(this::modifyJettyServer); }); if (!hostAllowlist.isEmpty()) { @@ -182,16 +185,15 @@ private void addExceptionHandler( private void configureCors(final JavalinConfig config) { if (!corsAllowedOrigins.isEmpty()) { if (corsAllowedOrigins.contains("*")) { - config.plugins.enableCors(cors -> cors.add(CorsPluginConfig::anyHost)); + config.bundledPlugins.enableCors(cors -> cors.addRule(CorsPluginConfig.CorsRule::anyHost)); } else { - config.plugins.enableCors( - cors -> corsAllowedOrigins.forEach(origin -> cors.add(it -> it.allowHost(origin)))); + config.bundledPlugins.enableCors( + cors -> corsAllowedOrigins.forEach(origin -> cors.addRule(it -> it.allowHost(origin)))); } } } - private Server createJettyServer() { - final Server server = new Server(); + private void modifyJettyServer(final Server server) { final ServerConnector connector; if (maybeKeystorePath.isPresent()) { connector = new ServerConnector(server, getSslContextFactory()); @@ -201,7 +203,6 @@ private Server createJettyServer() { connector.setPort(port); connector.setHost(listenAddress); server.setConnectors(new Connector[] {connector}); - maxUrlLength.ifPresent( maxLength -> { LOG.debug("Setting Max URL length to {}", maxLength); @@ -215,7 +216,6 @@ private Server createJettyServer() { } }); JavalinLogger.startupInfo = false; - return server; } private SslContextFactory.Server getSslContextFactory() { diff --git a/infrastructure/restapi/src/main/java/tech/pegasys/teku/infrastructure/restapi/SwaggerUIBuilder.java b/infrastructure/restapi/src/main/java/tech/pegasys/teku/infrastructure/restapi/SwaggerUIBuilder.java index 12d9dfcda1b..a1194120dc6 100644 --- a/infrastructure/restapi/src/main/java/tech/pegasys/teku/infrastructure/restapi/SwaggerUIBuilder.java +++ b/infrastructure/restapi/src/main/java/tech/pegasys/teku/infrastructure/restapi/SwaggerUIBuilder.java @@ -17,15 +17,20 @@ import io.javalin.config.JavalinConfig; import io.javalin.http.Handler; import io.javalin.http.staticfiles.Location; +import io.javalin.rendering.template.JavalinThymeleaf; import java.util.HashMap; import java.util.Map; import java.util.Optional; import java.util.Set; +import org.thymeleaf.TemplateEngine; +import org.thymeleaf.templatemode.TemplateMode; +import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver; +import org.thymeleaf.templateresolver.ITemplateResolver; import tech.pegasys.teku.infrastructure.restapi.openapi.OpenApiDocBuilder; public class SwaggerUIBuilder { // Version here MUST match `swagger-ui` library version - private static final String SWAGGER_UI_VERSION = "5.10.3"; + private static final String SWAGGER_UI_VERSION = "5.17.14"; private static final String SWAGGER_UI_PATH = "/swagger-ui"; private static final String SWAGGER_HOSTED_PATH = "/webjars/swagger-ui/" + SWAGGER_UI_VERSION; @@ -41,7 +46,7 @@ public class SwaggerUIBuilder { private static final Handler INDEX = (ctx) -> { - Map model = new HashMap<>(); + final Map model = new HashMap<>(); model.put("title", "Teku REST API"); model.put("basePath", SWAGGER_HOSTED_PATH); ctx.render("index.html", model); @@ -71,7 +76,8 @@ public void configureUI(final JavalinConfig config) { SWAGGER_HOSTED_PATH + SWAGGER_INITIALIZER_JS, SWAGGER_UI_PATCHED + SWAGGER_INITIALIZER_JS, Location.CLASSPATH); - ThymeleafConfigurator.enableThymeleafTemplates(SWAGGER_UI_PATCHED + "/"); + config.fileRenderer(createThymeleafRenderer(SWAGGER_UI_PATCHED + "/")); + config.spaRoot.addHandler(SWAGGER_UI_PATH, INDEX); } @@ -84,4 +90,20 @@ public Optional configureDocs( app.get(SWAGGER_DOCS_PATH, ctx -> ctx.json(apiDocs)); return Optional.of(apiDocs); } + + private JavalinThymeleaf createThymeleafRenderer(final String templatePath) { + final TemplateEngine templateEngine = new TemplateEngine(); + templateEngine.addTemplateResolver(templateResolver(templatePath)); + return new JavalinThymeleaf(templateEngine); + } + + private ITemplateResolver templateResolver(final String prefix) { + final ClassLoaderTemplateResolver templateResolver = + new ClassLoaderTemplateResolver(Thread.currentThread().getContextClassLoader()); + templateResolver.setTemplateMode(TemplateMode.HTML); + templateResolver.setPrefix(prefix); + templateResolver.setSuffix(".html"); + templateResolver.setCharacterEncoding("UTF-8"); + return templateResolver; + } } diff --git a/infrastructure/restapi/src/main/java/tech/pegasys/teku/infrastructure/restapi/ThymeleafConfigurator.java b/infrastructure/restapi/src/main/java/tech/pegasys/teku/infrastructure/restapi/ThymeleafConfigurator.java deleted file mode 100644 index 69bfdcd3b32..00000000000 --- a/infrastructure/restapi/src/main/java/tech/pegasys/teku/infrastructure/restapi/ThymeleafConfigurator.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright Consensys Software Inc., 2022 - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ - -package tech.pegasys.teku.infrastructure.restapi; - -import io.javalin.rendering.template.JavalinThymeleaf; -import java.util.concurrent.atomic.AtomicBoolean; -import org.thymeleaf.TemplateEngine; -import org.thymeleaf.templatemode.TemplateMode; -import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver; -import org.thymeleaf.templateresolver.ITemplateResolver; - -/** - * ThymeLeaf templates configuration for Javalin. Note that Javalin renderers are configured using a - * singleton so only the first call to this class will have any effect. - */ -class ThymeleafConfigurator { - private static final AtomicBoolean REGISTERED = new AtomicBoolean(false); - - public static void enableThymeleafTemplates(final String templatePath) { - if (!REGISTERED.compareAndSet(false, true)) { - return; - } - TemplateEngine templateEngine = new TemplateEngine(); - templateEngine.addTemplateResolver(templateResolver(TemplateMode.HTML, templatePath, ".html")); - JavalinThymeleaf.init(templateEngine); - } - - private static ITemplateResolver templateResolver( - final TemplateMode templateMode, final String prefix, final String suffix) { - ClassLoaderTemplateResolver templateResolver = - new ClassLoaderTemplateResolver(Thread.currentThread().getContextClassLoader()); - templateResolver.setTemplateMode(templateMode); - templateResolver.setPrefix(prefix); - templateResolver.setSuffix(suffix); - templateResolver.setCharacterEncoding("UTF-8"); - return templateResolver; - } -} diff --git a/infrastructure/restapi/src/main/java/tech/pegasys/teku/infrastructure/restapi/endpoints/JavalinEndpointAdapter.java b/infrastructure/restapi/src/main/java/tech/pegasys/teku/infrastructure/restapi/endpoints/JavalinEndpointAdapter.java index 0930044888a..473feabb276 100644 --- a/infrastructure/restapi/src/main/java/tech/pegasys/teku/infrastructure/restapi/endpoints/JavalinEndpointAdapter.java +++ b/infrastructure/restapi/src/main/java/tech/pegasys/teku/infrastructure/restapi/endpoints/JavalinEndpointAdapter.java @@ -27,7 +27,8 @@ private JavalinEndpointAdapter(final RestApiEndpoint endpoint) { public static void addEndpoint(final Javalin app, final RestApiEndpoint endpoint) { final EndpointMetadata metadata = endpoint.getMetadata(); - app.addHandler(metadata.getMethod(), metadata.getPath(), new JavalinEndpointAdapter(endpoint)); + app.addHttpHandler( + metadata.getMethod(), metadata.getPath(), new JavalinEndpointAdapter(endpoint)); } @Override diff --git a/infrastructure/restapi/src/main/java/tech/pegasys/teku/infrastructure/restapi/endpoints/JavalinRestApiRequest.java b/infrastructure/restapi/src/main/java/tech/pegasys/teku/infrastructure/restapi/endpoints/JavalinRestApiRequest.java index f0dd8f2b197..37b566e9bc7 100644 --- a/infrastructure/restapi/src/main/java/tech/pegasys/teku/infrastructure/restapi/endpoints/JavalinRestApiRequest.java +++ b/infrastructure/restapi/src/main/java/tech/pegasys/teku/infrastructure/restapi/endpoints/JavalinRestApiRequest.java @@ -77,6 +77,10 @@ public Optional getOptionalRequestBody() throws JsonProcessingException { public JavalinRestApiRequest(final Context context, final EndpointMetadata metadata) { this.context = context; this.metadata = metadata; + // Work around a bug in Javalin where it decides whether to compress on each call to + // write which could result in a mix of compressed and uncompressed content + // and means it doesn't evaluate the length of the response correctly. + this.context.minSizeForCompression(0); this.pathParamMap = context.pathParamMap(); this.queryParamMap = context.queryParamMap(); this.headerMap = context.headerMap(); diff --git a/infrastructure/restapi/src/test/java/tech/pegasys/teku/infrastructure/restapi/AuthorizationManagerTest.java b/infrastructure/restapi/src/test/java/tech/pegasys/teku/infrastructure/restapi/AuthorizationHandlerTest.java similarity index 69% rename from infrastructure/restapi/src/test/java/tech/pegasys/teku/infrastructure/restapi/AuthorizationManagerTest.java rename to infrastructure/restapi/src/test/java/tech/pegasys/teku/infrastructure/restapi/AuthorizationHandlerTest.java index 4942f5f0fe2..fa2fc63eccc 100644 --- a/infrastructure/restapi/src/test/java/tech/pegasys/teku/infrastructure/restapi/AuthorizationManagerTest.java +++ b/infrastructure/restapi/src/test/java/tech/pegasys/teku/infrastructure/restapi/AuthorizationHandlerTest.java @@ -16,47 +16,49 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static tech.pegasys.teku.infrastructure.http.HttpStatusCodes.SC_UNAUTHORIZED; import io.javalin.http.Context; -import io.javalin.http.Handler; import io.javalin.http.HandlerType; -import io.javalin.security.RouteRole; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.util.Set; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; import tech.pegasys.teku.infrastructure.exceptions.InvalidConfigurationException; -public class AuthorizationManagerTest { +public class AuthorizationHandlerTest { private static final String PASS = "secure"; - private final Handler handler = mock(Handler.class); private final Context context = mock(Context.class); - private final Set roles = Set.of(); @Test void shouldNotRequireAuthorizationForSwagger(@TempDir final Path tempDir) throws Exception { setupPasswordFile(tempDir); when(context.method()).thenReturn(HandlerType.GET); - when(context.matchedPath()).thenReturn("/swagger-docs"); - AuthorizationManager manager = new AuthorizationManager(tempDir.resolve("passwd")); - manager.manage(handler, context, roles); - verify(handler, times(1)).handle(context); + when(context.path()).thenReturn("/swagger-docs"); + final AuthorizationHandler handler = new AuthorizationHandler(tempDir.resolve("passwd")); + handler.handle(context); + } + + @Test + void shouldNotRequireAuthorizationForWebjars(@TempDir final Path tempDir) throws Exception { + setupPasswordFile(tempDir); + when(context.method()).thenReturn(HandlerType.GET); + when(context.path()).thenReturn("/webjars"); + final AuthorizationHandler handler = new AuthorizationHandler(tempDir.resolve("passwd")); + handler.handle(context); } @Test void shouldGrantAccessIfHeaderSet(@TempDir final Path tempDir) throws Exception { setupPasswordFile(tempDir); when(context.method()).thenReturn(HandlerType.DELETE); - when(context.matchedPath()).thenReturn("/aPath"); + when(context.path()).thenReturn("/aPath"); when(context.header("Authorization")).thenReturn("Bearer " + PASS); - AuthorizationManager manager = new AuthorizationManager(tempDir.resolve("passwd")); - manager.manage(handler, context, roles); - verify(handler, times(1)).handle(context); + final AuthorizationHandler handler = new AuthorizationHandler(tempDir.resolve("passwd")); + handler.handle(context); } @Test @@ -64,57 +66,50 @@ void shouldGrantAccessIfHeaderSetEncoded(@TempDir final Path tempDir) throws Exc // url encode will rewrite the ' ' to a '+' Files.writeString(tempDir.resolve("passwd"), PASS + " " + PASS); when(context.method()).thenReturn(HandlerType.POST); - when(context.matchedPath()).thenReturn("/aPath"); + when(context.path()).thenReturn("/aPath"); when(context.header("Authorization")).thenReturn("Bearer " + PASS + "+" + PASS); - AuthorizationManager manager = new AuthorizationManager(tempDir.resolve("passwd")); - manager.manage(handler, context, roles); - verify(handler, times(1)).handle(context); + final AuthorizationHandler handler = new AuthorizationHandler(tempDir.resolve("passwd")); + handler.handle(context); } @Test void shouldDenyAccessIfHeaderNotSet(@TempDir final Path tempDir) throws Exception { setupPasswordFile(tempDir); when(context.method()).thenReturn(HandlerType.POST); - when(context.matchedPath()).thenReturn("/aPath"); + when(context.path()).thenReturn("/aPath"); when(context.header("Authorization")).thenReturn(null); - AuthorizationManager manager = new AuthorizationManager(tempDir.resolve("passwd")); - manager.manage(handler, context, roles); - verify(handler, times(0)).handle(context); - verify(context).status(401); - verify(context).json(any()); + final AuthorizationHandler handler = new AuthorizationHandler(tempDir.resolve("passwd")); + handler.handle(context); + verifyUnauthorizedResponse(); } @Test void shouldDenyAccessIfHeaderIsNotBearer(@TempDir final Path tempDir) throws Exception { setupPasswordFile(tempDir); when(context.method()).thenReturn(HandlerType.GET); - when(context.matchedPath()).thenReturn("/aPath"); + when(context.path()).thenReturn("/aPath"); when(context.header("Authorization")).thenReturn(PASS); - AuthorizationManager manager = new AuthorizationManager(tempDir.resolve("passwd")); - manager.manage(handler, context, roles); - verify(handler, times(0)).handle(context); - verify(context).status(401); - verify(context).json(any()); + final AuthorizationHandler handler = new AuthorizationHandler(tempDir.resolve("passwd")); + handler.handle(context); + verifyUnauthorizedResponse(); } @Test void shouldDenyAccessIfBearerIsIncorrect(@TempDir final Path tempDir) throws Exception { setupPasswordFile(tempDir); when(context.method()).thenReturn(HandlerType.GET); - when(context.matchedPath()).thenReturn("/aPath"); + when(context.path()).thenReturn("/aPath"); when(context.header("Authorization")).thenReturn("Bearer no"); - AuthorizationManager manager = new AuthorizationManager(tempDir.resolve("passwd")); - manager.manage(handler, context, roles); - verify(handler, times(0)).handle(context); - verify(context).status(401); - verify(context).json(any()); + final AuthorizationHandler handler = new AuthorizationHandler(tempDir.resolve("passwd")); + handler.handle(context); + verifyUnauthorizedResponse(); } @Test public void createAuthorizationManagerShouldFailWhenPasswordFileDoesNotExist() { final Path directory = Path.of("/foo/bar"); - assertThatThrownBy(() -> new AuthorizationManager(directory)) + assertThatThrownBy(() -> new AuthorizationHandler(directory)) .isInstanceOf(InvalidConfigurationException.class) .hasMessageContaining( "password file %s does not exist", directory.toFile().getAbsolutePath()); @@ -128,10 +123,10 @@ public void createAuthorizationManagerShouldFailWhenCannotReadPasswordFile( if (!unreadableFilePath.toFile().setReadable(false)) { // If the underlying OS does not support setting file permissions we ignore the check on the // error message - assertThatThrownBy(() -> new AuthorizationManager(unreadableFilePath)) + assertThatThrownBy(() -> new AuthorizationHandler(unreadableFilePath)) .isInstanceOf(InvalidConfigurationException.class); } else { - assertThatThrownBy(() -> new AuthorizationManager(unreadableFilePath)) + assertThatThrownBy(() -> new AuthorizationHandler(unreadableFilePath)) .isInstanceOf(InvalidConfigurationException.class) .hasMessageContaining( "cannot read password file %s", unreadableFilePath.toFile().getAbsolutePath()); @@ -143,7 +138,7 @@ public void createAuthorizationManagerShouldFailWhenPasswordFileIsADirectory( @TempDir final Path tempDir) throws IOException { final Path directory = Files.createDirectories(tempDir); - assertThatThrownBy(() -> new AuthorizationManager(directory)) + assertThatThrownBy(() -> new AuthorizationHandler(directory)) .isInstanceOf(InvalidConfigurationException.class) .hasMessageContaining( "password file %s is a directory", directory.toFile().getAbsolutePath()); @@ -154,11 +149,17 @@ public void createAuthorizationManagerShouldFailWhenPasswordFileIsEmpty( @TempDir final Path tempDir) throws IOException { final Path directory = Files.writeString(tempDir.resolve("passwd"), ""); - assertThatThrownBy(() -> new AuthorizationManager(directory)) + assertThatThrownBy(() -> new AuthorizationHandler(directory)) .isInstanceOf(InvalidConfigurationException.class) .hasMessageContaining("password file %s is empty", directory.toFile().getAbsolutePath()); } + private void verifyUnauthorizedResponse() { + verify(context).status(SC_UNAUTHORIZED); + verify(context).json(any()); + verify(context).skipRemainingHandlers(); + } + private void setupPasswordFile(final Path tempDir) throws IOException { Files.writeString(tempDir.resolve("passwd"), PASS); } diff --git a/infrastructure/restapi/src/test/java/tech/pegasys/teku/infrastructure/restapi/SwaggerWebjarIntegrityTest.java b/infrastructure/restapi/src/test/java/tech/pegasys/teku/infrastructure/restapi/SwaggerWebjarIntegrityTest.java index 4f1d247ac69..5616a649592 100644 --- a/infrastructure/restapi/src/test/java/tech/pegasys/teku/infrastructure/restapi/SwaggerWebjarIntegrityTest.java +++ b/infrastructure/restapi/src/test/java/tech/pegasys/teku/infrastructure/restapi/SwaggerWebjarIntegrityTest.java @@ -41,7 +41,7 @@ class SwaggerWebjarIntegrityTest { * *

NOTICE: If it doesn't match due to swagger version update, both * `infrastructure/restapi/src/main/resources/swagger-ui/vendor` (just jar files copy) and - * `infrastructure/restapi/src/main/resources/swagger-ui/patched` (uptodate vendor files with + * `infrastructure/restapi/src/main/resources/swagger-ui/patched` (up-to-date vendor files with * changed links similar to the current modifications) should be updated */ @Test diff --git a/infrastructure/ssz/generator/build.gradle b/infrastructure/ssz/generator/build.gradle index 6da7c3c2901..5cf5f4435d3 100644 --- a/infrastructure/ssz/generator/build.gradle +++ b/infrastructure/ssz/generator/build.gradle @@ -9,7 +9,7 @@ dependencies { task generateContainers(type: JavaExec) { dependsOn compileJava - mainClass = 'tech.pegasys.teku.ssz.backing.ContainersGenerator' + mainClass = 'tech.pegasys.teku.infrastructure.ssz.ContainersGenerator' args project.sourceSets.main.java.srcDirs.join(" "), project.parent.sourceSets.main.java.srcDirs.join(" ") classpath sourceSets.main.runtimeClasspath diff --git a/infrastructure/ssz/generator/src/main/java/tech/pegasys/teku/infrastructure/ssz/ContainersGenerator.java b/infrastructure/ssz/generator/src/main/java/tech/pegasys/teku/infrastructure/ssz/ContainersGenerator.java index 861c98fe4d7..a6e33e67cb9 100644 --- a/infrastructure/ssz/generator/src/main/java/tech/pegasys/teku/infrastructure/ssz/ContainersGenerator.java +++ b/infrastructure/ssz/generator/src/main/java/tech/pegasys/teku/infrastructure/ssz/ContainersGenerator.java @@ -23,7 +23,7 @@ public class ContainersGenerator { - private final int maxFields = 17; + private final int maxFields = 18; private final Path templateSrcPath; private final Path targetSrcPath; private final String typePackagePath = "tech/pegasys/teku/infrastructure/ssz/containers/"; diff --git a/infrastructure/ssz/src/main/java/tech/pegasys/teku/infrastructure/ssz/containers/Container18.java b/infrastructure/ssz/src/main/java/tech/pegasys/teku/infrastructure/ssz/containers/Container18.java new file mode 100644 index 00000000000..2b14f2f70da --- /dev/null +++ b/infrastructure/ssz/src/main/java/tech/pegasys/teku/infrastructure/ssz/containers/Container18.java @@ -0,0 +1,176 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.infrastructure.ssz.containers; + +import tech.pegasys.teku.infrastructure.ssz.SszData; +import tech.pegasys.teku.infrastructure.ssz.impl.AbstractSszImmutableContainer; +import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode; + +/** Autogenerated by tech.pegasys.teku.ssz.backing.ContainersGenerator */ +public class Container18< + C extends + Container18< + C, + V0, + V1, + V2, + V3, + V4, + V5, + V6, + V7, + V8, + V9, + V10, + V11, + V12, + V13, + V14, + V15, + V16, + V17>, + V0 extends SszData, + V1 extends SszData, + V2 extends SszData, + V3 extends SszData, + V4 extends SszData, + V5 extends SszData, + V6 extends SszData, + V7 extends SszData, + V8 extends SszData, + V9 extends SszData, + V10 extends SszData, + V11 extends SszData, + V12 extends SszData, + V13 extends SszData, + V14 extends SszData, + V15 extends SszData, + V16 extends SszData, + V17 extends SszData> + extends AbstractSszImmutableContainer { + + protected Container18( + ContainerSchema18< + C, V0, V1, V2, V3, V4, V5, V6, V7, V8, V9, V10, V11, V12, V13, V14, V15, V16, V17> + schema) { + super(schema); + } + + protected Container18( + ContainerSchema18< + C, V0, V1, V2, V3, V4, V5, V6, V7, V8, V9, V10, V11, V12, V13, V14, V15, V16, V17> + schema, + TreeNode backingNode) { + super(schema, backingNode); + } + + protected Container18( + ContainerSchema18< + C, V0, V1, V2, V3, V4, V5, V6, V7, V8, V9, V10, V11, V12, V13, V14, V15, V16, V17> + schema, + V0 arg0, + V1 arg1, + V2 arg2, + V3 arg3, + V4 arg4, + V5 arg5, + V6 arg6, + V7 arg7, + V8 arg8, + V9 arg9, + V10 arg10, + V11 arg11, + V12 arg12, + V13 arg13, + V14 arg14, + V15 arg15, + V16 arg16, + V17 arg17) { + super( + schema, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, + arg13, arg14, arg15, arg16, arg17); + } + + protected V0 getField0() { + return getAny(0); + } + + protected V1 getField1() { + return getAny(1); + } + + protected V2 getField2() { + return getAny(2); + } + + protected V3 getField3() { + return getAny(3); + } + + protected V4 getField4() { + return getAny(4); + } + + protected V5 getField5() { + return getAny(5); + } + + protected V6 getField6() { + return getAny(6); + } + + protected V7 getField7() { + return getAny(7); + } + + protected V8 getField8() { + return getAny(8); + } + + protected V9 getField9() { + return getAny(9); + } + + protected V10 getField10() { + return getAny(10); + } + + protected V11 getField11() { + return getAny(11); + } + + protected V12 getField12() { + return getAny(12); + } + + protected V13 getField13() { + return getAny(13); + } + + protected V14 getField14() { + return getAny(14); + } + + protected V15 getField15() { + return getAny(15); + } + + protected V16 getField16() { + return getAny(16); + } + + protected V17 getField17() { + return getAny(17); + } +} diff --git a/infrastructure/ssz/src/main/java/tech/pegasys/teku/infrastructure/ssz/containers/ContainerSchema18.java b/infrastructure/ssz/src/main/java/tech/pegasys/teku/infrastructure/ssz/containers/ContainerSchema18.java new file mode 100644 index 00000000000..3349f9f37c9 --- /dev/null +++ b/infrastructure/ssz/src/main/java/tech/pegasys/teku/infrastructure/ssz/containers/ContainerSchema18.java @@ -0,0 +1,313 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.infrastructure.ssz.containers; + +import java.util.List; +import java.util.function.BiFunction; +import tech.pegasys.teku.infrastructure.ssz.SszContainer; +import tech.pegasys.teku.infrastructure.ssz.SszData; +import tech.pegasys.teku.infrastructure.ssz.schema.SszSchema; +import tech.pegasys.teku.infrastructure.ssz.schema.impl.AbstractSszContainerSchema; +import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode; + +/** Autogenerated by tech.pegasys.teku.ssz.backing.ContainersGenerator */ +public abstract class ContainerSchema18< + C extends SszContainer, + V0 extends SszData, + V1 extends SszData, + V2 extends SszData, + V3 extends SszData, + V4 extends SszData, + V5 extends SszData, + V6 extends SszData, + V7 extends SszData, + V8 extends SszData, + V9 extends SszData, + V10 extends SszData, + V11 extends SszData, + V12 extends SszData, + V13 extends SszData, + V14 extends SszData, + V15 extends SszData, + V16 extends SszData, + V17 extends SszData> + extends AbstractSszContainerSchema { + + public static < + C extends SszContainer, + V0 extends SszData, + V1 extends SszData, + V2 extends SszData, + V3 extends SszData, + V4 extends SszData, + V5 extends SszData, + V6 extends SszData, + V7 extends SszData, + V8 extends SszData, + V9 extends SszData, + V10 extends SszData, + V11 extends SszData, + V12 extends SszData, + V13 extends SszData, + V14 extends SszData, + V15 extends SszData, + V16 extends SszData, + V17 extends SszData> + ContainerSchema18< + C, V0, V1, V2, V3, V4, V5, V6, V7, V8, V9, V10, V11, V12, V13, V14, V15, V16, V17> + create( + SszSchema fieldSchema0, + SszSchema fieldSchema1, + SszSchema fieldSchema2, + SszSchema fieldSchema3, + SszSchema fieldSchema4, + SszSchema fieldSchema5, + SszSchema fieldSchema6, + SszSchema fieldSchema7, + SszSchema fieldSchema8, + SszSchema fieldSchema9, + SszSchema fieldSchema10, + SszSchema fieldSchema11, + SszSchema fieldSchema12, + SszSchema fieldSchema13, + SszSchema fieldSchema14, + SszSchema fieldSchema15, + SszSchema fieldSchema16, + SszSchema fieldSchema17, + BiFunction< + ContainerSchema18< + C, + V0, + V1, + V2, + V3, + V4, + V5, + V6, + V7, + V8, + V9, + V10, + V11, + V12, + V13, + V14, + V15, + V16, + V17>, + TreeNode, + C> + instanceCtor) { + return new ContainerSchema18<>( + fieldSchema0, + fieldSchema1, + fieldSchema2, + fieldSchema3, + fieldSchema4, + fieldSchema5, + fieldSchema6, + fieldSchema7, + fieldSchema8, + fieldSchema9, + fieldSchema10, + fieldSchema11, + fieldSchema12, + fieldSchema13, + fieldSchema14, + fieldSchema15, + fieldSchema16, + fieldSchema17) { + @Override + public C createFromBackingNode(TreeNode node) { + return instanceCtor.apply(this, node); + } + }; + } + + protected ContainerSchema18( + SszSchema fieldSchema0, + SszSchema fieldSchema1, + SszSchema fieldSchema2, + SszSchema fieldSchema3, + SszSchema fieldSchema4, + SszSchema fieldSchema5, + SszSchema fieldSchema6, + SszSchema fieldSchema7, + SszSchema fieldSchema8, + SszSchema fieldSchema9, + SszSchema fieldSchema10, + SszSchema fieldSchema11, + SszSchema fieldSchema12, + SszSchema fieldSchema13, + SszSchema fieldSchema14, + SszSchema fieldSchema15, + SszSchema fieldSchema16, + SszSchema fieldSchema17) { + + super( + List.of( + fieldSchema0, + fieldSchema1, + fieldSchema2, + fieldSchema3, + fieldSchema4, + fieldSchema5, + fieldSchema6, + fieldSchema7, + fieldSchema8, + fieldSchema9, + fieldSchema10, + fieldSchema11, + fieldSchema12, + fieldSchema13, + fieldSchema14, + fieldSchema15, + fieldSchema16, + fieldSchema17)); + } + + protected ContainerSchema18( + String containerName, + NamedSchema fieldNamedSchema0, + NamedSchema fieldNamedSchema1, + NamedSchema fieldNamedSchema2, + NamedSchema fieldNamedSchema3, + NamedSchema fieldNamedSchema4, + NamedSchema fieldNamedSchema5, + NamedSchema fieldNamedSchema6, + NamedSchema fieldNamedSchema7, + NamedSchema fieldNamedSchema8, + NamedSchema fieldNamedSchema9, + NamedSchema fieldNamedSchema10, + NamedSchema fieldNamedSchema11, + NamedSchema fieldNamedSchema12, + NamedSchema fieldNamedSchema13, + NamedSchema fieldNamedSchema14, + NamedSchema fieldNamedSchema15, + NamedSchema fieldNamedSchema16, + NamedSchema fieldNamedSchema17) { + + super( + containerName, + List.of( + fieldNamedSchema0, + fieldNamedSchema1, + fieldNamedSchema2, + fieldNamedSchema3, + fieldNamedSchema4, + fieldNamedSchema5, + fieldNamedSchema6, + fieldNamedSchema7, + fieldNamedSchema8, + fieldNamedSchema9, + fieldNamedSchema10, + fieldNamedSchema11, + fieldNamedSchema12, + fieldNamedSchema13, + fieldNamedSchema14, + fieldNamedSchema15, + fieldNamedSchema16, + fieldNamedSchema17)); + } + + @SuppressWarnings("unchecked") + public SszSchema getFieldSchema0() { + return (SszSchema) getChildSchema(0); + } + + @SuppressWarnings("unchecked") + public SszSchema getFieldSchema1() { + return (SszSchema) getChildSchema(1); + } + + @SuppressWarnings("unchecked") + public SszSchema getFieldSchema2() { + return (SszSchema) getChildSchema(2); + } + + @SuppressWarnings("unchecked") + public SszSchema getFieldSchema3() { + return (SszSchema) getChildSchema(3); + } + + @SuppressWarnings("unchecked") + public SszSchema getFieldSchema4() { + return (SszSchema) getChildSchema(4); + } + + @SuppressWarnings("unchecked") + public SszSchema getFieldSchema5() { + return (SszSchema) getChildSchema(5); + } + + @SuppressWarnings("unchecked") + public SszSchema getFieldSchema6() { + return (SszSchema) getChildSchema(6); + } + + @SuppressWarnings("unchecked") + public SszSchema getFieldSchema7() { + return (SszSchema) getChildSchema(7); + } + + @SuppressWarnings("unchecked") + public SszSchema getFieldSchema8() { + return (SszSchema) getChildSchema(8); + } + + @SuppressWarnings("unchecked") + public SszSchema getFieldSchema9() { + return (SszSchema) getChildSchema(9); + } + + @SuppressWarnings("unchecked") + public SszSchema getFieldSchema10() { + return (SszSchema) getChildSchema(10); + } + + @SuppressWarnings("unchecked") + public SszSchema getFieldSchema11() { + return (SszSchema) getChildSchema(11); + } + + @SuppressWarnings("unchecked") + public SszSchema getFieldSchema12() { + return (SszSchema) getChildSchema(12); + } + + @SuppressWarnings("unchecked") + public SszSchema getFieldSchema13() { + return (SszSchema) getChildSchema(13); + } + + @SuppressWarnings("unchecked") + public SszSchema getFieldSchema14() { + return (SszSchema) getChildSchema(14); + } + + @SuppressWarnings("unchecked") + public SszSchema getFieldSchema15() { + return (SszSchema) getChildSchema(15); + } + + @SuppressWarnings("unchecked") + public SszSchema getFieldSchema16() { + return (SszSchema) getChildSchema(16); + } + + @SuppressWarnings("unchecked") + public SszSchema getFieldSchema17() { + return (SszSchema) getChildSchema(17); + } +} diff --git a/infrastructure/ssz/src/main/java/tech/pegasys/teku/infrastructure/ssz/schema/impl/SszOptionalSchemaImpl.java b/infrastructure/ssz/src/main/java/tech/pegasys/teku/infrastructure/ssz/schema/impl/SszOptionalSchemaImpl.java index 62f6716a4ab..fc6a3c5ffc9 100644 --- a/infrastructure/ssz/src/main/java/tech/pegasys/teku/infrastructure/ssz/schema/impl/SszOptionalSchemaImpl.java +++ b/infrastructure/ssz/src/main/java/tech/pegasys/teku/infrastructure/ssz/schema/impl/SszOptionalSchemaImpl.java @@ -250,7 +250,7 @@ public SszLengthBounds getSszLengthBounds() { } private SszLengthBounds calcSszLengthBounds() { - return childSchema.getSszLengthBounds().addBytes(PREFIX_SIZE_BYTES).ceilToBytes(); + return SszLengthBounds.ZERO.or(childSchema.getSszLengthBounds().addBytes(PREFIX_SIZE_BYTES)); } @Override diff --git a/infrastructure/ssz/src/main/java/tech/pegasys/teku/infrastructure/ssz/tree/LeafNode.java b/infrastructure/ssz/src/main/java/tech/pegasys/teku/infrastructure/ssz/tree/LeafNode.java index eb9881cfa49..5f6f63e64ff 100644 --- a/infrastructure/ssz/src/main/java/tech/pegasys/teku/infrastructure/ssz/tree/LeafNode.java +++ b/infrastructure/ssz/src/main/java/tech/pegasys/teku/infrastructure/ssz/tree/LeafNode.java @@ -28,6 +28,7 @@ * in the spec: * https://github.com/protolambda/eth-merkle-trees/blob/master/typing_partials.md#structure */ +@SuppressWarnings("ClassInitializationDeadlock") public interface LeafNode extends TreeNode, LeafDataNode { int MAX_BYTE_SIZE = 32; diff --git a/infrastructure/ssz/src/main/java/tech/pegasys/teku/infrastructure/ssz/tree/SszNodeTemplate.java b/infrastructure/ssz/src/main/java/tech/pegasys/teku/infrastructure/ssz/tree/SszNodeTemplate.java index 1bacaf5793c..9b7c13e6b35 100644 --- a/infrastructure/ssz/src/main/java/tech/pegasys/teku/infrastructure/ssz/tree/SszNodeTemplate.java +++ b/infrastructure/ssz/src/main/java/tech/pegasys/teku/infrastructure/ssz/tree/SszNodeTemplate.java @@ -180,8 +180,7 @@ private static T binaryTraverse( long gIndex, final TreeNode node, final BinaryVisitor visitor) { if (node instanceof LeafNode) { return visitor.visitLeaf(gIndex, (LeafNode) node); - } else if (node instanceof BranchNode) { - BranchNode branchNode = (BranchNode) node; + } else if (node instanceof BranchNode branchNode) { return visitor.visitBranch( gIndex, branchNode, diff --git a/infrastructure/ssz/src/test/java/tech/pegasys/teku/infrastructure/ssz/TestContainers.java b/infrastructure/ssz/src/test/java/tech/pegasys/teku/infrastructure/ssz/TestContainers.java index 9c1b81b299e..0d4087e5340 100644 --- a/infrastructure/ssz/src/test/java/tech/pegasys/teku/infrastructure/ssz/TestContainers.java +++ b/infrastructure/ssz/src/test/java/tech/pegasys/teku/infrastructure/ssz/TestContainers.java @@ -36,6 +36,7 @@ import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode; import tech.pegasys.teku.infrastructure.unsigned.UInt64; +@SuppressWarnings("ClassInitializationDeadlock") public class TestContainers { public interface ImmutableSubContainer extends SszContainer { diff --git a/infrastructure/ssz/src/test/java/tech/pegasys/teku/infrastructure/ssz/schema/SszOptionalSchemaTest.java b/infrastructure/ssz/src/test/java/tech/pegasys/teku/infrastructure/ssz/schema/SszOptionalSchemaTest.java index 7f9ee241a32..c1299d56a54 100644 --- a/infrastructure/ssz/src/test/java/tech/pegasys/teku/infrastructure/ssz/schema/SszOptionalSchemaTest.java +++ b/infrastructure/ssz/src/test/java/tech/pegasys/teku/infrastructure/ssz/schema/SszOptionalSchemaTest.java @@ -21,6 +21,7 @@ import java.util.stream.Stream; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.units.bigints.UInt256; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -54,6 +55,18 @@ public static Stream> testContainerOptionalSchemas() { return Stream.of(ContainerWithOptionals.SSZ_SCHEMA); } + @Test + void verifySszLengthBounds() { + assertThat(SszOptionalSchema.create(SszPrimitiveSchemas.BIT_SCHEMA).getSszLengthBounds()) + .matches(bound -> bound.getMinBytes() == 0) + .matches(bound -> bound.getMaxBytes() == 2) + .matches(bound -> bound.getMaxBits() == 9); + + assertThat(SszOptionalSchema.create(SszPrimitiveSchemas.BYTES32_SCHEMA).getSszLengthBounds()) + .matches(bound -> bound.getMinBytes() == 0) + .matches(bound -> bound.getMaxBytes() == 33); + } + @Override public Stream> testSchemas() { return Streams.concat(testOptionalSchemas(), testContainerOptionalSchemas()); diff --git a/infrastructure/ssz/src/test/java/tech/pegasys/teku/infrastructure/ssz/schema/SszSchemaTestBase.java b/infrastructure/ssz/src/test/java/tech/pegasys/teku/infrastructure/ssz/schema/SszSchemaTestBase.java index 87acd6208c5..fbef5896bf5 100644 --- a/infrastructure/ssz/src/test/java/tech/pegasys/teku/infrastructure/ssz/schema/SszSchemaTestBase.java +++ b/infrastructure/ssz/src/test/java/tech/pegasys/teku/infrastructure/ssz/schema/SszSchemaTestBase.java @@ -25,6 +25,7 @@ import tech.pegasys.teku.infrastructure.ssz.RandomSszDataGenerator; import tech.pegasys.teku.infrastructure.ssz.SszData; import tech.pegasys.teku.infrastructure.ssz.SszDataAssert; +import tech.pegasys.teku.infrastructure.ssz.SszOptional; import tech.pegasys.teku.infrastructure.ssz.schema.SszSchemaHints.SszSuperNodeHint; import tech.pegasys.teku.infrastructure.ssz.schema.impl.AbstractSszCollectionSchema; import tech.pegasys.teku.infrastructure.ssz.sos.SimpleSszReader; @@ -44,25 +45,26 @@ void getDefaultTree_shouldBeEqualToDefaultStructure(SszSchema schema) { @MethodSource("testSchemaArguments") @ParameterizedTest - void sszDeserialize_tooLongSszShouldFailFastWithoutReadingWholeInput(SszSchema schema) { - if (schema instanceof SszOptionalSchema) { - // empty SszOptional couldn't pass this test - return; - } + void sszDeserialize_tooLongSszShouldFailFastWithoutReadingWholeInput( + final SszSchema schema) { long maxSszLength = schema.getSszLengthBounds().getMaxBytes(); // ignore too large and degenerative structs assumeThat(maxSszLength).isLessThan(32 * 1024 * 1024).isGreaterThan(0); // ignore lists using SszSuperNode as many validations are skipped - if (schema instanceof AbstractSszCollectionSchema) { - assumeThat( - ((AbstractSszCollectionSchema) schema) - .getHints() - .getHint(SszSuperNodeHint.class)) + if (schema instanceof AbstractSszCollectionSchema collectionSchema) { + assumeThat(collectionSchema.getHints().getHint(SszSuperNodeHint.class)) .describedAs("uses SszSuperNode") .isEmpty(); } SszData data = randomSsz.randomData(schema); + + if (data instanceof SszOptional optionalData) { + assumeThat(optionalData.getValue()) + .describedAs("optional can't be empty to pass the test") + .isPresent(); + } + Bytes ssz = data.sszSerialize(); Bytes sszWithExtraData = Bytes.wrap(ssz, Bytes.random((int) (maxSszLength - ssz.size() + 1))); diff --git a/infrastructure/ssz/src/test/java/tech/pegasys/teku/infrastructure/ssz/schema/TreeNodeAssert.java b/infrastructure/ssz/src/test/java/tech/pegasys/teku/infrastructure/ssz/schema/TreeNodeAssert.java index 48806158419..7ed33dbc2f9 100644 --- a/infrastructure/ssz/src/test/java/tech/pegasys/teku/infrastructure/ssz/schema/TreeNodeAssert.java +++ b/infrastructure/ssz/src/test/java/tech/pegasys/teku/infrastructure/ssz/schema/TreeNodeAssert.java @@ -91,8 +91,7 @@ private void assertTreeEqual(final TreeNode actual, final TreeNode expected, fin assertThat(actual.hashTreeRoot()) .describedAs("zero branch node root at gIndex %s", gIndex) .isEqualTo(expected.hashTreeRoot()); - } else if (actual instanceof BranchNode) { - final BranchNode actualBranch = (BranchNode) actual; + } else if (actual instanceof BranchNode actualBranch) { final BranchNode expectedBranch = (BranchNode) expected; assertTreeEqual( actualBranch.left(), expectedBranch.left(), GIndexUtil.gIdxLeftGIndex(gIndex)); diff --git a/infrastructure/ssz/src/testFixtures/java/tech/pegasys/teku/infrastructure/ssz/RandomSszDataGenerator.java b/infrastructure/ssz/src/testFixtures/java/tech/pegasys/teku/infrastructure/ssz/RandomSszDataGenerator.java index a609293eaad..6535f873ef8 100644 --- a/infrastructure/ssz/src/testFixtures/java/tech/pegasys/teku/infrastructure/ssz/RandomSszDataGenerator.java +++ b/infrastructure/ssz/src/testFixtures/java/tech/pegasys/teku/infrastructure/ssz/RandomSszDataGenerator.java @@ -94,9 +94,7 @@ public Stream randomDataStream(SszSchema schema) { } else { throw new IllegalArgumentException("Unknown primitive schema: " + schema); } - } else if (schema instanceof AbstractSszContainerSchema) { - AbstractSszContainerSchema containerSchema = - (AbstractSszContainerSchema) schema; + } else if (schema instanceof AbstractSszContainerSchema containerSchema) { return Stream.generate( () -> { List children = @@ -124,10 +122,9 @@ public Stream randomDataStream(SszSchema schema) { SszCollection ret = collectionSchema.createFromElements(children); return (T) ret; }); - } else if (schema instanceof SszUnionSchema) { + } else if (schema instanceof SszUnionSchema unionSchema) { return Stream.generate( () -> { - SszUnionSchema unionSchema = (SszUnionSchema) schema; int selector = random.nextInt(unionSchema.getTypesCount()); return (T) unionSchema.createFromValue( diff --git a/infrastructure/ssz/src/testFixtures/java/tech/pegasys/teku/infrastructure/ssz/SszDataAssert.java b/infrastructure/ssz/src/testFixtures/java/tech/pegasys/teku/infrastructure/ssz/SszDataAssert.java index 6ae9cd95540..d0c7ad96e9f 100644 --- a/infrastructure/ssz/src/testFixtures/java/tech/pegasys/teku/infrastructure/ssz/SszDataAssert.java +++ b/infrastructure/ssz/src/testFixtures/java/tech/pegasys/teku/infrastructure/ssz/SszDataAssert.java @@ -41,7 +41,7 @@ public SszDataAssert isEqualByGettersTo(T expected) { IntStream.range(0, res.size() - 1) .mapToObj(i -> " ".repeat(i) + res.get(i)) .collect(Collectors.joining("\n")); - errMessage += " ERROR: " + res.get(res.size() - 1); + errMessage += " ERROR: " + res.getLast(); failWithMessage( "Expected %s's to be equal by getter, but found differences:\n%s", expected.getClass().getSimpleName(), errMessage); @@ -123,8 +123,7 @@ private static List compareByGetters(SszData actual, SszData expected) { + ", actual: " + actual.getSchema()); } - if (actual instanceof SszComposite) { - SszComposite c1 = (SszComposite) actual; + if (actual instanceof SszComposite c1) { SszComposite c2 = (SszComposite) expected; if (c1.size() != c2.size()) { return List.of( diff --git a/infrastructure/ssz/src/testFixtures/java/tech/pegasys/teku/infrastructure/ssz/SszTestUtils.java b/infrastructure/ssz/src/testFixtures/java/tech/pegasys/teku/infrastructure/ssz/SszTestUtils.java index 1fa7d87084a..632e4c44aa2 100644 --- a/infrastructure/ssz/src/testFixtures/java/tech/pegasys/teku/infrastructure/ssz/SszTestUtils.java +++ b/infrastructure/ssz/src/testFixtures/java/tech/pegasys/teku/infrastructure/ssz/SszTestUtils.java @@ -17,7 +17,6 @@ import it.unimi.dsi.fastutil.ints.IntList; import java.util.List; import java.util.function.Consumer; -import java.util.stream.Collectors; import java.util.stream.IntStream; import tech.pegasys.teku.infrastructure.ssz.collections.SszBitlist; import tech.pegasys.teku.infrastructure.ssz.schema.SszContainerSchema; @@ -38,7 +37,7 @@ public static IntList getVectorLengths(SszContainerSchema sszContainerSchema) } public static SszBitlist not(SszBitlist bitlist) { - List notList = bitlist.stream().map(b -> !b.get()).collect(Collectors.toList()); + List notList = bitlist.stream().map(b -> !b.get()).toList(); int[] notBitIndices = IntStream.range(0, notList.size()).filter(notList::get).toArray(); return bitlist.getSchema().ofBits(bitlist.size(), notBitIndices); } @@ -51,9 +50,11 @@ public static String dumpBinaryTree(TreeNode node) { } private static void dumpBinaryTreeRec( - TreeNode node, String prefix, boolean printCommit, Consumer linesConsumer) { - if (node instanceof LeafNode) { - LeafNode leafNode = (LeafNode) node; + final TreeNode node, + final String prefix, + final boolean printCommit, + final Consumer linesConsumer) { + if (node instanceof LeafNode leafNode) { linesConsumer.accept(prefix + leafNode); } else { BranchNode branchNode = (BranchNode) node; diff --git a/networking/eth2/src/integration-test/java/tech/pegasys/teku/networking/eth2/AbstractRpcMethodIntegrationTest.java b/networking/eth2/src/integration-test/java/tech/pegasys/teku/networking/eth2/AbstractRpcMethodIntegrationTest.java index e34fa53b9cf..b742091c103 100644 --- a/networking/eth2/src/integration-test/java/tech/pegasys/teku/networking/eth2/AbstractRpcMethodIntegrationTest.java +++ b/networking/eth2/src/integration-test/java/tech/pegasys/teku/networking/eth2/AbstractRpcMethodIntegrationTest.java @@ -35,6 +35,7 @@ import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.bellatrix.BeaconBlockBodyBellatrix; import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.capella.BeaconBlockBodyCapella; import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.deneb.BeaconBlockBodyDeneb; +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.electra.BeaconBlockBodyElectra; import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.phase0.BeaconBlockBodyPhase0; import tech.pegasys.teku.storage.storageSystem.InMemoryStorageSystemBuilder; import tech.pegasys.teku.storage.storageSystem.StorageSystem; @@ -79,6 +80,7 @@ private void setUpNextSpec(final SpecMilestone nextSpecMilestone) { checkState(nextSpecMilestone.equals(SpecMilestone.DENEB), "next spec should be deneb"); nextSpec = Optional.of(TestSpecFactory.createMinimalWithDenebForkEpoch(nextSpecEpoch)); } + case ELECTRA -> throw new RuntimeException("Not implemented yet"); case DENEB -> throw new RuntimeException("Base spec is already latest supported milestone"); } nextSpecSlot = nextSpec.orElseThrow().computeStartSlotAtEpoch(nextSpecEpoch); @@ -203,27 +205,21 @@ protected PeerAndNetwork createRemotePeerAndNetwork(final Spec localSpec, final public record PeerAndNetwork(Eth2Peer peer, Eth2P2PNetwork network) {} protected static Stream generateSpecTransitionWithCombinationParams() { - return Arrays.stream(SpecMilestone.values()) - .filter(milestone -> milestone.ordinal() < SpecMilestone.values().length - 1) + return SpecMilestone.getAllMilestonesFrom(SpecMilestone.ALTAIR).stream() .flatMap( milestone -> { - final SpecMilestone nextMilestone = SpecMilestone.values()[milestone.ordinal() + 1]; + final SpecMilestone prevMilestone = milestone.getPreviousMilestone(); return Stream.of( - Arguments.of(milestone, nextMilestone, true, true), - Arguments.of(milestone, nextMilestone, false, true), - Arguments.of(milestone, nextMilestone, true, false), - Arguments.of(milestone, nextMilestone, false, false)); + Arguments.of(prevMilestone, milestone, true, true), + Arguments.of(prevMilestone, milestone, false, true), + Arguments.of(prevMilestone, milestone, true, false), + Arguments.of(prevMilestone, milestone, false, false)); }); } protected static Stream generateSpecTransition() { - return Arrays.stream(SpecMilestone.values()) - .filter(milestone -> milestone.ordinal() < SpecMilestone.values().length - 1) - .map( - milestone -> { - final SpecMilestone nextMilestone = SpecMilestone.values()[milestone.ordinal() + 1]; - return Arguments.of(milestone, nextMilestone); - }); + return SpecMilestone.getAllMilestonesFrom(SpecMilestone.ALTAIR).stream() + .map(milestone -> Arguments.of(milestone.getPreviousMilestone(), milestone)); } protected static Stream generateSpec() { @@ -261,6 +257,7 @@ protected static Class milestoneToBeaconBlockBodyClass(final SpecMilestone mi case ALTAIR -> BeaconBlockBodyAltair.class; case BELLATRIX -> BeaconBlockBodyBellatrix.class; case CAPELLA -> BeaconBlockBodyCapella.class; + case ELECTRA -> BeaconBlockBodyElectra.class; case DENEB -> BeaconBlockBodyDeneb.class; }; } diff --git a/networking/eth2/src/integration-test/java/tech/pegasys/teku/networking/eth2/GetMetadataIntegrationTest.java b/networking/eth2/src/integration-test/java/tech/pegasys/teku/networking/eth2/GetMetadataIntegrationTest.java index d9db758e9f2..e123b4f1edc 100644 --- a/networking/eth2/src/integration-test/java/tech/pegasys/teku/networking/eth2/GetMetadataIntegrationTest.java +++ b/networking/eth2/src/integration-test/java/tech/pegasys/teku/networking/eth2/GetMetadataIntegrationTest.java @@ -147,7 +147,7 @@ public void requestMetadata_withDisparateVersionsEnabled( private static Class milestoneToMetadataClass(final SpecMilestone milestone) { return switch (milestone) { case PHASE0 -> MetadataMessagePhase0.class; - case ALTAIR, BELLATRIX, CAPELLA, DENEB -> MetadataMessageAltair.class; + case ALTAIR, BELLATRIX, CAPELLA, ELECTRA, DENEB -> MetadataMessageAltair.class; }; } } diff --git a/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/Eth2P2PNetworkBuilder.java b/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/Eth2P2PNetworkBuilder.java index 4deae0712f0..61c4efb92cb 100644 --- a/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/Eth2P2PNetworkBuilder.java +++ b/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/Eth2P2PNetworkBuilder.java @@ -38,6 +38,7 @@ import tech.pegasys.teku.networking.eth2.gossip.forks.versions.GossipForkSubscriptionsBellatrix; import tech.pegasys.teku.networking.eth2.gossip.forks.versions.GossipForkSubscriptionsCapella; import tech.pegasys.teku.networking.eth2.gossip.forks.versions.GossipForkSubscriptionsDeneb; +import tech.pegasys.teku.networking.eth2.gossip.forks.versions.GossipForkSubscriptionsElectra; import tech.pegasys.teku.networking.eth2.gossip.forks.versions.GossipForkSubscriptionsPhase0; import tech.pegasys.teku.networking.eth2.gossip.subnets.AttestationSubnetTopicProvider; import tech.pegasys.teku.networking.eth2.gossip.subnets.PeerSubnetSubscriptions; @@ -267,6 +268,23 @@ private GossipForkSubscriptions createSubscriptions( gossipedSignedContributionAndProofProcessor, gossipedSyncCommitteeMessageProcessor, gossipedSignedBlsToExecutionChangeProcessor); + case ELECTRA -> new GossipForkSubscriptionsElectra( + forkAndSpecMilestone.getFork(), + spec, + asyncRunner, + metricsSystem, + network, + combinedChainDataClient.getRecentChainData(), + gossipEncoding, + gossipedBlockProcessor, + gossipedAttestationConsumer, + gossipedAggregateProcessor, + gossipedAttesterSlashingConsumer, + gossipedProposerSlashingConsumer, + gossipedVoluntaryExitConsumer, + gossipedSignedContributionAndProofProcessor, + gossipedSyncCommitteeMessageProcessor, + gossipedSignedBlsToExecutionChangeProcessor); case DENEB -> new GossipForkSubscriptionsDeneb( forkAndSpecMilestone.getFork(), spec, diff --git a/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/gossip/forks/versions/GossipForkSubscriptionsDeneb.java b/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/gossip/forks/versions/GossipForkSubscriptionsDeneb.java index 5b6b3ac71e4..1824d50e5d1 100644 --- a/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/gossip/forks/versions/GossipForkSubscriptionsDeneb.java +++ b/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/gossip/forks/versions/GossipForkSubscriptionsDeneb.java @@ -33,7 +33,7 @@ import tech.pegasys.teku.spec.datastructures.state.ForkInfo; import tech.pegasys.teku.storage.client.RecentChainData; -public class GossipForkSubscriptionsDeneb extends GossipForkSubscriptionsCapella { +public class GossipForkSubscriptionsDeneb extends GossipForkSubscriptionsElectra { private final OperationProcessor blobSidecarProcessor; diff --git a/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/gossip/forks/versions/GossipForkSubscriptionsElectra.java b/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/gossip/forks/versions/GossipForkSubscriptionsElectra.java new file mode 100644 index 00000000000..cd6238a0fbb --- /dev/null +++ b/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/gossip/forks/versions/GossipForkSubscriptionsElectra.java @@ -0,0 +1,73 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.networking.eth2.gossip.forks.versions; + +import org.hyperledger.besu.plugin.services.MetricsSystem; +import tech.pegasys.teku.infrastructure.async.AsyncRunner; +import tech.pegasys.teku.networking.eth2.gossip.encoding.GossipEncoding; +import tech.pegasys.teku.networking.eth2.gossip.topics.OperationProcessor; +import tech.pegasys.teku.networking.p2p.discovery.DiscoveryNetwork; +import tech.pegasys.teku.spec.Spec; +import tech.pegasys.teku.spec.datastructures.attestation.ValidatableAttestation; +import tech.pegasys.teku.spec.datastructures.blocks.SignedBeaconBlock; +import tech.pegasys.teku.spec.datastructures.operations.AttesterSlashing; +import tech.pegasys.teku.spec.datastructures.operations.ProposerSlashing; +import tech.pegasys.teku.spec.datastructures.operations.SignedBlsToExecutionChange; +import tech.pegasys.teku.spec.datastructures.operations.SignedVoluntaryExit; +import tech.pegasys.teku.spec.datastructures.operations.versions.altair.SignedContributionAndProof; +import tech.pegasys.teku.spec.datastructures.operations.versions.altair.ValidatableSyncCommitteeMessage; +import tech.pegasys.teku.spec.datastructures.state.Fork; +import tech.pegasys.teku.storage.client.RecentChainData; + +public class GossipForkSubscriptionsElectra extends GossipForkSubscriptionsCapella { + + public GossipForkSubscriptionsElectra( + final Fork fork, + final Spec spec, + final AsyncRunner asyncRunner, + final MetricsSystem metricsSystem, + final DiscoveryNetwork discoveryNetwork, + final RecentChainData recentChainData, + final GossipEncoding gossipEncoding, + final OperationProcessor blockProcessor, + final OperationProcessor attestationProcessor, + final OperationProcessor aggregateProcessor, + final OperationProcessor attesterSlashingProcessor, + final OperationProcessor proposerSlashingProcessor, + final OperationProcessor voluntaryExitProcessor, + final OperationProcessor + signedContributionAndProofOperationProcessor, + final OperationProcessor + syncCommitteeMessageOperationProcessor, + final OperationProcessor + signedBlsToExecutionChangeOperationProcessor) { + super( + fork, + spec, + asyncRunner, + metricsSystem, + discoveryNetwork, + recentChainData, + gossipEncoding, + blockProcessor, + attestationProcessor, + aggregateProcessor, + attesterSlashingProcessor, + proposerSlashingProcessor, + voluntaryExitProcessor, + signedContributionAndProofOperationProcessor, + syncCommitteeMessageOperationProcessor, + signedBlsToExecutionChangeOperationProcessor); + } +} diff --git a/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/rpc/core/Eth2RpcResponseHandler.java b/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/rpc/core/Eth2RpcResponseHandler.java index af3bedba884..e4b038518a6 100644 --- a/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/rpc/core/Eth2RpcResponseHandler.java +++ b/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/rpc/core/Eth2RpcResponseHandler.java @@ -76,6 +76,7 @@ public static Eth2RpcResponseHandler expectSingleResponse() { return new Eth2RpcResponseHandler<>(responseHandler, completed, resultFuture); } + @SuppressWarnings("VoidUsed") private static SafeFuture applyError( SafeFuture future, AtomicReference errorCapture) { return future.thenApply( diff --git a/networking/eth2/src/testFixtures/java/tech/pegasys/teku/networking/eth2/Eth2P2PNetworkFactory.java b/networking/eth2/src/testFixtures/java/tech/pegasys/teku/networking/eth2/Eth2P2PNetworkFactory.java index c833f718f86..df3baee64d1 100644 --- a/networking/eth2/src/testFixtures/java/tech/pegasys/teku/networking/eth2/Eth2P2PNetworkFactory.java +++ b/networking/eth2/src/testFixtures/java/tech/pegasys/teku/networking/eth2/Eth2P2PNetworkFactory.java @@ -54,6 +54,7 @@ import tech.pegasys.teku.networking.eth2.gossip.forks.versions.GossipForkSubscriptionsBellatrix; import tech.pegasys.teku.networking.eth2.gossip.forks.versions.GossipForkSubscriptionsCapella; import tech.pegasys.teku.networking.eth2.gossip.forks.versions.GossipForkSubscriptionsDeneb; +import tech.pegasys.teku.networking.eth2.gossip.forks.versions.GossipForkSubscriptionsElectra; import tech.pegasys.teku.networking.eth2.gossip.forks.versions.GossipForkSubscriptionsPhase0; import tech.pegasys.teku.networking.eth2.gossip.subnets.AttestationSubnetTopicProvider; import tech.pegasys.teku.networking.eth2.gossip.subnets.PeerSubnetSubscriptions; @@ -403,6 +404,23 @@ private GossipForkSubscriptions createSubscriptions( signedContributionAndProofProcessor, syncCommitteeMessageProcessor, signedBlsToExecutionChangeProcessor); + case ELECTRA -> new GossipForkSubscriptionsElectra( + forkAndSpecMilestone.getFork(), + spec, + asyncRunner, + metricsSystem, + network, + recentChainData, + gossipEncoding, + gossipedBlockProcessor, + gossipedAttestationProcessor, + gossipedAggregateProcessor, + attesterSlashingProcessor, + proposerSlashingProcessor, + voluntaryExitProcessor, + signedContributionAndProofProcessor, + syncCommitteeMessageProcessor, + signedBlsToExecutionChangeProcessor); case DENEB -> new GossipForkSubscriptionsDeneb( forkAndSpecMilestone.getFork(), spec, diff --git a/scripts/update-snapshot.sh b/scripts/update-snapshot.sh index e064d9eaf2f..85082654ba8 100755 --- a/scripts/update-snapshot.sh +++ b/scripts/update-snapshot.sh @@ -2,7 +2,7 @@ set -euo pipefail LOCAL_REST_API_BINDING_PORT=15051 -valid_networks=("gnosis" "goerli" "lukso" "mainnet" "sepolia" "holesky") +valid_networks=("gnosis" "lukso" "mainnet" "sepolia" "holesky") OUT=${1:?Must specify destination directory for snapshots} echo $'\nChecking that required environment variables are set:' diff --git a/teku/src/main/java/tech/pegasys/teku/cli/options/Eth2NetworkOptions.java b/teku/src/main/java/tech/pegasys/teku/cli/options/Eth2NetworkOptions.java index 7b5a91ff578..8347f2cfdeb 100644 --- a/teku/src/main/java/tech/pegasys/teku/cli/options/Eth2NetworkOptions.java +++ b/teku/src/main/java/tech/pegasys/teku/cli/options/Eth2NetworkOptions.java @@ -145,6 +145,14 @@ public class Eth2NetworkOptions { arity = "1") private UInt64 denebForkEpoch; + @Option( + names = {"--Xnetwork-electra-fork-epoch"}, + hidden = true, + paramLabel = "", + description = "Override the electra fork activation epoch.", + arity = "1") + private UInt64 electraForkEpoch; + @Option( names = {"--Xnetwork-total-terminal-difficulty-override"}, hidden = true, @@ -298,6 +306,9 @@ private void configureEth2Network(Eth2NetworkConfiguration.Builder builder) { if (capellaForkEpoch != null) { builder.capellaForkEpoch(capellaForkEpoch); } + if (electraForkEpoch != null) { + builder.electraForkEpoch(electraForkEpoch); + } if (denebForkEpoch != null) { builder.denebForkEpoch(denebForkEpoch); } diff --git a/test-network/README.md b/test-network/README.md index 171282ab820..e1702434b48 100644 --- a/test-network/README.md +++ b/test-network/README.md @@ -1,30 +1,30 @@ -Docker Testnet +Kurtosis Testnet ============== -This directory contains a docker-compose configuration to run a basic 4-node Teku network. -The network uses the minimal spec and the mock-genesis protocol to generate a genesis state without -needing an ETH1 chain. The 64 validators are spread across the four nodes. +[Kurtosis](https://github.com/kurtosis-tech/ethereum-package) can be used to spin up a Docker-based +test network. A sample [network_params.yaml](./network_params.yaml) configuration file has been +provided to run a basic 4-node Teku/Besu network with a mainnet preset and a total of 256 validators (64 per node). +For exhaustive Kurtosis configuration options, please check the full YAML schema [here](https://github.com/kurtosis-tech/ethereum-package#configuration). How To Run ---------- -To start the network, run the `launch.sh` script in this directory. -To stop, simply ctrl-C to kill the docker instances and then optionally run `docker-compose down` to remove the stopped instances from docker. +* Make sure Kurtosis is [installed](https://docs.kurtosis.com/install/). +* Run `kurtosis run --enclave test-network github.com/kurtosis-tech/ethereum-package --args-file network_params.yaml` +If you would like to use a locally built Teku image, first run `./gradlew distDocker` in the root +directory and then use `cl_image: consensys/teku:develop` in the `network_params.yaml` file. -Ports and Access ----------------- +To tear down the test network, you can simply run `kurtosis enclave rm -f test-network`. -Metrics are available via Grafana at http://localhost:3001/ username is `admin` and password is `pass`. +Monitoring/Debugging +---------- -Each node's REST APIs are exposed on ports 19601, 19602, 19603 and 19604 respectively. +[Dora](https://github.com/ethpandaops/dora), [el_forkmon](https://github.com/ethereum/nodemonitor), +Prometheus/Grafana and [rpc-snooper](https://github.com/ethpandaops/rpc-snooper) have been enabled +to allow for an easier monitoring/debugging of the network/nodes. -Add a `ports:` section to any of the nodes to expose additional ports and access services from that node. -Persistent Data ---------------- -The teku nodes store data and logs in `data/node/`. It is safe to delete the entire `data` directory to start from scratch. -Grafana stores its data in `grafana/data` so changes made to dashboards are persisted across runs. diff --git a/test-network/docker-compose.yml b/test-network/docker-compose.yml deleted file mode 100644 index b9f48390a2f..00000000000 --- a/test-network/docker-compose.yml +++ /dev/null @@ -1,150 +0,0 @@ -version: '3.6' - -x-teku-deploy-def: - &teku-deploy-def - environment: - - 'JAVA_OPTS=-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data -Djdk.nio.maxCachedBufferSize=1 -XX:+UseContainerSupport' - deploy: - resources: - limits: - cpus: "1" - memory: 512m - -services: - prometheus: - image: prom/prometheus:latest - volumes: - - './prometheus:/etc/prometheus' - command: - - '--config.file=/etc/prometheus/prometheus.yml' - node-exporter: - image: prom/node-exporter:latest - - grafana: - image: grafana/grafana:latest - user: "${USER}:root" - environment: - - GF_SECURITY_ADMIN_PASSWORD=pass - volumes: - - ./grafana/provisioning/:/etc/grafana/provisioning/ - - ./grafana/data/:/var/lib/grafana - - ./grafana/log/:/var/log/grafana - depends_on: - - prometheus - ports: - - "3001:3000" - - teku1: - image: consensys/teku:develop - << : *teku-deploy-def - user: "${USER}" - command: - - '--network=minimal' - - '--rest-api-enabled' - - '--metrics-enabled' - - '--metrics-port=8008' - - '--metrics-host-allowlist=*' - - '--rest-api-host-allowlist=*' - - '--log-file=/data/teku.log' - - '--data-path=/data/storage' - - '--data-storage-mode=archive' - - '--Xnetwork-altair-fork-epoch=0' - - '--Xinterop-genesis-time=${GENESIS_TIME}' - - '--Xinterop-owned-validator-start-index=0' - - '--Xinterop-owned-validator-count=16' - - '--Xinterop-number-of-validators=64' - - '--Xinterop-enabled' - - '--p2p-private-key-file=/etc/teku/p2p-key.txt' - - '--p2p-static-peers=/dns4/teku2/tcp/9000/p2p/16Uiu2HAm7WCLoc7KqP5jKQuQM3CNfR9tiamadxmEmNYUviXKoYmm,/dns4/teku3/tcp/9000/p2p/16Uiu2HAm3NZUwzzNHfnnB8ADfnuP5MTDuqjRb3nTRBxPTQ4g7Wjj,/dns4/teku4/tcp/9000/p2p/16Uiu2HAmPF4kvruyovDo7Pg8ZSAYefGdQvTiqQUWC1oUGFfUGm32' - - '--Xlog-wire-cipher-enabled' - - '--Xlog-wire-mux-enabled' - - '--Xlog-wire-gossip-enabled' - volumes: - - './nodes/node1:/etc/teku' - - './data/node1:/data' - ports: - - '19601:5051' - - teku2: - image: consensys/teku:develop - <<: *teku-deploy-def - user: "${USER}" - command: - - '--network=minimal' - - '--rest-api-enabled' - - '--metrics-enabled' - - '--metrics-port=8008' - - '--metrics-host-allowlist=*' - - '--rest-api-host-allowlist=*' - - '--log-file=/data/teku.log' - - '--data-path=/data/storage' - - '--data-storage-mode=archive' - - '--Xnetwork-altair-fork-epoch=0' - - '--Xinterop-genesis-time=${GENESIS_TIME}' - - '--Xinterop-owned-validator-start-index=16' - - '--Xinterop-owned-validator-count=16' - - '--Xinterop-number-of-validators=64' - - '--Xinterop-enabled' - - '--p2p-private-key-file=/etc/teku/p2p-key.txt' - - '--p2p-static-peers=/dns4/teku1/tcp/9000/p2p/16Uiu2HAmGNMvKxVP6E1Jjnn6oTxUMRbdkJXaEvd2R9ENkGYVDqVh,/dns4/teku3/tcp/9000/p2p/16Uiu2HAm3NZUwzzNHfnnB8ADfnuP5MTDuqjRb3nTRBxPTQ4g7Wjj,/dns4/teku4/tcp/9000/p2p/16Uiu2HAmPF4kvruyovDo7Pg8ZSAYefGdQvTiqQUWC1oUGFfUGm32' - volumes: - - './nodes/node2:/etc/teku' - - './data/node2:/data' - ports: - - '19602:5051' - - teku3: - image: consensys/teku:develop - <<: *teku-deploy-def - user: "${USER}" - command: - - '--network=minimal' - - '--rest-api-enabled' - - '--metrics-enabled' - - '--metrics-port=8008' - - '--metrics-host-allowlist=*' - - '--rest-api-host-allowlist=*' - - '--log-file=/data/teku.log' - - '--data-path=/data/storage' - - '--data-storage-mode=archive' - - '--Xnetwork-altair-fork-epoch=0' - - '--Xinterop-genesis-time=${GENESIS_TIME}' - - '--Xinterop-owned-validator-start-index=32' - - '--Xinterop-owned-validator-count=16' - - '--Xinterop-number-of-validators=64' - - '--Xinterop-enabled' - - '--p2p-private-key-file=/etc/teku/p2p-key.txt' - - '--p2p-static-peers=/dns4/teku1/tcp/9000/p2p/16Uiu2HAmGNMvKxVP6E1Jjnn6oTxUMRbdkJXaEvd2R9ENkGYVDqVh,/dns4/teku2/tcp/9000/p2p/16Uiu2HAm7WCLoc7KqP5jKQuQM3CNfR9tiamadxmEmNYUviXKoYmm,/dns4/teku4/tcp/9000/p2p/16Uiu2HAmPF4kvruyovDo7Pg8ZSAYefGdQvTiqQUWC1oUGFfUGm32' - volumes: - - './nodes/node3:/etc/teku' - - './data/node3:/data' - ports: - - '19603:5051' - - teku4: - image: consensys/teku:develop - <<: *teku-deploy-def - user: "${USER}" - command: - - '--network=minimal' - - '--rest-api-enabled' - - '--metrics-enabled' - - '--metrics-port=8008' - - '--metrics-host-allowlist=*' - - '--rest-api-host-allowlist=*' - - '--log-file=/data/teku.log' - - '--data-path=/data/storage' - - '--data-storage-mode=archive' - - '--Xnetwork-altair-fork-epoch=0' - - '--Xinterop-genesis-time=${GENESIS_TIME}' - - '--Xinterop-owned-validator-start-index=48' - - '--Xinterop-owned-validator-count=16' - - '--Xinterop-number-of-validators=64' - - '--Xinterop-enabled' - - '--p2p-private-key-file=/etc/teku/p2p-key.txt' - - '--p2p-static-peers=/dns4/teku1/tcp/9000/p2p/16Uiu2HAmGNMvKxVP6E1Jjnn6oTxUMRbdkJXaEvd2R9ENkGYVDqVh,/dns4/teku2/tcp/9000/p2p/16Uiu2HAm7WCLoc7KqP5jKQuQM3CNfR9tiamadxmEmNYUviXKoYmm,/dns4/teku3/tcp/9000/p2p/16Uiu2HAm3NZUwzzNHfnnB8ADfnuP5MTDuqjRb3nTRBxPTQ4g7Wjj' - volumes: - - './nodes/node4:/etc/teku' - - './data/node4:/data' - ports: - - '19604:5051' diff --git a/test-network/grafana/provisioning/dashboards/dashboard.yml b/test-network/grafana/provisioning/dashboards/dashboard.yml deleted file mode 100644 index 9f7232c9efc..00000000000 --- a/test-network/grafana/provisioning/dashboards/dashboard.yml +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: 1 - -providers: - - name: 'Prometheus' - orgId: 1 - folder: '' - type: file - disableDeletion: false - editable: true - options: - path: /etc/grafana/provisioning/dashboards \ No newline at end of file diff --git a/test-network/grafana/provisioning/datasources/datasource.yml b/test-network/grafana/provisioning/datasources/datasource.yml deleted file mode 100644 index d5dba3805d7..00000000000 --- a/test-network/grafana/provisioning/datasources/datasource.yml +++ /dev/null @@ -1,50 +0,0 @@ -# config file version -apiVersion: 1 - -# list of datasources that should be deleted from the database -deleteDatasources: - - name: Prometheus - orgId: 1 - -# list of datasources to insert/update depending -# whats available in the database -datasources: - # name of the datasource. Required - - name: Prometheus - # datasource type. Required - type: prometheus - # access mode. direct or proxy. Required - access: proxy - # org id. will default to orgId 1 if not specified - orgId: 1 - # url - url: http://prometheus:9090 - # database password, if used - password: - # database user, if used - user: - # database name, if used - database: - # enable/disable basic auth - basicAuth: false - # basic auth username, if used - basicAuthUser: - # basic auth password, if used - basicAuthPassword: - # enable/disable with credentials headers - withCredentials: - # mark as default datasource. Max one per org - isDefault: true - # fields that will be converted to json and stored in json_data - jsonData: - graphiteVersion: "1.1" - tlsAuth: false - tlsAuthWithCACert: false - # json object of data that will be encrypted. - secureJsonData: - tlsCACert: "..." - tlsClientCert: "..." - tlsClientKey: "..." - version: 1 - # allow users to edit datasources from the UI. - editable: true \ No newline at end of file diff --git a/test-network/launch.sh b/test-network/launch.sh deleted file mode 100755 index 476af450b60..00000000000 --- a/test-network/launch.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash -set -euo pipefail -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" - -cd "${DIR}" - -mkdir -p data/node1 data/node2 data/node3 data/node4 grafana/data grafana/log - -START_DELAY=30 -CURRENT_TIME=$(date +%s) -export GENESIS_TIME=$((CURRENT_TIME + START_DELAY)) -cp "${DIR}/../dashboard/teku-dashboard-grafana.json" "${DIR}/grafana/provisioning/dashboards/" - -USER=${UID:-root} docker-compose --compatibility up \ No newline at end of file diff --git a/test-network/network_params.yaml b/test-network/network_params.yaml new file mode 100644 index 00000000000..07681b2f572 --- /dev/null +++ b/test-network/network_params.yaml @@ -0,0 +1,24 @@ +participants: + - el_type: besu + el_image: hyperledger/besu:latest + cl_type: teku + cl_image: consensys/teku:latest + - el_type: besu + el_image: hyperledger/besu:latest + cl_type: teku + cl_image: consensys/teku:latest + - el_type: besu + el_image: hyperledger/besu:latest + cl_type: teku + cl_image: consensys/teku:latest + - el_type: besu + el_image: hyperledger/besu:latest + cl_type: teku + cl_image: consensys/teku:latest +network_params: + preset: mainnet +additional_services: + - dora + - el_forkmon + - prometheus_grafana +snooper_enabled: true \ No newline at end of file diff --git a/test-network/nodes/node1/p2p-key.txt b/test-network/nodes/node1/p2p-key.txt deleted file mode 100644 index 4440d178e8f..00000000000 --- a/test-network/nodes/node1/p2p-key.txt +++ /dev/null @@ -1 +0,0 @@ -0x0802122100b9bf75ae758881c847f26e026fd12b41e9ba2af3d39f830dfa3e9eb18d59ed1f \ No newline at end of file diff --git a/test-network/nodes/node2/p2p-key.txt b/test-network/nodes/node2/p2p-key.txt deleted file mode 100644 index 9976e41a76a..00000000000 --- a/test-network/nodes/node2/p2p-key.txt +++ /dev/null @@ -1 +0,0 @@ -0x0802122027ed6cf375c026a762a6ca3b91765c39b72b2022f02dfea7bd36e05e37864688 \ No newline at end of file diff --git a/test-network/nodes/node3/p2p-key.txt b/test-network/nodes/node3/p2p-key.txt deleted file mode 100644 index c08609fc30c..00000000000 --- a/test-network/nodes/node3/p2p-key.txt +++ /dev/null @@ -1 +0,0 @@ -0x0802122074ca7d1380b2c407be6878669ebb5c7a2ee751bb18198f1a0f214bcb93b894b5 \ No newline at end of file diff --git a/test-network/nodes/node4/p2p-key.txt b/test-network/nodes/node4/p2p-key.txt deleted file mode 100644 index c1b3ef85e2d..00000000000 --- a/test-network/nodes/node4/p2p-key.txt +++ /dev/null @@ -1 +0,0 @@ -0x08021220468ec485aabc3c23bf742636952bf8a3ab4e7fa3cc63cfb6c1e517e40c21b25c \ No newline at end of file diff --git a/test-network/prometheus/prometheus.yml b/test-network/prometheus/prometheus.yml deleted file mode 100644 index 41336996115..00000000000 --- a/test-network/prometheus/prometheus.yml +++ /dev/null @@ -1,24 +0,0 @@ -# prometheus.yml -global: - scrape_interval: 5s - external_labels: - monitor: 'my-monitor' -scrape_configs: - - job_name: 'prometheus' - static_configs: - - targets: ['localhost:9090'] - - job_name: 'node-exporter' - static_configs: - - targets: ['node-exporter:9100'] - - job_name: 'teku1' - static_configs: - - targets: ['teku1:8008'] - - job_name: 'teku2' - static_configs: - - targets: ['teku2:8008'] - - job_name: 'teku3' - static_configs: - - targets: ['teku3:8008'] - - job_name: 'teku4' - static_configs: - - targets: ['teku4:8008'] \ No newline at end of file