From c4c9e38fb6f068e1551272f181821a0174c79189 Mon Sep 17 00:00:00 2001 From: danceratopz Date: Wed, 12 Jul 2023 10:43:40 +0100 Subject: [PATCH] Deployed dda0f6a to v1.0.1b1-refactor-4844-specs with MkDocs 1.4.3 and mike 1.1.2 --- .../library/ethereum_test_tools/index.html | 38 ++++++------ .../library/evm_transition_tool/index.html | 4 +- .../pytest_plugins/test_filler/index.html | 4 +- .../search/search_index.json | 2 +- v1.0.1b1-refactor-4844-specs/sitemap.xml.gz | Bin 932 -> 932 bytes .../berlin/eip2930_access_list/index.html | 2 +- .../eip2930_access_list/test_acl/index.html | 2 +- .../test_acl/index/test_cases/index.html | 2 +- .../tests/berlin/index.html | 2 +- .../tests/cancun/eip4844_blobs/index.html | 2 +- .../cancun/eip4844_blobs/spec/index.html | 44 +++++++------- .../eip4844_blobs/test_blob_txs/index.html | 42 ++++++------- .../test_blob_txs/index/test_cases/index.html | 2 +- .../test_blob_txs_full/index.html | 56 +++++++----------- .../index/test_cases/index.html | 2 +- .../test_blobhash_opcode/index.html | 48 +++++++-------- .../index/test_cases/index.html | 2 +- .../test_blobhash_opcode_contexts/index.html | 42 ++++++------- .../index/test_cases/index.html | 2 +- .../test_excess_data_gas/index.html | 42 ++++++------- .../index/test_cases/index.html | 2 +- .../index.html | 42 ++++++------- .../index/test_cases/index.html | 2 +- .../index.html | 26 ++++---- .../index/test_cases/index.html | 2 +- .../index.html | 28 ++++----- .../index/test_cases/index.html | 2 +- .../tests/cancun/index.html | 2 +- .../tests/frontier/index.html | 2 +- .../tests/frontier/opcodes/index.html | 2 +- .../frontier/opcodes/test_dup/index.html | 2 +- .../test_dup/index/test_cases/index.html | 2 +- .../tests/homestead/index.html | 2 +- .../tests/homestead/yul/index.html | 2 +- .../homestead/yul/test_yul_example/index.html | 2 +- .../index/test_cases/index.html | 2 +- v1.0.1b1-refactor-4844-specs/tests/index.html | 2 +- .../tests/istanbul/eip1344_chainid/index.html | 2 +- .../eip1344_chainid/test_chainid/index.html | 2 +- .../test_chainid/index/test_cases/index.html | 2 +- .../tests/istanbul/index.html | 2 +- .../tests/merge/index.html | 2 +- .../tests/merge/security/index.html | 2 +- .../test_selfdestruct_balance_bug/index.html | 2 +- .../index/test_cases/index.html | 2 +- .../shanghai/eip3651_warm_coinbase/index.html | 2 +- .../test_warm_coinbase/index.html | 2 +- .../index/test_cases/index.html | 2 +- .../tests/shanghai/eip3855_push0/index.html | 2 +- .../eip3855_push0/test_push0/index.html | 2 +- .../test_push0/index/test_cases/index.html | 2 +- .../shanghai/eip3860_initcode/index.html | 2 +- .../eip3860_initcode/test_initcode/index.html | 2 +- .../test_initcode/index/test_cases/index.html | 2 +- .../shanghai/eip4895_withdrawals/index.html | 2 +- .../test_withdrawals/index.html | 2 +- .../index/test_cases/index.html | 2 +- .../tests/shanghai/index.html | 2 +- 58 files changed, 234 insertions(+), 272 deletions(-) diff --git a/v1.0.1b1-refactor-4844-specs/library/ethereum_test_tools/index.html b/v1.0.1b1-refactor-4844-specs/library/ethereum_test_tools/index.html index 5371db544e..5fb3c32008 100644 --- a/v1.0.1b1-refactor-4844-specs/library/ethereum_test_tools/index.html +++ b/v1.0.1b1-refactor-4844-specs/library/ethereum_test_tools/index.html @@ -5867,8 +5867,8 @@

bytecode: Optional[bytes] = None - class-attribute instance-attribute + class-attribute

@@ -5894,8 +5894,8 @@

name: Optional[str] = None - class-attribute instance-attribute + class-attribute

@@ -7532,7 +7532,7 @@

- Bases: BaseTest

+ Bases: BaseTest

Filler type that tests multiple blocks (valid or invalid) in a chain.

@@ -9294,7 +9294,7 @@

- Bases: BaseTest

+ Bases: BaseTest

Filler type that tests transactions over the period of a single block.

@@ -12940,8 +12940,8 @@

overhead_cost: int = 0 - class-attribute instance-attribute + class-attribute

@@ -12967,8 +12967,8 @@

extra_stack_items: int = 0 - class-attribute instance-attribute + class-attribute

@@ -12996,8 +12996,8 @@

sstore_key: int = 0 - class-attribute instance-attribute + class-attribute

@@ -14036,8 +14036,8 @@

storage: Storage | None = None - class-attribute instance-attribute + class-attribute

@@ -14519,8 +14519,8 @@

nonce: int | None = nonce - class-attribute instance-attribute + class-attribute

@@ -14548,8 +14548,8 @@

balance: int | None = balance - class-attribute instance-attribute + class-attribute

@@ -14575,8 +14575,8 @@

code: str | bytes | Code | None = code - class-attribute instance-attribute + class-attribute

@@ -16491,8 +16491,8 @@

ty: Optional[int] = None - class-attribute instance-attribute + class-attribute

@@ -17994,8 +17994,8 @@

rlp: Optional[bytes] = None - class-attribute instance-attribute + class-attribute

@@ -18024,8 +18024,8 @@

rlp_modifier: Optional[Header] = None - class-attribute instance-attribute + class-attribute

@@ -18052,8 +18052,8 @@

exception: Optional[str] = None - class-attribute instance-attribute + class-attribute

@@ -18079,8 +18079,8 @@

engine_api_error_code: Optional[EngineAPIError] = None - class-attribute instance-attribute + class-attribute

@@ -18106,8 +18106,8 @@

txs: Optional[List[Transaction]] = None - class-attribute instance-attribute + class-attribute

@@ -18133,8 +18133,8 @@

ommers: Optional[List[Header]] = None - class-attribute instance-attribute + class-attribute

@@ -18160,8 +18160,8 @@

withdrawals: Optional[List[Withdrawal]] = None - class-attribute instance-attribute + class-attribute

diff --git a/v1.0.1b1-refactor-4844-specs/library/evm_transition_tool/index.html b/v1.0.1b1-refactor-4844-specs/library/evm_transition_tool/index.html index 48b2206f43..8ee18da905 100644 --- a/v1.0.1b1-refactor-4844-specs/library/evm_transition_tool/index.html +++ b/v1.0.1b1-refactor-4844-specs/library/evm_transition_tool/index.html @@ -3728,7 +3728,7 @@

- Bases: TransitionTool

+ Bases: TransitionTool

Go-ethereum evm Transition tool frontend wrapper class.

@@ -4356,7 +4356,7 @@

- Bases: TransitionTool

+ Bases: TransitionTool

Evmone evmone-t8n Transition tool frontend wrapper class.

diff --git a/v1.0.1b1-refactor-4844-specs/library/pytest_plugins/test_filler/index.html b/v1.0.1b1-refactor-4844-specs/library/pytest_plugins/test_filler/index.html index 1509f14314..ddced8887f 100644 --- a/v1.0.1b1-refactor-4844-specs/library/pytest_plugins/test_filler/index.html +++ b/v1.0.1b1-refactor-4844-specs/library/pytest_plugins/test_filler/index.html @@ -4403,7 +4403,7 @@

- Bases: BaseTest

+ Bases: BaseTest

Filler type that tests multiple blocks (valid or invalid) in a chain.

@@ -7003,7 +7003,7 @@

- Bases: BaseTest

+ Bases: BaseTest

Filler type that tests transactions over the period of a single block.

diff --git a/v1.0.1b1-refactor-4844-specs/search/search_index.json b/v1.0.1b1-refactor-4844-specs/search/search_index.json index 75231c0040..5809e7edba 100644 --- a/v1.0.1b1-refactor-4844-specs/search/search_index.json +++ b/v1.0.1b1-refactor-4844-specs/search/search_index.json @@ -1 +1 @@ -{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Execution Spec Tests","text":"

ethereum/execution-spec-tests is both a collection of test cases and a framework in Python to generate tests for Ethereum execution clients implemented.

The framework collects and executes the test cases in order to generate test fixtures (JSON) which can be consumed by any execution client to verify their implementation of ethereum/execution-specs. Currently, the fixtures, which define state transition and block tests, are generated by the framework using the t8n command from the ethereum/go-ethereum evm command-line tool. Integration of other t8n tools is planned.

---\ntitle: Test Fixture Generation with execution-spec-tests\n---\nflowchart LR\n  style C stroke:#333,stroke-width:2px\n  style D stroke:#333,stroke-width:2px\n  style G stroke:#F9A825,stroke-width:2px\n  style H stroke:#F9A825,stroke-width:2px\n\n  subgraph ethereum/go-ethereum\n    C[<code>evm t8n</code>\\nexternal executable]\n  end\n\n  subgraph ethereum/solidity\n    D[<code>solc</code>\\nexternal executable]\n  end\n\n  subgraph ethereum/EIPs\n    E(<code>EIPS/EIP-*.md</code>\\nSHA digest via Github API)\n  end\n\n  subgraph \"ethereum/execution-spec-tests\"\n    A(<code>./tests/**/*.py</code>\\nPython Test Cases)\n    B([<code>$ fill ./tests/</code>\\nPython Framework])\n  end\n\n  subgraph Test Fixture Consumers\n    subgraph ethereum/hive\n      G([<code>$ hive ...</code>\\nGo Test Framework])\n    end\n    H([Client executables])\n  end\n\n  C <-.-> B  \n  D <-.-> B\n  A --> B\n  E <-.-> |retrieve latest spec version\\ncheck tested spec version| B\n  B -->|output| F(<code>./fixtures/**/*.json</code>\\nJSON Test Fixtures)\n  F -->|input| G\n  F -->|input| H

The generated test fixtures can be used:

  1. Directly by client teams' test frameworks, and,
  2. In the integration tests executed in the ethereum/hive framework.
"},{"location":"#relationship-to-ethereumtests","title":"Relationship to ethereum/tests","text":"

This collection of tests is relatively new (test case development started Q4, 2022) and mainly targets recent and upcoming Ethereum specification changes. It does not replace, but rather complements the existing tests in ethereum/tests.

"},{"location":"#motivation","title":"Motivation","text":"

The motivation to implement test cases in ethereum/execution-spec-tests is:

  1. To implement test cases as code and ensure that changes, due to spec changes, for example, can be easily made. Moreover, changes are easily understandable and available in version control.
  2. To avoid the 2-step approach often used in ethereum/tests:
    1. Code (often unavailable) -> Test case (YAML).
    2. Test case (YAML) -> Fixtures (JSON).

Contributing

Contributions via PR are welcome!

"},{"location":"navigation/","title":"Navigation","text":"
  • Overview
  • Getting Started
    • Quick Start
    • VS Code Setup
    • Repository Overview
    • Executing Tests at a Prompt
    • Executing Tests in VS Code
    • Executing Tests for Features Under Development
  • Writing Tests
    • Code Standards
    • Types of Test
    • Adding a New Test
    • Writing a New Test
    • Referencing an EIP Spec Version
    • Verifying Changes Locally
  • Tutorials
    • State Transition Tests
  • Getting Help
  • Developer Doc
    • Documentation
    • Coding Style
  • Library Reference
    • EVM Transition Tool Package
    • Ethereum Test Tools Package
    • Ethereum Test Forks Package
    • Pytest Plugins
  • Test case reference
    • Cancun
      • EIP-4844 Blobs
        • Spec
        • Test Blob Txs
          • Test Cases
        • Test Blob Txs Full
          • Test Cases
        • Test Blobhash Opcode
          • Test Cases
        • Test Blobhash Opcode Contexts
          • Test Cases
        • Test Excess Data Gas
          • Test Cases
        • Test Excess Data Gas Fork Transition
          • Test Cases
        • Test Point Evaluation Precompile
          • Test Cases
        • Test Point Evaluation Precompile Gas
          • Test Cases
        • Point Evaluation Vectors
          • Readme
    • Shanghai
      • EIP-3651 Warm Coinbase
        • Test Warm Coinbase
          • Test Cases
      • EIP-3855 Push0
        • Test Push0
          • Test Cases
      • EIP-3860 Initcode
        • Test Initcode
          • Test Cases
      • EIP-4895 Withdrawals
        • Test Withdrawals
          • Test Cases
    • Merge
      • Security
        • Test Selfdestruct Balance Bug
          • Test Cases
    • Berlin
      • EIP-2930 Access List
        • Test ACL
          • Test Cases
    • Istanbul
      • EIP-1344 CHAINID
        • Test CHAINID
          • Test Cases
    • Homestead
      • Yul
        • Test Yul Example
          • Test Cases
    • Frontier
      • Opcodes
        • Test DUP
          • Test Cases
"},{"location":"dev/","title":"Developer Documentation","text":"

This documentation is aimed at maintainers of execution-spec-tests but may be helpful during test case development:

  • generating documentation.
  • coding style.
  • enabling pre-commit checks.
"},{"location":"dev/coding_style/","title":"Coding Style","text":""},{"location":"dev/coding_style/#formatting-and-line-length","title":"Formatting and Line Length","text":"

The Python code in execution-spec-tests is black formatted with a maximum line length of 100. Using VS Code with editor.formatOnSave is a big help to ensure files conform to the repo's coding style, see VS Code Setup to configure this and other useful settings.

"},{"location":"dev/coding_style/#ignoring-bulk-change-commits","title":"Ignoring Bulk Change Commits","text":"

The max line length was changed from 80 to 100 in Q2 2023. To ignore this bulk change commit in git blame output, use the .git-blame-ignore-revs file, for example:

git blame --ignore-revs-file .git-blame-ignore-revs docs/gen_test_case_reference.py\n

To use the revs file persistently with git blame, run

git config blame.ignoreRevsFile .git-blame-ignore-revs\n
"},{"location":"dev/docs/","title":"Documentation","text":"

The execution-spec-tests documentation is generated via mkdocs and hosted remotely on Github Pages at ethereum.github.io/execution-spec-tests.

"},{"location":"dev/docs/#prerequisites","title":"Prerequisites","text":"
pip install -e .[docs]\n
"},{"location":"dev/docs/#build-the-documentation","title":"Build the Documentation","text":"

One time build:

mkdocs build\n

Pre-commit check: One time build and lint/type checking:

tox -e docs\n
"},{"location":"dev/docs/#local-deployment-and-test","title":"Local Deployment and Test","text":"

This runs continually: Deploys the site locally and re-generates the site upon modifications to docs/**/*.md or tests/**/*.py:

mkdocs serve\n
"},{"location":"dev/docs/#remote-deployment-and-versioning","title":"Remote Deployment and Versioning","text":"

The execution-specs-test docs are hosted on Github pages at the repo's Github pages. Versions are updated/deployed automatically as part of Github Actions, but this can also be performed on the command-line.

Our mkdocs configuration uses mike as a version provider. All deployments should be made via mike (whether as part of CI/CD or executed locally).

The deployed versions of the docs managed via mike are kept in the gh-pages branch. When you run mike it commits to this branch and optionally pushes the changes directly to remote.

"},{"location":"dev/docs/#aliases","title":"Aliases","text":"

We currently use two aliases:

  • latest: the latest stable release.
  • development: the current state of the main branch.

These aliases point to specific versions, as configured below. It's possible to share links containing either of these aliases or to specific versions, i.e, the following are all valid links:

  • https://ethereum.github.io/execution-spec-tests/ (redirects to latest/main)
  • https://ethereum.github.io/execution-spec-tests/latest (redirects to main)
  • https://ethereum.github.io/execution-spec-tests/development (redirects to tagged version)
  • https://ethereum.github.io/execution-spec-tests/main
  • https://ethereum.github.io/execution-spec-tests/v1.0.0
"},{"location":"dev/docs/#cicd-doc-deployment-via-github-actions","title":"CI/CD: Doc Deployment via Github Actions","text":"

There are two workflows that automatically deploy updated/new versions of the docs:

| Workflow yaml File | What | When | |-----------------_____|------|------| | docs_main.yaml | Update \"main\" version of docs | Push to 'main' branch, (e.g., on PR merge) | | docs_tags.yaml | Deploy new version of docs; tag is used as version name | Upon creating a tag matching v* |

"},{"location":"dev/docs/#build-and-deployment-without-alias-update","title":"Build and Deployment (without alias update)","text":"

Build a new version and deploy it to remote (this version will then show up in the version selector list):

mike deploy --push v1.2.3\n

Local deployment

If you deploy locally, the documentation will be built with any changes made in your local repository. Check out the tag to deploy tagged versions.

"},{"location":"dev/docs/#build-deploy-and-update-the-alias","title":"Build, Deploy and Update the Alias","text":"

Build, deploy and update the version an alias points to with:

mike deploy --push --update-aliases v1.2.3 latest\n

where v1.2.3 indicates the version's name and development is the alias. This will overwrite the version if it already exists.

Updating the 'main' version locally

\"main\" is just a version name (intended to reflect that it is build from the main branch). However, mike will build the docs site from the current local repository state (including local modifications). Therefore, make sure you're on the HEAD of the main branch before executing (unless you know what you're doing )!

mike deploy --push main\n

If the alias accidentally go change:

mike deploy --push --update-aliases main development\n
"},{"location":"dev/docs/#viewing-and-deleting-versions","title":"Viewing and Deleting Versions","text":"

List versions:

mike list\n

Delete a version:

mike delete v1.2.3a1-eof\n
"},{"location":"dev/docs/#set-default-version","title":"Set Default Version","text":"

Set the default version of the docs to open upon loading the page:

mike set-default --push latest\n

Typically, this must only be executed once for a repo.

"},{"location":"dev/docs/#implementation","title":"Implementation","text":""},{"location":"dev/docs/#plugins","title":"Plugins","text":"

The documentation flow uses mkdocs and the following additional plugins:

  • mkdocs: The main doc generation tool.
  • mkdocs-material: Provides many additional features and styling for mkdocs.
  • mkdocstrings and mkdocstrings-python: To generate documentation from Python docstrings.
  • mkdocs-gen-files: To generate markdown files automatically for each test case Python module. See this page for example usage. This plugin is used to programmatically generate the nav section for the generated test case reference documentation.
  • mkdocs-literate-nav: Is used to define the navigation layout for non-generated content and was created to work well with mkdocs-gen-files to add nav content for generated content.
  • blueswen/mkdocs-glightbox - for improved image and inline content display.
"},{"location":"dev/docs/#the-test-case-reference-section","title":"The \"Test Case Reference\" Section","text":"

This section is auto-generated via a combination of:

  1. mkdocstrings and mkdocstrings-python,
  2. mkdocs-gen-files,
  3. mkdocs-literate-nav.

It auto-generates a sequence of nested pages (with nav entries) of all python modules detected under ./tests. Each page contains a stub to the doc generated by mkdocstrings from the module's docstrings and source code. The mkdocs-gen-files and mkdocs-literate-nav plugins were created exactly for this purpose.

No action is necessary if a new test directory or module is added to ./tests, it will be picked up automatically.

Working with generated content

The files in the ./tests directory are watched by mkdocs serve. Run mkdocs serve and edit the source docstrings: The browser will reload with the new content automatically.

"},{"location":"dev/docs/#navigation","title":"Navigation","text":"

All pages that are to be included in the documentation and the navigation bar must be included in navigation.md, except \"Test Case Reference\" entries. This is enabled by mkdocs-literate-nav. The nav entries for the automatically generated \"Test Case Reference\" section are generated in mkdocs-gen-files and appended to navigation.md.

Current nav ordering limitations

The \"Test Case Reference\" section must currently be the last section in the nav. This is because our mkdocs flow:

  1. Reads navigation.md.
  2. Generates the Test Case Reference documentation and appends the Test Case Reference entries to navigation.md
  3. Generates the nav.

If necessary, we could probably split navigation.md into two files

  • navigation-pre-test-case-reference.md,
  • navigation-post-test-case-reference.md,

and create an arbitrary ordering in the Test Case Reference doc gen script. But this is untested.

"},{"location":"dev/docs/#read-the-docs","title":"Read the Docs","text":"

Originally, documentation was hosted at [readthedocs.io]. Currently, execution-spec-tests.readthedocs.io is configured to redirect to the Github Pages site. This is achieved by following the steps listed in the second half of this answer on stackoverflow. A public repo with dummy Sphinx project is required to achieve this: danceratopz/est-docs-redirect.

"},{"location":"dev/precommit/","title":"Enabling Pre-Commit Checks","text":"

There's a pre-commit config file available in the repository root (.pre-commit-config.yaml) that can be used to enable automatic checks upon commit - the commit will not go through if the checks don't pass.

To enable pre-commit, the following must be ran once:

pip install pre-commit\npre-commit install\n

Bypassing pre-commit checks

Enabling of pre-commit checks is not mandatory (it cannot be enforced) and even if it is enabled, it can always be bypassed with:

git commit --no-verify\n
"},{"location":"getting_help/","title":"Getting Help","text":"

The tests in this repository are a community effort to help improve the development cycle of all Ethereum execution clients.

We encourage contributions and recognize that Python is not everyone's primary language - if you stumble over issues or need help, please reach out to one of the execution-spec-tests maintainers either directly or in the #testing channel in the Ethereum R&D Discord Server.

"},{"location":"getting_help/#contact-the-maintainers","title":"Contact the Maintainers","text":"

Write to:

  • Dan on Discord or Telegram (danceratopz).
  • Spencer on Discord or Telegram (spencertaylorbrown/@spencertb).
  • Mario on Discord or Telegram (marioevz/@marioevz).

"},{"location":"getting_started/executing_tests_command_line/","title":"Executing Tests at a Prompt","text":"

The execution-spec-tests test framework uses the pytest framework for test case collection and execution. The fill command is essentially an alias for pytest, which uses several custom pytest plugins to run transition tools against test cases and generate JSON fixtures.

Options specific to execution-spec-tests

The command-line options specific to filling tests can be listed via:

fill --test-help\n

See Custom fill Command-Line Options for all options.

"},{"location":"getting_started/executing_tests_command_line/#collection-test-exploration","title":"Collection - Test Exploration","text":"

The test cases implemented in the ./tests sub-directory can be listed in the console using:

fill --collect-only\n

and can be filtered (by test path, function and parameter substring):

fill --collect-only -k warm_coinbase\n

Docstrings are additionally displayed when ran verbosely:

fill --collect-only -k warm_coinbase -vv\n
"},{"location":"getting_started/executing_tests_command_line/#execution","title":"Execution","text":"

By default, test cases are executed for all forks already deployed to mainnet, but not for forks still under active development, i.e., as of time of writing, Q2 2023:

fill\n

will generate fixtures for test cases from Frontier to Shanghai.

To generate all the test fixtures defined in the ./tests/shanghai sub-directory and write them to the ./fixtures-shanghai directory, run fill in the top-level directory as:

fill ./tests/shanghai --output=\"fixtures-shanghai\"\n

Test case verification

Note, that the (limited set of) test post conditions are tested against the output of the evm t8n command during test generation.

To generate all the test fixtures in the tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase.py module, for example, run:

fill tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase.py\n

To generate specific test fixtures from a specific test function or even test function and parameter set, obtain the corresponding test ID using:

fill --collect-only -q -k test_warm_coinbase\n

This filters the tests by test_warm_coinbase. Then find the relevant test ID in the console output and provide it to fill, for example, for a test function:

fill tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase.py::test_warm_coinbase_gas_usage\n

or, for a test function and specific parameter combination:

fill tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase.py::test_warm_coinbase_gas_usage[fork=Merge-DELEGATECALL]\n
"},{"location":"getting_started/executing_tests_command_line/#execution-for-development-forks","title":"Execution for Development Forks","text":"

By default, test cases are not executed with upcoming Ethereum forks so that they can be readily executed against the evm tool from the latest geth release.

In order to execute test cases for an upcoming fork, ensure that the evm tool used supports that fork and features under test and use the --until or --fork flag.

For example, as of Q2 2023, the current fork under active development is Cancun:

fill --until Cancun\n

See: Executing Tests for Features under Development.

"},{"location":"getting_started/executing_tests_command_line/#other-useful-pytest-command-line-options","title":"Other Useful Pytest Command-Line Options","text":"
fill -vv            # More verbose output\nfill -x             # Exit instantly on first error or failed test case\nfill --pdb          # Drop into the debugger upon error in a test case\n
"},{"location":"getting_started/executing_tests_command_line/#custom-fill-command-line-options","title":"Custom fill Command-Line Options","text":"

Options added by the execution-spec-tests pytest plugins can be listed with:

fill --test-help\n

Output:

usage: fill [-h] [--evm-bin EVM_BIN] [--traces TRACES] [--solc-bin SOLC_BIN]\n            [--filler-path FILLER_PATH] [--output OUTPUT]\n            [--flat-output FLAT_OUTPUT] [--forks FORKS] [--fork FORK]\n            [--from FROM] [--until UNTIL] [--test-help TEST_HELP]\n\noptions:\n  -h, --help            show this help message and exit\n\nArguments defining evm executable behavior:\n  --evm-bin EVM_BIN     Path to an evm executable that provides `t8n` and\n                        `b11r.` Default: First 'evm' entry in PATH\n  --traces TRACES       Collect traces of the execution information from the\n                        transition tool\n\nArguments defining the solc executable:\n  --solc-bin SOLC_BIN   Path to a solc executable (for Yul source compilation).\n                        Default: First 'solc' entry in PATH\n\nArguments defining filler location and output:\n  --filler-path FILLER_PATH\n                        Path to filler directives\n  --output OUTPUT       Directory to store the generated test fixtures. Can be\n                        deleted.\n  --flat-output FLAT_OUTPUT\n                        Output each test case in the directory without the\n                        folder structure.\n\nSpecify the fork range to generate fixtures for:\n  --forks FORKS         Display forks supported by the test framework and exit.\n  --fork FORK           Only fill tests for the specified fork.\n  --from FROM           Fill tests from and including the specified fork.\n  --until UNTIL         Fill tests until and including the specified fork.\n\nArguments related to running execution-spec-tests:\n  --test-help TEST_HELP\n                        Only show help options specific to execution-spec-tests\n                        and exit.\n\nExit: After displaying help.\n
"},{"location":"getting_started/executing_tests_dev_fork/","title":"Executing Tests for Features under Development","text":""},{"location":"getting_started/executing_tests_dev_fork/#requirements","title":"Requirements","text":"

By default, execution-spec-tests only generates fixtures for forks that have been deployed to mainnet. In order to generate fixtures for evm features that are actively under development:

  1. A version of the evm and solc tools that implement the feature must be available (although, typically only a developer version of the evm tool is required, usually the latest stable release of solc is adequate), and,
  2. The development fork to test must be explicitly specified on the command-line:

    via the --fork flagvia the --from flagvia the --until flag
    fill -k 4844 --fork=Cancun -v\n
    fill -k 4844 --from=Cancun -v\n
    fill -k 4844 --until=Cancun -v\n

Specifying the evm binary via evm-bin

It is possible to explicitly specify the evm binary used to generate fixtures via the --evm-bin flag, for example,

fill --fork=Cancun --evm-bin=/opt/bin/evm -v\n

"},{"location":"getting_started/executing_tests_dev_fork/#further-help","title":"Further Help","text":"
  1. geth/evm build documentation.
  2. solc build documentation.

Verifying evm and solc versions used

The versions used to generate fixtures are displayed in the console output:

"},{"location":"getting_started/executing_tests_dev_fork/#vs-code-setup","title":"VS Code Setup","text":"

By default, VS Code's Testing View will only show tests for stable forks. To show tests for development forks, uncomment the relevant line in the python.testing.pytestArgs configuration section of included settings file (.vscode/settings.json) to enable the --until=FORK flag. See VS Code Setup for help finding the settings files.

"},{"location":"getting_started/executing_tests_vs_code/","title":"Executing Tests in VS Code","text":"

Prerequisite: VS Code Setup.

"},{"location":"getting_started/executing_tests_vs_code/#exploring-test-cases","title":"Exploring Test Cases","text":"

Implemented test cases can be explored in VS Code's \"Testing\" View; click on the conical flask highlighted in the screenshot below.

Testing EVM Features Under Active Development

See the VS Code section in Executing Tests for Features under Development to explore tests targeting EVM features under development.

"},{"location":"getting_started/executing_tests_vs_code/#executing-and-debugging-test-cases","title":"Executing and Debugging Test Cases","text":""},{"location":"getting_started/quick_start/","title":"Quick Start","text":"

Testing features under active development

The EVM features under test must be implemented in the evm tool and solc executables that are used by the execution-spec-tests framework. The following guide installs stable versions of these tools.

To test features under active development, start with this base configuration and then follow the steps in executing tests for features under development.

The following requires a Python 3.10 or Python 3.11 installation.

  1. Ensure go-ethereum's evm tool and solc are in your path. Either build the required versions, or alternatively:

    UbuntumacosWindows

    sudo add-apt-repository -y ppa:ethereum/ethereum\nsudo apt-get update\nsudo apt-get install ethereum solc\n
    More help:

    • geth installation doc.
    • solc installation doc.

    brew update\nbrew upgrade\nbrew tap ethereum/ethereum\nbrew install ethereum solidity\n
    More help:

    • geth installation doc.
    • solc installation doc.

    Binaries available here:

    • geth (binary or installer).
    • solc.

    More help:

    • geth installation doc.
    • solc static binaries doc.
  2. Clone the execution-spec-tests repo and install its and dependencies (it's recommended to use a virtual environment for the installation):

    git clone https://github.com/ethereum/execution-spec-tests\ncd execution-spec-tests\npython3 -m venv ./venv/\nsource ./venv/bin/activate\npip install -e .[docs,lint,test]\n

  3. Verify installation:

    1. Explore test cases:
    2. console fill --collect-only

    Expected console output: 3. Execute the test cases (verbosely) in the ./tests/berlin/eip2930_access_list/test_acl.py module:

    fill -v tests/berlin/eip2930_access_list/test_acl.py\n
    Expected console output:

    Check:

    1. The versions of the evm and solc tools are as expected (your versions may differ from those in the highlighted box).
    2. The corresponding fixture file has been generated:

      head fixtures/berlin/eip2930_access_list/acl/access_list.json\n
"},{"location":"getting_started/quick_start/#next-steps","title":"Next Steps","text":"
  1. Learn useful command-line flags.
  2. Execute tests for features under development via the --fork flag.
  3. Optional: Configure VS Code to auto-format Python code and execute tests within VS Code.
  4. Implement a new test case, see Writing Tests.
"},{"location":"getting_started/repository_overview/","title":"Repository Overview","text":"

The most relevant folders and file in the repo are:

\ud83d\udcc1 execution-test-specs/\n\u251c\u2500\u2574\ud83d\udcc1 tests/                     # test cases\n\u2502   \u251c\u2500\u2500 \ud83d\udcc1 eips/\n\u2502   \u251c\u2500\u2500 \ud83d\udcc1 vm/\n\u2502   \u2514\u2500\u2500 \ud83d\udcc1 ...\n\u251c\u2500\u2574\ud83d\udcc1 fixtures/                  # default fixture output dir\n\u2502   \u251c\u2500\u2500 \ud83d\udcc1 eips/\n\u2502   \u251c\u2500\u2500 \ud83d\udcc1 vm/\n\u2502   \u2514\u2500\u2500 \ud83d\udcc1 ...\n\u251c\u2500\u2574\ud83d\udcc1 src/                       # library & framework packages\n\u2502   \u251c\u2500\u2500 \ud83d\udcc1 ethereum_test_fork/\n\u2502   \u251c\u2500\u2500 \ud83d\udcc1 ethereum_test_tools/\n\u2502   \u2514\u2500\u2500 \ud83d\udcc1 ...\n\u251c\u2500\u2574\ud83d\udcc1 docs/                      # markdown documentation\n\u2502   \u251c\u2500\u2500 \ud83d\udcc1 getting_started\n\u2502   \u251c\u2500\u2500 \ud83d\udcc1 dev\n\u2502   \u2514\u2500\u2500 \ud83d\udcc1 ...\n\u251c\u2500\u2574\ud83d\udcc1 .vscode/                   # visual studio code config\n\u2502   \u251c\u2500\u2500 \ud83d\udcc4 settings.recommended.json # copy to settings.json\n\u2502   \u251c\u2500\u2500 \ud83d\udcc4 launch.recommended.json\n\u2502   \u2514\u2500\u2500 \ud83d\udcc4 extensions.json\n\u2514\u2500\u2500 \ud83d\udcc4 whitelist.txt             # spellcheck dictionary\n

"},{"location":"getting_started/repository_overview/#tests","title":"tests/","text":"

Contains the implementation of the Ethereum consensus tests available in this repository.

"},{"location":"getting_started/repository_overview/#src","title":"src/","text":"

Contains various packages that help to define test cases and to interface with the evm t8n command. Additionally, it contains some packages that enable test case execution by customizing pytest which acts as the test framework.

"},{"location":"getting_started/repository_overview/#docs","title":"docs/","text":"

Contains documentation configuration and source files.

"},{"location":"getting_started/repository_overview/#vscode","title":".vscode/","text":"

See VS Code Setup.

"},{"location":"getting_started/setup_vs_code/","title":"VS Code Setup","text":"

VS Code setup is optional, but does offer the following advantages:

  • Auto-format your Python code to conform to the repository's code standards (black).
  • Inline linting and auto-completion (thanks to Python type hints).
  • Spell-check your code and docs.
  • Graphical exploration of test cases and easy test execution/debug.
"},{"location":"getting_started/setup_vs_code/#installation","title":"Installation","text":"

Please refer to the Visual Studio Code docs for help with installation.

"},{"location":"getting_started/setup_vs_code/#vs-code-settings-file","title":"VS Code Settings file","text":"

The ethereum/execution-spec-tests repo includes configuration files for VS Code in the .vscode/ sub-directory:

\ud83d\udcc1 execution-test-specs/\n\u2514\u2500\u2500\ud83d\udcc1 .vscode/\n    \u251c\u2500\u2500 \ud83d\udcc4 settings.recommended.json\n    \u251c\u2500\u2500 \ud83d\udcc4 extensions.json\n    \u2514\u2500\u2500 \ud83d\udcc4 launch.recommended.json\n

To enable the recommended settings, copy the settings file to the expected location:

cp .vscode/settings.recommended.json .vscode/settings.json\n

To additionally enable the recommended launch configurations:

cp .vscode/launch.recommended.json .vscode/launch.json\n
"},{"location":"getting_started/setup_vs_code/#additional-vs-code-extensions","title":"Additional VS Code Extensions","text":"

Open the folder in VS Code where execution-spec-tests is cloned: VS Code should prompt to install the repository's required extensions from .vscode/extensions.json:

  • ms-python.python
  • ms-python.isort
  • ms-python.flake8
  • ms-python.black-formatter
  • esbenp.prettier-vscode
  • streetsidesoftware.code-spell-checker
  • tamasfe.even-better-toml

Workspace Trust

Trust the execution-specs-test repository when opening in VS Code to be prompted to install the plugins recommended via the extensions.json file.

"},{"location":"getting_started/setup_vs_code/#configuration-for-testing-evm-features-under-active-development","title":"Configuration for Testing EVM Features Under Active Development","text":"

An additional step is required to enable fixture generations for features from forks that are under active development and have not been deployed to mainnet, see Executing Tests for Features under Development.

"},{"location":"library/","title":"Library (Tools) Reference Documentation","text":"

Execution spec tests consists of several packages that implement helper classes and tools that enable and simplify test case implementation. This section contains their reference documentation:

  • evm_transition_tool - a wrapper for the transition (t8n) tool.
  • ethereum_test_tools - provides primitives and helpers to test Ethereum execution clients.
  • ethereum_test_forks - provides definitions for supported forks used in tests.
  • pytest_plugins - contains pytest customizations that provide additional functionality for generating test fixtures.
"},{"location":"library/ethereum_test_forks/","title":"Ethereum Test Forks package","text":"

Ethereum test fork definitions.

"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.Frontier","title":"Frontier","text":"

Bases: BaseFork

Frontier fork

Source code in src/ethereum_test_forks/forks/forks.py
class Frontier(BaseFork):\n\"\"\"\n    Frontier fork\n    \"\"\"\n\n    @classmethod\n    def header_base_fee_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n        At genesis, header must not contain base fee\n        \"\"\"\n        return False\n\n    @classmethod\n    def header_prev_randao_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n        At genesis, header must not contain Prev Randao value\n        \"\"\"\n        return False\n\n    @classmethod\n    def header_zero_difficulty_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n        At genesis, header must not have difficulty zero\n        \"\"\"\n        return False\n\n    @classmethod\n    def header_withdrawals_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n        At genesis, header must not contain withdrawals\n        \"\"\"\n        return False\n\n    @classmethod\n    def header_excess_data_gas_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n        At genesis, header must not contain excess data gas\n        \"\"\"\n        return False\n\n    @classmethod\n    def header_data_gas_used_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n        At genesis, header must not contain data gas used\n        \"\"\"\n        return False\n\n    @classmethod\n    def engine_new_payload_version(cls, block_number: int, timestamp: int) -> Optional[int]:\n\"\"\"\n        At genesis, payloads cannot be sent through the engine API\n        \"\"\"\n        return None\n\n    @classmethod\n    def engine_new_payload_blob_hashes(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n        At genesis, payloads do not have blob hashes.\n        \"\"\"\n        return False\n\n    @classmethod\n    def get_reward(cls, block_number: int, timestamp: int) -> int:\n\"\"\"\n        At Genesis the expected reward amount in wei is\n        5_000_000_000_000_000_000\n        \"\"\"\n        return 5_000_000_000_000_000_000\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.Frontier.header_base_fee_required","title":"header_base_fee_required(block_number, timestamp) classmethod","text":"

At genesis, header must not contain base fee

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef header_base_fee_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n    At genesis, header must not contain base fee\n    \"\"\"\n    return False\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.Frontier.header_prev_randao_required","title":"header_prev_randao_required(block_number, timestamp) classmethod","text":"

At genesis, header must not contain Prev Randao value

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef header_prev_randao_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n    At genesis, header must not contain Prev Randao value\n    \"\"\"\n    return False\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.Frontier.header_zero_difficulty_required","title":"header_zero_difficulty_required(block_number, timestamp) classmethod","text":"

At genesis, header must not have difficulty zero

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef header_zero_difficulty_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n    At genesis, header must not have difficulty zero\n    \"\"\"\n    return False\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.Frontier.header_withdrawals_required","title":"header_withdrawals_required(block_number, timestamp) classmethod","text":"

At genesis, header must not contain withdrawals

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef header_withdrawals_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n    At genesis, header must not contain withdrawals\n    \"\"\"\n    return False\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.Frontier.header_excess_data_gas_required","title":"header_excess_data_gas_required(block_number, timestamp) classmethod","text":"

At genesis, header must not contain excess data gas

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef header_excess_data_gas_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n    At genesis, header must not contain excess data gas\n    \"\"\"\n    return False\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.Frontier.header_data_gas_used_required","title":"header_data_gas_used_required(block_number, timestamp) classmethod","text":"

At genesis, header must not contain data gas used

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef header_data_gas_used_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n    At genesis, header must not contain data gas used\n    \"\"\"\n    return False\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.Frontier.engine_new_payload_version","title":"engine_new_payload_version(block_number, timestamp) classmethod","text":"

At genesis, payloads cannot be sent through the engine API

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef engine_new_payload_version(cls, block_number: int, timestamp: int) -> Optional[int]:\n\"\"\"\n    At genesis, payloads cannot be sent through the engine API\n    \"\"\"\n    return None\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.Frontier.engine_new_payload_blob_hashes","title":"engine_new_payload_blob_hashes(block_number, timestamp) classmethod","text":"

At genesis, payloads do not have blob hashes.

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef engine_new_payload_blob_hashes(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n    At genesis, payloads do not have blob hashes.\n    \"\"\"\n    return False\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.Frontier.get_reward","title":"get_reward(block_number, timestamp) classmethod","text":"

At Genesis the expected reward amount in wei is 5_000_000_000_000_000_000

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef get_reward(cls, block_number: int, timestamp: int) -> int:\n\"\"\"\n    At Genesis the expected reward amount in wei is\n    5_000_000_000_000_000_000\n    \"\"\"\n    return 5_000_000_000_000_000_000\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.BerlinToLondonAt5","title":"BerlinToLondonAt5","text":"

Bases: Berlin

Berlin to London transition at Block 5 fork

Source code in src/ethereum_test_forks/forks/transition.py
@transition_fork(to_fork=London)\nclass BerlinToLondonAt5(Berlin):\n\"\"\"\n    Berlin to London transition at Block 5 fork\n    \"\"\"\n\n    @classmethod\n    def header_base_fee_required(cls, block_number: int, _: int) -> bool:\n\"\"\"\n        Base Fee is required starting from London.\n        \"\"\"\n        return block_number >= 5\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.transition.BerlinToLondonAt5.header_base_fee_required","title":"header_base_fee_required(block_number, _) classmethod","text":"

Base Fee is required starting from London.

Source code in src/ethereum_test_forks/forks/transition.py
@classmethod\ndef header_base_fee_required(cls, block_number: int, _: int) -> bool:\n\"\"\"\n    Base Fee is required starting from London.\n    \"\"\"\n    return block_number >= 5\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.InvalidForkError","title":"InvalidForkError","text":"

Bases: Exception

Invalid fork error raised when the fork specified by command-line option --latest-fork is not found.

Source code in src/ethereum_test_forks/helpers.py
class InvalidForkError(Exception):\n\"\"\"\n    Invalid fork error raised when the fork specified by command-line option\n    --latest-fork is not found.\n    \"\"\"\n\n    def __init__(self, message):\n        super().__init__(message)\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.get_forks","title":"get_forks()","text":"

Returns a list of all the fork classes implemented by ethereum_test_forks ordered chronologically by deployment.

Source code in src/ethereum_test_forks/helpers.py
def get_forks() -> List[Fork]:\n\"\"\"\n    Returns a list of all the fork classes implemented by\n    `ethereum_test_forks` ordered chronologically by deployment.\n    \"\"\"\n    all_forks: List[Fork] = []\n    for fork_name in forks.__dict__:\n        fork = forks.__dict__[fork_name]\n        if not isinstance(fork, type):\n            continue\n        if issubclass(fork, BaseFork) and fork is not BaseFork:\n            all_forks.append(fork)\n    return all_forks\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.MergeToShanghaiAtTime15k","title":"MergeToShanghaiAtTime15k","text":"

Bases: Merge

Merge to Shanghai transition at Timestamp 15k fork

Source code in src/ethereum_test_forks/forks/transition.py
@transition_fork(to_fork=Shanghai)\nclass MergeToShanghaiAtTime15k(Merge):\n\"\"\"\n    Merge to Shanghai transition at Timestamp 15k fork\n    \"\"\"\n\n    @classmethod\n    def header_withdrawals_required(cls, _: int, timestamp: int) -> bool:\n\"\"\"\n        Withdrawals are required starting from Shanghai.\n        \"\"\"\n        return timestamp >= 15_000\n\n    @classmethod\n    def engine_new_payload_version(cls, block_number: int, timestamp: int) -> Optional[int]:\n\"\"\"\n        Starting at Shanghai, new payload calls must use version 2\n        \"\"\"\n        return 2 if timestamp >= 15_000 else 1\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.transition.MergeToShanghaiAtTime15k.header_withdrawals_required","title":"header_withdrawals_required(_, timestamp) classmethod","text":"

Withdrawals are required starting from Shanghai.

Source code in src/ethereum_test_forks/forks/transition.py
@classmethod\ndef header_withdrawals_required(cls, _: int, timestamp: int) -> bool:\n\"\"\"\n    Withdrawals are required starting from Shanghai.\n    \"\"\"\n    return timestamp >= 15_000\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.transition.MergeToShanghaiAtTime15k.engine_new_payload_version","title":"engine_new_payload_version(block_number, timestamp) classmethod","text":"

Starting at Shanghai, new payload calls must use version 2

Source code in src/ethereum_test_forks/forks/transition.py
@classmethod\ndef engine_new_payload_version(cls, block_number: int, timestamp: int) -> Optional[int]:\n\"\"\"\n    Starting at Shanghai, new payload calls must use version 2\n    \"\"\"\n    return 2 if timestamp >= 15_000 else 1\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.get_deployed_forks","title":"get_deployed_forks()","text":"

Returns a list of all the fork classes implemented by ethereum_test_forks that have been deployed to mainnet, chronologically ordered by deployment.

Source code in src/ethereum_test_forks/helpers.py
def get_deployed_forks():\n\"\"\"\n    Returns a list of all the fork classes implemented by `ethereum_test_forks`\n    that have been deployed to mainnet, chronologically ordered by deployment.\n    \"\"\"\n    return [fork for fork in get_forks() if fork.is_deployed()]\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.get_development_forks","title":"get_development_forks()","text":"

Returns a list of all the fork classes implemented by ethereum_test_forks that have been not yet deployed to mainnet and are currently under development. The list is ordered by their planned deployment date.

Source code in src/ethereum_test_forks/helpers.py
def get_development_forks():\n\"\"\"\n    Returns a list of all the fork classes implemented by `ethereum_test_forks`\n    that have been not yet deployed to mainnet and are currently under\n    development. The list is ordered by their planned deployment date.\n    \"\"\"\n    return [fork for fork in get_forks() if not fork.is_deployed()]\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.ShanghaiToCancunAtTime15k","title":"ShanghaiToCancunAtTime15k","text":"

Bases: Shanghai

Shanghai to Cancun transition at Timestamp 15k

Source code in src/ethereum_test_forks/forks/transition.py
@transition_fork(to_fork=Cancun)\nclass ShanghaiToCancunAtTime15k(Shanghai):\n\"\"\"\n    Shanghai to Cancun transition at Timestamp 15k\n    \"\"\"\n\n    @classmethod\n    def header_excess_data_gas_required(cls, _: int, timestamp: int) -> bool:\n\"\"\"\n        Excess data gas is required if transitioning to Cancun.\n        \"\"\"\n        return timestamp >= 15_000\n\n    @classmethod\n    def engine_new_payload_version(cls, block_number: int, timestamp: int) -> Optional[int]:\n\"\"\"\n        Starting at Cancun, new payload calls must use version 3\n        \"\"\"\n        return 3 if timestamp >= 15_000 else 2\n\n    @classmethod\n    def engine_new_payload_blob_hashes(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n        Starting at Cancun, payloads must have blob hashes.\n        \"\"\"\n        return timestamp >= 15_000\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.transition.ShanghaiToCancunAtTime15k.header_excess_data_gas_required","title":"header_excess_data_gas_required(_, timestamp) classmethod","text":"

Excess data gas is required if transitioning to Cancun.

Source code in src/ethereum_test_forks/forks/transition.py
@classmethod\ndef header_excess_data_gas_required(cls, _: int, timestamp: int) -> bool:\n\"\"\"\n    Excess data gas is required if transitioning to Cancun.\n    \"\"\"\n    return timestamp >= 15_000\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.transition.ShanghaiToCancunAtTime15k.engine_new_payload_version","title":"engine_new_payload_version(block_number, timestamp) classmethod","text":"

Starting at Cancun, new payload calls must use version 3

Source code in src/ethereum_test_forks/forks/transition.py
@classmethod\ndef engine_new_payload_version(cls, block_number: int, timestamp: int) -> Optional[int]:\n\"\"\"\n    Starting at Cancun, new payload calls must use version 3\n    \"\"\"\n    return 3 if timestamp >= 15_000 else 2\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.transition.ShanghaiToCancunAtTime15k.engine_new_payload_blob_hashes","title":"engine_new_payload_blob_hashes(block_number, timestamp) classmethod","text":"

Starting at Cancun, payloads must have blob hashes.

Source code in src/ethereum_test_forks/forks/transition.py
@classmethod\ndef engine_new_payload_blob_hashes(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n    Starting at Cancun, payloads must have blob hashes.\n    \"\"\"\n    return timestamp >= 15_000\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.get_transition_forks","title":"get_transition_forks()","text":"

Returns all the transition forks

Source code in src/ethereum_test_forks/helpers.py
def get_transition_forks() -> List[Fork]:\n\"\"\"\n    Returns all the transition forks\n    \"\"\"\n    transition_forks: List[Fork] = []\n\n    for fork_name in transition.__dict__:\n        fork = transition.__dict__[fork_name]\n        if not isinstance(fork, type):\n            continue\n        if issubclass(fork, TransitionBaseClass) and issubclass(fork, BaseFork):\n            transition_forks.append(fork)\n\n    return transition_forks\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.transition_fork_from_to","title":"transition_fork_from_to(fork_from, fork_to)","text":"

Returns the transition fork that transitions to and from the specified forks.

Source code in src/ethereum_test_forks/helpers.py
def transition_fork_from_to(fork_from: Fork, fork_to: Fork) -> Fork | None:\n\"\"\"\n    Returns the transition fork that transitions to and from the specified\n    forks.\n    \"\"\"\n    for transition_fork in get_transition_forks():\n        if not issubclass(transition_fork, TransitionBaseClass):\n            continue\n        if (\n            transition_fork.transitions_to() == fork_to\n            and transition_fork.transitions_from() == fork_from\n        ):\n            return transition_fork\n\n    return None\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.Homestead","title":"Homestead","text":"

Bases: Frontier

Homestead fork

Source code in src/ethereum_test_forks/forks/forks.py
class Homestead(Frontier):\n\"\"\"\n    Homestead fork\n    \"\"\"\n\n    pass\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.Byzantium","title":"Byzantium","text":"

Bases: Homestead

Byzantium fork

Source code in src/ethereum_test_forks/forks/forks.py
class Byzantium(Homestead):\n\"\"\"\n    Byzantium fork\n    \"\"\"\n\n    @classmethod\n    def get_reward(cls, block_number: int, timestamp: int) -> int:\n\"\"\"\n        At Byzantium, the block reward is reduced to\n        3_000_000_000_000_000_000 wei\n        \"\"\"\n        return 3_000_000_000_000_000_000\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.Byzantium.get_reward","title":"get_reward(block_number, timestamp) classmethod","text":"

At Byzantium, the block reward is reduced to 3_000_000_000_000_000_000 wei

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef get_reward(cls, block_number: int, timestamp: int) -> int:\n\"\"\"\n    At Byzantium, the block reward is reduced to\n    3_000_000_000_000_000_000 wei\n    \"\"\"\n    return 3_000_000_000_000_000_000\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.transition_fork_to","title":"transition_fork_to(fork_to)","text":"

Returns the transition fork that transitions to the specified fork.

Source code in src/ethereum_test_forks/helpers.py
def transition_fork_to(fork_to: Fork) -> List[Fork]:\n\"\"\"\n    Returns the transition fork that transitions to the specified fork.\n    \"\"\"\n    transition_forks: List[Fork] = []\n    for transition_fork in get_transition_forks():\n        if not issubclass(transition_fork, TransitionBaseClass):\n            continue\n        if transition_fork.transitions_to() == fork_to:\n            transition_forks.append(transition_fork)\n\n    return transition_forks\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.Constantinople","title":"Constantinople","text":"

Bases: Byzantium

Constantinople fork

Source code in src/ethereum_test_forks/forks/forks.py
class Constantinople(Byzantium):\n\"\"\"\n    Constantinople fork\n    \"\"\"\n\n    @classmethod\n    def get_reward(cls, block_number: int, timestamp: int) -> int:\n\"\"\"\n        At Constantinople, the block reward is reduced to\n        2_000_000_000_000_000_000 wei\n        \"\"\"\n        return 2_000_000_000_000_000_000\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.Constantinople.get_reward","title":"get_reward(block_number, timestamp) classmethod","text":"

At Constantinople, the block reward is reduced to 2_000_000_000_000_000_000 wei

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef get_reward(cls, block_number: int, timestamp: int) -> int:\n\"\"\"\n    At Constantinople, the block reward is reduced to\n    2_000_000_000_000_000_000 wei\n    \"\"\"\n    return 2_000_000_000_000_000_000\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks_from_until","title":"forks_from_until(fork_from, fork_until)","text":"

Returns the specified fork and all forks after it until and including the second specified fork

Source code in src/ethereum_test_forks/helpers.py
def forks_from_until(fork_from: Fork, fork_until: Fork) -> List[Fork]:\n\"\"\"\n    Returns the specified fork and all forks after it until and including the\n    second specified fork\n    \"\"\"\n    prev_fork = fork_until\n\n    forks: List[Fork] = []\n\n    while prev_fork != BaseFork and prev_fork != fork_from:\n        forks.insert(0, prev_fork)\n\n        prev_fork = prev_fork.__base__\n\n    if prev_fork == BaseFork:\n        return []\n\n    forks.insert(0, fork_from)\n\n    return forks\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.ConstantinopleFix","title":"ConstantinopleFix","text":"

Bases: Constantinople

Constantinople Fix fork

Source code in src/ethereum_test_forks/forks/forks.py
class ConstantinopleFix(Constantinople):\n\"\"\"\n    Constantinople Fix fork\n    \"\"\"\n\n    pass\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.Istanbul","title":"Istanbul","text":"

Bases: ConstantinopleFix

Istanbul fork

Source code in src/ethereum_test_forks/forks/forks.py
class Istanbul(ConstantinopleFix):\n\"\"\"\n    Istanbul fork\n    \"\"\"\n\n    pass\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks_from","title":"forks_from(fork, deployed_only=True)","text":"

Returns the specified fork and all forks after it.

Source code in src/ethereum_test_forks/helpers.py
def forks_from(fork: Fork, deployed_only: bool = True) -> List[Fork]:\n\"\"\"\n    Returns the specified fork and all forks after it.\n    \"\"\"\n    if deployed_only:\n        latest_fork = get_deployed_forks()[-1]\n    else:\n        latest_fork = get_forks()[-1]\n    return forks_from_until(fork, latest_fork)\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.MuirGlacier","title":"MuirGlacier","text":"

Bases: Istanbul

Muir Glacier fork

Source code in src/ethereum_test_forks/forks/forks.py
class MuirGlacier(Istanbul):\n\"\"\"\n    Muir Glacier fork\n    \"\"\"\n\n    pass\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.is_fork","title":"is_fork(fork, which)","text":"

Returns True if fork is which or beyond, `False otherwise.

Source code in src/ethereum_test_forks/helpers.py
def is_fork(fork: Fork, which: Fork) -> bool:\n\"\"\"\n    Returns `True` if `fork` is `which` or beyond, `False otherwise.\n    \"\"\"\n    prev_fork = fork\n\n    while prev_fork != BaseFork:\n        if prev_fork == which:\n            return True\n\n        prev_fork = prev_fork.__base__\n\n    return False\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.Berlin","title":"Berlin","text":"

Bases: Istanbul

Berlin fork

Source code in src/ethereum_test_forks/forks/forks.py
class Berlin(Istanbul):\n\"\"\"\n    Berlin fork\n    \"\"\"\n\n    pass\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.London","title":"London","text":"

Bases: Berlin

London fork

Source code in src/ethereum_test_forks/forks/forks.py
class London(Berlin):\n\"\"\"\n    London fork\n    \"\"\"\n\n    @classmethod\n    def header_base_fee_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n        Base Fee is required starting from London.\n        \"\"\"\n        return True\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.London.header_base_fee_required","title":"header_base_fee_required(block_number, timestamp) classmethod","text":"

Base Fee is required starting from London.

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef header_base_fee_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n    Base Fee is required starting from London.\n    \"\"\"\n    return True\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.ArrowGlacier","title":"ArrowGlacier","text":"

Bases: London

Arrow Glacier fork

Source code in src/ethereum_test_forks/forks/forks.py
class ArrowGlacier(London):\n\"\"\"\n    Arrow Glacier fork\n    \"\"\"\n\n    pass\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.GrayGlacier","title":"GrayGlacier","text":"

Bases: ArrowGlacier

Gray Glacier fork

Source code in src/ethereum_test_forks/forks/forks.py
class GrayGlacier(ArrowGlacier):\n\"\"\"\n    Gray Glacier fork\n    \"\"\"\n\n    pass\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.Merge","title":"Merge","text":"

Bases: London

Merge fork

Source code in src/ethereum_test_forks/forks/forks.py
class Merge(London):\n\"\"\"\n    Merge fork\n    \"\"\"\n\n    @classmethod\n    def header_prev_randao_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n        Prev Randao is required starting from Merge.\n        \"\"\"\n        return True\n\n    @classmethod\n    def header_zero_difficulty_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n        Zero difficulty is required starting from Merge.\n        \"\"\"\n        return True\n\n    @classmethod\n    def get_reward(cls, block_number: int, timestamp: int) -> int:\n\"\"\"\n        Merge updates the reward to 0.\n        \"\"\"\n        return 0\n\n    @classmethod\n    def engine_new_payload_version(cls, block_number: int, timestamp: int) -> Optional[int]:\n\"\"\"\n        Starting at the merge, payloads can be sent through the engine API\n        \"\"\"\n        return 1\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.Merge.header_prev_randao_required","title":"header_prev_randao_required(block_number, timestamp) classmethod","text":"

Prev Randao is required starting from Merge.

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef header_prev_randao_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n    Prev Randao is required starting from Merge.\n    \"\"\"\n    return True\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.Merge.header_zero_difficulty_required","title":"header_zero_difficulty_required(block_number, timestamp) classmethod","text":"

Zero difficulty is required starting from Merge.

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef header_zero_difficulty_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n    Zero difficulty is required starting from Merge.\n    \"\"\"\n    return True\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.Merge.get_reward","title":"get_reward(block_number, timestamp) classmethod","text":"

Merge updates the reward to 0.

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef get_reward(cls, block_number: int, timestamp: int) -> int:\n\"\"\"\n    Merge updates the reward to 0.\n    \"\"\"\n    return 0\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.Merge.engine_new_payload_version","title":"engine_new_payload_version(block_number, timestamp) classmethod","text":"

Starting at the merge, payloads can be sent through the engine API

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef engine_new_payload_version(cls, block_number: int, timestamp: int) -> Optional[int]:\n\"\"\"\n    Starting at the merge, payloads can be sent through the engine API\n    \"\"\"\n    return 1\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.Shanghai","title":"Shanghai","text":"

Bases: Merge

Shanghai fork

Source code in src/ethereum_test_forks/forks/forks.py
class Shanghai(Merge):\n\"\"\"\n    Shanghai fork\n    \"\"\"\n\n    @classmethod\n    def header_withdrawals_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n        Withdrawals are required starting from Shanghai.\n        \"\"\"\n        return True\n\n    @classmethod\n    def engine_new_payload_version(cls, block_number: int, timestamp: int) -> Optional[int]:\n\"\"\"\n        Starting at Shanghai, new payload calls must use version 2\n        \"\"\"\n        return 2\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.Shanghai.header_withdrawals_required","title":"header_withdrawals_required(block_number, timestamp) classmethod","text":"

Withdrawals are required starting from Shanghai.

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef header_withdrawals_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n    Withdrawals are required starting from Shanghai.\n    \"\"\"\n    return True\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.Shanghai.engine_new_payload_version","title":"engine_new_payload_version(block_number, timestamp) classmethod","text":"

Starting at Shanghai, new payload calls must use version 2

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef engine_new_payload_version(cls, block_number: int, timestamp: int) -> Optional[int]:\n\"\"\"\n    Starting at Shanghai, new payload calls must use version 2\n    \"\"\"\n    return 2\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.Cancun","title":"Cancun","text":"

Bases: Shanghai

Cancun fork

Source code in src/ethereum_test_forks/forks/forks.py
class Cancun(Shanghai):\n\"\"\"\n    Cancun fork\n    \"\"\"\n\n    @classmethod\n    def is_deployed(cls):\n\"\"\"\n        Flags that Cancun has not been deployed to mainnet; it is under active\n        development.\n        \"\"\"\n        return False\n\n    @classmethod\n    def header_excess_data_gas_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n        Excess data gas is required starting from Cancun.\n        \"\"\"\n        return True\n\n    @classmethod\n    def header_data_gas_used_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n        Data gas used is required starting from Cancun.\n        \"\"\"\n        return True\n\n    @classmethod\n    def engine_new_payload_version(cls, block_number: int, timestamp: int) -> Optional[int]:\n\"\"\"\n        Starting at Cancun, new payload calls must use version 3\n        \"\"\"\n        return 3\n\n    @classmethod\n    def engine_new_payload_blob_hashes(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n        Starting at Cancun, payloads must have blob hashes.\n        \"\"\"\n        return True\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.Cancun.is_deployed","title":"is_deployed() classmethod","text":"

Flags that Cancun has not been deployed to mainnet; it is under active development.

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef is_deployed(cls):\n\"\"\"\n    Flags that Cancun has not been deployed to mainnet; it is under active\n    development.\n    \"\"\"\n    return False\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.Cancun.header_excess_data_gas_required","title":"header_excess_data_gas_required(block_number, timestamp) classmethod","text":"

Excess data gas is required starting from Cancun.

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef header_excess_data_gas_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n    Excess data gas is required starting from Cancun.\n    \"\"\"\n    return True\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.Cancun.header_data_gas_used_required","title":"header_data_gas_used_required(block_number, timestamp) classmethod","text":"

Data gas used is required starting from Cancun.

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef header_data_gas_used_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n    Data gas used is required starting from Cancun.\n    \"\"\"\n    return True\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.Cancun.engine_new_payload_version","title":"engine_new_payload_version(block_number, timestamp) classmethod","text":"

Starting at Cancun, new payload calls must use version 3

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef engine_new_payload_version(cls, block_number: int, timestamp: int) -> Optional[int]:\n\"\"\"\n    Starting at Cancun, new payload calls must use version 3\n    \"\"\"\n    return 3\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.Cancun.engine_new_payload_blob_hashes","title":"engine_new_payload_blob_hashes(block_number, timestamp) classmethod","text":"

Starting at Cancun, payloads must have blob hashes.

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef engine_new_payload_blob_hashes(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n    Starting at Cancun, payloads must have blob hashes.\n    \"\"\"\n    return True\n
"},{"location":"library/ethereum_test_tools/","title":"Ethereum Test Tools Package","text":"

Module containing tools for generating cross-client Ethereum execution layer tests.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.Code","title":"Code dataclass","text":"

Generic code object.

Source code in src/ethereum_test_tools/code/code.py
@dataclass(kw_only=True)\nclass Code:\n\"\"\"\n    Generic code object.\n    \"\"\"\n\n    bytecode: Optional[bytes] = None\n\"\"\"\n    bytes array that represents the bytecode of this object.\n    \"\"\"\n    name: Optional[str] = None\n\"\"\"\n    Name used to describe this code.\n    Usually used to add extra information to a test case.\n    \"\"\"\n\n    def assemble(self) -> bytes:\n\"\"\"\n        Transform the Code object into bytes.\n        Normally will be overriden by the classes that inherit this class.\n        \"\"\"\n        if self.bytecode is None:\n            return bytes()\n        else:\n            return self.bytecode\n\n    def __add__(self, other: Union[str, bytes, \"Code\"]) -> \"Code\":\n\"\"\"\n        Adds two code objects together, by converting both to bytes first.\n        \"\"\"\n        return Code(bytecode=(code_to_bytes(self) + code_to_bytes(other)))\n\n    def __radd__(self, other: Union[str, bytes, \"Code\"]) -> \"Code\":\n\"\"\"\n        Adds two code objects together, by converting both to bytes first.\n        \"\"\"\n        return Code(bytecode=(code_to_bytes(other) + code_to_bytes(self)))\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.code.code.Code.bytecode","title":"bytecode: Optional[bytes] = None class-attribute instance-attribute","text":"

bytes array that represents the bytecode of this object.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.code.code.Code.name","title":"name: Optional[str] = None class-attribute instance-attribute","text":"

Name used to describe this code. Usually used to add extra information to a test case.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.code.code.Code.assemble","title":"assemble()","text":"

Transform the Code object into bytes. Normally will be overriden by the classes that inherit this class.

Source code in src/ethereum_test_tools/code/code.py
def assemble(self) -> bytes:\n\"\"\"\n    Transform the Code object into bytes.\n    Normally will be overriden by the classes that inherit this class.\n    \"\"\"\n    if self.bytecode is None:\n        return bytes()\n    else:\n        return self.bytecode\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.code.code.Code.__add__","title":"__add__(other)","text":"

Adds two code objects together, by converting both to bytes first.

Source code in src/ethereum_test_tools/code/code.py
def __add__(self, other: Union[str, bytes, \"Code\"]) -> \"Code\":\n\"\"\"\n    Adds two code objects together, by converting both to bytes first.\n    \"\"\"\n    return Code(bytecode=(code_to_bytes(self) + code_to_bytes(other)))\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.code.code.Code.__radd__","title":"__radd__(other)","text":"

Adds two code objects together, by converting both to bytes first.

Source code in src/ethereum_test_tools/code/code.py
def __radd__(self, other: Union[str, bytes, \"Code\"]) -> \"Code\":\n\"\"\"\n    Adds two code objects together, by converting both to bytes first.\n    \"\"\"\n    return Code(bytecode=(code_to_bytes(other) + code_to_bytes(self)))\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.Initcode","title":"Initcode","text":"

Bases: Code

Helper class used to generate initcode for the specified deployment code.

The execution gas cost of the initcode is calculated, and also the deployment gas costs for the deployed code.

The initcode can be padded to a certain length if necessary, which does not affect the deployed code.

Other costs such as the CREATE2 hashing costs or the initcode_word_cost of EIP-3860 are not taken into account by any of these calculated costs.

Source code in src/ethereum_test_tools/code/generators.py
class Initcode(Code):\n\"\"\"\n    Helper class used to generate initcode for the specified deployment code.\n\n    The execution gas cost of the initcode is calculated, and also the\n    deployment gas costs for the deployed code.\n\n    The initcode can be padded to a certain length if necessary, which\n    does not affect the deployed code.\n\n    Other costs such as the CREATE2 hashing costs or the initcode_word_cost\n    of EIP-3860 are *not* taken into account by any of these calculated\n    costs.\n    \"\"\"\n\n    deploy_code: bytes | str | Code\n\"\"\"\n    Bytecode to be deployed by the initcode.\n    \"\"\"\n    execution_gas: int\n\"\"\"\n    Gas cost of executing the initcode, without considering deployment gas\n    costs.\n    \"\"\"\n    deployment_gas: int\n\"\"\"\n    Gas cost of deploying the cost, subtracted after initcode execution,\n    \"\"\"\n\n    def __init__(\n        self,\n        *,\n        deploy_code: str | bytes | Code,\n        initcode_length: Optional[int] = None,\n        padding_byte: int = 0x00,\n        name: Optional[str] = None,\n    ):\n\"\"\"\n        Generate legacy initcode that inits a contract with the specified code.\n        The initcode can be padded to a specified length for testing purposes.\n        \"\"\"\n        self.execution_gas = 0\n        self.deploy_code = deploy_code\n        deploy_code_bytes = code_to_bytes(self.deploy_code)\n        code_length = len(deploy_code_bytes)\n\n        initcode = bytearray()\n\n        # PUSH2: length=<bytecode length>\n        initcode.append(0x61)\n        initcode += code_length.to_bytes(length=2, byteorder=\"big\")\n        self.execution_gas += 3\n\n        # PUSH1: offset=0\n        initcode.append(0x60)\n        initcode.append(0x00)\n        self.execution_gas += 3\n\n        # DUP2\n        initcode.append(0x81)\n        self.execution_gas += 3\n\n        # PUSH1: initcode_length=11 (constant)\n        initcode.append(0x60)\n        initcode.append(0x0B)\n        self.execution_gas += 3\n\n        # DUP3\n        initcode.append(0x82)\n        self.execution_gas += 3\n\n        # CODECOPY: destinationOffset=0, offset=0, length\n        initcode.append(0x39)\n        self.execution_gas += (\n            3\n            + (3 * ceiling_division(code_length, 32))\n            + (3 * code_length)\n            + ((code_length * code_length) // 512)\n        )\n\n        # RETURN: offset=0, length\n        initcode.append(0xF3)\n        self.execution_gas += 0\n\n        pre_padding_bytes = bytes(initcode) + deploy_code_bytes\n\n        if initcode_length is not None:\n            if len(pre_padding_bytes) > initcode_length:\n                raise Exception(\"Invalid specified length for initcode\")\n\n            padding_bytes = bytes([padding_byte] * (initcode_length - len(pre_padding_bytes)))\n        else:\n            padding_bytes = bytes()\n\n        self.deployment_gas = GAS_PER_DEPLOYED_CODE_BYTE * len(deploy_code_bytes)\n\n        super().__init__(bytecode=pre_padding_bytes + padding_bytes, name=name)\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.code.generators.Initcode.__init__","title":"__init__(*, deploy_code, initcode_length=None, padding_byte=0, name=None)","text":"

Generate legacy initcode that inits a contract with the specified code. The initcode can be padded to a specified length for testing purposes.

Source code in src/ethereum_test_tools/code/generators.py
def __init__(\n    self,\n    *,\n    deploy_code: str | bytes | Code,\n    initcode_length: Optional[int] = None,\n    padding_byte: int = 0x00,\n    name: Optional[str] = None,\n):\n\"\"\"\n    Generate legacy initcode that inits a contract with the specified code.\n    The initcode can be padded to a specified length for testing purposes.\n    \"\"\"\n    self.execution_gas = 0\n    self.deploy_code = deploy_code\n    deploy_code_bytes = code_to_bytes(self.deploy_code)\n    code_length = len(deploy_code_bytes)\n\n    initcode = bytearray()\n\n    # PUSH2: length=<bytecode length>\n    initcode.append(0x61)\n    initcode += code_length.to_bytes(length=2, byteorder=\"big\")\n    self.execution_gas += 3\n\n    # PUSH1: offset=0\n    initcode.append(0x60)\n    initcode.append(0x00)\n    self.execution_gas += 3\n\n    # DUP2\n    initcode.append(0x81)\n    self.execution_gas += 3\n\n    # PUSH1: initcode_length=11 (constant)\n    initcode.append(0x60)\n    initcode.append(0x0B)\n    self.execution_gas += 3\n\n    # DUP3\n    initcode.append(0x82)\n    self.execution_gas += 3\n\n    # CODECOPY: destinationOffset=0, offset=0, length\n    initcode.append(0x39)\n    self.execution_gas += (\n        3\n        + (3 * ceiling_division(code_length, 32))\n        + (3 * code_length)\n        + ((code_length * code_length) // 512)\n    )\n\n    # RETURN: offset=0, length\n    initcode.append(0xF3)\n    self.execution_gas += 0\n\n    pre_padding_bytes = bytes(initcode) + deploy_code_bytes\n\n    if initcode_length is not None:\n        if len(pre_padding_bytes) > initcode_length:\n            raise Exception(\"Invalid specified length for initcode\")\n\n        padding_bytes = bytes([padding_byte] * (initcode_length - len(pre_padding_bytes)))\n    else:\n        padding_bytes = bytes()\n\n    self.deployment_gas = GAS_PER_DEPLOYED_CODE_BYTE * len(deploy_code_bytes)\n\n    super().__init__(bytecode=pre_padding_bytes + padding_bytes, name=name)\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.code.generators.Initcode.execution_gas","title":"execution_gas: int = 0 instance-attribute","text":"

Gas cost of executing the initcode, without considering deployment gas costs.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.code.generators.Initcode.deploy_code","title":"deploy_code: bytes | str | Code = deploy_code instance-attribute","text":"

Bytecode to be deployed by the initcode.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.code.generators.Initcode.deployment_gas","title":"deployment_gas: int = GAS_PER_DEPLOYED_CODE_BYTE * len(deploy_code_bytes) instance-attribute","text":"

Gas cost of deploying the cost, subtracted after initcode execution,

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.ceiling_division","title":"ceiling_division(a, b)","text":"

Calculates the ceil without using floating point. Used by many of the EVM's formulas

Source code in src/ethereum_test_tools/common/helpers.py
def ceiling_division(a: int, b: int) -> int:\n\"\"\"\n    Calculates the ceil without using floating point.\n    Used by many of the EVM's formulas\n    \"\"\"\n    return -(a // -b)\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.fill_test","title":"fill_test(t8n, test_spec, fork, engine, spec, eips=None)","text":"

Fills fixtures for the specified fork.

Source code in src/ethereum_test_tools/filling/fill.py
def fill_test(\n    t8n: TransitionTool,\n    test_spec: BaseTest,\n    fork: Fork,\n    engine: str,\n    spec: ReferenceSpec | None,\n    eips: Optional[List[int]] = None,\n) -> Fixture:\n\"\"\"\n    Fills fixtures for the specified fork.\n    \"\"\"\n    t8n.reset_traces()\n\n    genesis_rlp, genesis = test_spec.make_genesis(t8n, fork)\n\n    (blocks, head, alloc) = test_spec.make_blocks(\n        t8n,\n        genesis,\n        fork,\n        eips=eips,\n    )\n\n    fork_name = fork.name()\n    fixture = Fixture(\n        blocks=blocks,\n        genesis=genesis,\n        genesis_rlp=genesis_rlp,\n        head=head,\n        fork=\"+\".join([fork_name] + [str(eip) for eip in eips]) if eips is not None else fork_name,\n        pre_state=copy(test_spec.pre),\n        post_state=alloc_to_accounts(alloc),\n        seal_engine=engine,\n        name=test_spec.tag,\n    )\n    fixture.fill_info(t8n, spec)\n\n    return fixture\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.compute_create_address","title":"compute_create_address(address, nonce)","text":"

Compute address of the resulting contract created using a transaction or the CREATE opcode.

Source code in src/ethereum_test_tools/common/helpers.py
def compute_create_address(address: str | int, nonce: int) -> str:\n\"\"\"\n    Compute address of the resulting contract created using a transaction\n    or the `CREATE` opcode.\n    \"\"\"\n    if type(address) is str:\n        if address.startswith(\"0x\"):\n            address = address[2:]\n        address_bytes = bytes.fromhex(address)\n    elif type(address) is int:\n        address_bytes = address.to_bytes(length=20, byteorder=\"big\")\n    if nonce == 0:\n        nonce_bytes = bytes()\n    else:\n        nonce_bytes = nonce.to_bytes(length=1, byteorder=\"big\")\n    hash = keccak256(encode([address_bytes, nonce_bytes]))\n    return \"0x\" + hash[-20:].hex()\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.EngineAPIError","title":"EngineAPIError","text":"

Bases: IntEnum

List of Engine API errors

Source code in src/ethereum_test_tools/common/constants.py
class EngineAPIError(IntEnum):\n\"\"\"\n    List of Engine API errors\n    \"\"\"\n\n    ParseError = -32700\n    InvalidRequest = -32600\n    MethodNotFound = -32601\n    InvalidParams = -32602\n    InternalError = -32603\n    ServerError = -32000\n    UnknownPayload = -38001\n    InvalidForkchoiceState = -38002\n    InvalidPayloadAttributes = -38003\n    TooLargeRequest = -38004\n    UnsupportedFork = -38005\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.Opcode","title":"Opcode","text":"

Bases: bytes

Represents a single Opcode instruction in the EVM, with extra metadata useful to parametrize tests.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.Opcode--parameters","title":"Parameters","text":"
  • popped_stack_items: number of items the opcode pops from the stack
  • pushed_stack_items: number of items the opcode pushes to the stack
  • min_stack_height: minimum stack height required by the opcode
  • data_portion_length: number of bytes after the opcode in the bytecode that represent data
Source code in src/ethereum_test_tools/vm/opcode.py
class Opcode(bytes):\n\"\"\"\n    Represents a single Opcode instruction in the EVM, with extra\n    metadata useful to parametrize tests.\n\n    Parameters\n    ----------\n    - popped_stack_items: number of items the opcode pops from the stack\n    - pushed_stack_items: number of items the opcode pushes to the stack\n    - min_stack_height: minimum stack height required by the opcode\n    - data_portion_length: number of bytes after the opcode in the bytecode\n        that represent data\n    \"\"\"\n\n    popped_stack_items: int\n    pushed_stack_items: int\n    min_stack_height: int\n    data_portion_length: int\n    _name_: str\n\n    def __new__(\n        cls,\n        opcode_or_byte: Union[int, \"Opcode\"],\n        *,\n        popped_stack_items: int = 0,\n        pushed_stack_items: int = 0,\n        min_stack_height: int = 0,\n        data_portion_length: int = 0,\n    ):\n\"\"\"\n        Creates a new opcode instance.\n        \"\"\"\n        if type(opcode_or_byte) is Opcode:\n            # Required because Enum class calls the base class with the\n            # instantiated object as parameter.\n            return opcode_or_byte\n        elif isinstance(opcode_or_byte, int):\n            obj = super().__new__(cls, [opcode_or_byte])\n            obj.popped_stack_items = popped_stack_items\n            obj.pushed_stack_items = pushed_stack_items\n            obj.min_stack_height = min_stack_height\n            obj.data_portion_length = data_portion_length\n            return obj\n\n    def __call__(self, *args_t: Union[int, bytes, \"Opcode\"]) -> bytes:\n\"\"\"\n        Makes all opcode instances callable to return formatted bytecode,\n        which constitutes a data portion, that is located after the opcode\n        byte, and pre-opcode bytecode, which is normally used to set up the\n        stack.\n\n        This useful to automatically format, e.g., push opcodes and their\n        data sections as `Opcodes.PUSH1(0x00)`.\n\n        Data sign is automatically detected but for this reason the range\n        of the input must be:\n        `[-2^(data_portion_bits-1), 2^(data_portion_bits)]`\n        where:\n        `data_portion_bits == data_portion_length * 8`\n\n        For the stack, the arguments are set up in the opposite order they are\n        given, so the first argument is the last item pushed to the stack.\n\n        The resulting stack arrangement does not take into account opcode stack\n        element consumption, so the stack height is not guaranteed to be\n        correct and the user must take this into consideration.\n\n        Integers can also be used as stack elements, in which case they are\n        automatically converted to PUSH operations, and negative numbers always\n        use a PUSH32 operation.\n\n\n        \"\"\"\n        args: List[Union[int, bytes, \"Opcode\"]] = list(args_t)\n        pre_opcode_bytecode = bytes()\n        data_portion = bytes()\n\n        if self.data_portion_length > 0:\n            # For opcodes with a data portion, the first argument is the data\n            # and the rest of the arguments form the stack.\n            if len(args) == 0:\n                raise ValueError(\"Opcode with data portion requires at least one argument\")\n            data = args.pop(0)\n            if isinstance(data, bytes):\n                data_portion = data\n            elif isinstance(data, int):\n                signed = data < 0\n                data_portion = data.to_bytes(\n                    length=self.data_portion_length,\n                    byteorder=\"big\",\n                    signed=signed,\n                )\n            else:\n                raise TypeError(\"Opcode data portion must be either an int or a bytes\")\n\n        # The rest of the arguments conform the stack.\n        while len(args) > 0:\n            data = args.pop()\n            if isinstance(data, bytes):\n                pre_opcode_bytecode += data\n            elif isinstance(data, int):\n                # We are going to push a constant to the stack.\n                signed = data < 0\n                data_size = _get_int_size(data)\n                if data_size > 32:\n                    raise ValueError(\"Opcode stack data must be less than 32 bytes\")\n                elif data_size == 0:\n                    # Pushing 0 is done with the PUSH1 opcode for compatibility\n                    # reasons.\n                    data_size = 1\n\n                pre_opcode_bytecode += _push_opcodes_byte_list[data_size]\n                pre_opcode_bytecode += data.to_bytes(\n                    length=data_size,\n                    byteorder=\"big\",\n                    signed=signed,\n                )\n\n            else:\n                raise TypeError(\"Opcode stack data must be either an int or a bytes\")\n\n        return pre_opcode_bytecode + self + data_portion\n\n    def __len__(self) -> int:\n\"\"\"\n        Returns the total bytecode length of the opcode, taking into account\n        its data portion.\n        \"\"\"\n        return self.data_portion_length + 1\n\n    def int(self) -> int:\n\"\"\"\n        Returns the integer representation of the opcode.\n        \"\"\"\n        return int.from_bytes(bytes=self, byteorder=\"big\")\n\n    def __str__(self) -> str:\n\"\"\"\n        Return the name of the opcode, assigned at Enum creation.\n        \"\"\"\n        return self._name_\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.vm.opcode.Opcode.__new__","title":"__new__(opcode_or_byte, *, popped_stack_items=0, pushed_stack_items=0, min_stack_height=0, data_portion_length=0)","text":"

Creates a new opcode instance.

Source code in src/ethereum_test_tools/vm/opcode.py
def __new__(\n    cls,\n    opcode_or_byte: Union[int, \"Opcode\"],\n    *,\n    popped_stack_items: int = 0,\n    pushed_stack_items: int = 0,\n    min_stack_height: int = 0,\n    data_portion_length: int = 0,\n):\n\"\"\"\n    Creates a new opcode instance.\n    \"\"\"\n    if type(opcode_or_byte) is Opcode:\n        # Required because Enum class calls the base class with the\n        # instantiated object as parameter.\n        return opcode_or_byte\n    elif isinstance(opcode_or_byte, int):\n        obj = super().__new__(cls, [opcode_or_byte])\n        obj.popped_stack_items = popped_stack_items\n        obj.pushed_stack_items = pushed_stack_items\n        obj.min_stack_height = min_stack_height\n        obj.data_portion_length = data_portion_length\n        return obj\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.vm.opcode.Opcode.__call__","title":"__call__(*args_t)","text":"

Makes all opcode instances callable to return formatted bytecode, which constitutes a data portion, that is located after the opcode byte, and pre-opcode bytecode, which is normally used to set up the stack.

This useful to automatically format, e.g., push opcodes and their data sections as Opcodes.PUSH1(0x00).

Data sign is automatically detected but for this reason the range of the input must be: [-2^(data_portion_bits-1), 2^(data_portion_bits)] where: data_portion_bits == data_portion_length * 8

For the stack, the arguments are set up in the opposite order they are given, so the first argument is the last item pushed to the stack.

The resulting stack arrangement does not take into account opcode stack element consumption, so the stack height is not guaranteed to be correct and the user must take this into consideration.

Integers can also be used as stack elements, in which case they are automatically converted to PUSH operations, and negative numbers always use a PUSH32 operation.

Source code in src/ethereum_test_tools/vm/opcode.py
def __call__(self, *args_t: Union[int, bytes, \"Opcode\"]) -> bytes:\n\"\"\"\n    Makes all opcode instances callable to return formatted bytecode,\n    which constitutes a data portion, that is located after the opcode\n    byte, and pre-opcode bytecode, which is normally used to set up the\n    stack.\n\n    This useful to automatically format, e.g., push opcodes and their\n    data sections as `Opcodes.PUSH1(0x00)`.\n\n    Data sign is automatically detected but for this reason the range\n    of the input must be:\n    `[-2^(data_portion_bits-1), 2^(data_portion_bits)]`\n    where:\n    `data_portion_bits == data_portion_length * 8`\n\n    For the stack, the arguments are set up in the opposite order they are\n    given, so the first argument is the last item pushed to the stack.\n\n    The resulting stack arrangement does not take into account opcode stack\n    element consumption, so the stack height is not guaranteed to be\n    correct and the user must take this into consideration.\n\n    Integers can also be used as stack elements, in which case they are\n    automatically converted to PUSH operations, and negative numbers always\n    use a PUSH32 operation.\n\n\n    \"\"\"\n    args: List[Union[int, bytes, \"Opcode\"]] = list(args_t)\n    pre_opcode_bytecode = bytes()\n    data_portion = bytes()\n\n    if self.data_portion_length > 0:\n        # For opcodes with a data portion, the first argument is the data\n        # and the rest of the arguments form the stack.\n        if len(args) == 0:\n            raise ValueError(\"Opcode with data portion requires at least one argument\")\n        data = args.pop(0)\n        if isinstance(data, bytes):\n            data_portion = data\n        elif isinstance(data, int):\n            signed = data < 0\n            data_portion = data.to_bytes(\n                length=self.data_portion_length,\n                byteorder=\"big\",\n                signed=signed,\n            )\n        else:\n            raise TypeError(\"Opcode data portion must be either an int or a bytes\")\n\n    # The rest of the arguments conform the stack.\n    while len(args) > 0:\n        data = args.pop()\n        if isinstance(data, bytes):\n            pre_opcode_bytecode += data\n        elif isinstance(data, int):\n            # We are going to push a constant to the stack.\n            signed = data < 0\n            data_size = _get_int_size(data)\n            if data_size > 32:\n                raise ValueError(\"Opcode stack data must be less than 32 bytes\")\n            elif data_size == 0:\n                # Pushing 0 is done with the PUSH1 opcode for compatibility\n                # reasons.\n                data_size = 1\n\n            pre_opcode_bytecode += _push_opcodes_byte_list[data_size]\n            pre_opcode_bytecode += data.to_bytes(\n                length=data_size,\n                byteorder=\"big\",\n                signed=signed,\n            )\n\n        else:\n            raise TypeError(\"Opcode stack data must be either an int or a bytes\")\n\n    return pre_opcode_bytecode + self + data_portion\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.vm.opcode.Opcode.__len__","title":"__len__()","text":"

Returns the total bytecode length of the opcode, taking into account its data portion.

Source code in src/ethereum_test_tools/vm/opcode.py
def __len__(self) -> int:\n\"\"\"\n    Returns the total bytecode length of the opcode, taking into account\n    its data portion.\n    \"\"\"\n    return self.data_portion_length + 1\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.vm.opcode.Opcode.int","title":"int()","text":"

Returns the integer representation of the opcode.

Source code in src/ethereum_test_tools/vm/opcode.py
def int(self) -> int:\n\"\"\"\n    Returns the integer representation of the opcode.\n    \"\"\"\n    return int.from_bytes(bytes=self, byteorder=\"big\")\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.vm.opcode.Opcode.__str__","title":"__str__()","text":"

Return the name of the opcode, assigned at Enum creation.

Source code in src/ethereum_test_tools/vm/opcode.py
def __str__(self) -> str:\n\"\"\"\n    Return the name of the opcode, assigned at Enum creation.\n    \"\"\"\n    return self._name_\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.BlockchainTest","title":"BlockchainTest dataclass","text":"

Bases: BaseTest

Filler type that tests multiple blocks (valid or invalid) in a chain.

Source code in src/ethereum_test_tools/spec/blockchain_test.py
@dataclass(kw_only=True)\nclass BlockchainTest(BaseTest):\n\"\"\"\n    Filler type that tests multiple blocks (valid or invalid) in a chain.\n    \"\"\"\n\n    pre: Mapping[str, Account]\n    post: Mapping[str, Account]\n    blocks: List[Block]\n    genesis_environment: Environment = field(default_factory=Environment)\n    tag: str = \"\"\n\n    @classmethod\n    def pytest_parameter_name(cls) -> str:\n\"\"\"\n        Returns the parameter name used to identify this filler in a test.\n        \"\"\"\n        return \"blockchain_test\"\n\n    def make_genesis(\n        self,\n        t8n: TransitionTool,\n        fork: Fork,\n    ) -> Tuple[bytes, FixtureHeader]:\n\"\"\"\n        Create a genesis block from the state test definition.\n        \"\"\"\n        env = self.genesis_environment.set_fork_requirements(fork)\n\n        genesis = FixtureHeader(\n            parent_hash=EmptyHash,\n            ommers_hash=EmptyOmmersRoot,\n            coinbase=ZeroAddress,\n            state_root=t8n.calc_state_root(\n                to_json(self.pre),\n                fork,\n            ),\n            transactions_root=EmptyTrieRoot,\n            receipt_root=EmptyTrieRoot,\n            bloom=EmptyBloom,\n            difficulty=0x20000 if env.difficulty is None else env.difficulty,\n            number=0,\n            gas_limit=env.gas_limit,\n            gas_used=0,\n            timestamp=0,\n            extra_data=bytes([0]),\n            mix_digest=EmptyHash,\n            nonce=EmptyNonce,\n            base_fee=env.base_fee,\n            data_gas_used=env.data_gas_used,\n            excess_data_gas=env.excess_data_gas,\n            withdrawals_root=t8n.calc_withdrawals_root(env.withdrawals, fork)\n            if env.withdrawals is not None\n            else None,\n        )\n\n        genesis_rlp, genesis.hash = genesis.build(\n            txs=[],\n            ommers=[],\n            withdrawals=env.withdrawals,\n        )\n\n        return genesis_rlp, genesis\n\n    def make_block(\n        self,\n        t8n: TransitionTool,\n        fork: Fork,\n        block: Block,\n        previous_env: Environment,\n        previous_alloc: Dict[str, Any],\n        previous_head: bytes,\n        chain_id=1,\n        eips: Optional[List[int]] = None,\n    ) -> Tuple[FixtureBlock, Environment, Dict[str, Any], bytes]:\n\"\"\"\n        Produces a block based on the previous environment and allocation.\n        If the block is an invalid block, the environment and allocation\n        returned are the same as passed as parameters.\n        Raises exception on invalid test behavior.\n\n        Returns\n        -------\n            FixtureBlock: Block to be appended to the fixture.\n            Environment: Environment for the next block to produce.\n                If the produced block is invalid, this is exactly the same\n                environment as the one passed as parameter.\n            Dict[str, Any]: Allocation for the next block to produce.\n                If the produced block is invalid, this is exactly the same\n                allocation as the one passed as parameter.\n            str: Hash of the head of the chain, only updated if the produced\n                block is not invalid.\n\n        \"\"\"\n        if block.rlp and block.exception is not None:\n            raise Exception(\n                \"test correctness: post-state cannot be verified if the \"\n                + \"block's rlp is supplied and the block is not supposed \"\n                + \"to produce an exception\"\n            )\n\n        if block.rlp is None:\n            # This is the most common case, the RLP needs to be constructed\n            # based on the transactions to be included in the block.\n            # Set the environment according to the block to execute.\n            env = block.set_environment(previous_env)\n            env = env.set_fork_requirements(fork)\n\n            txs = (\n                [tx.with_signature_and_sender() for tx in block.txs]\n                if block.txs is not None\n                else []\n            )\n\n            next_alloc, result = t8n.evaluate(\n                alloc=previous_alloc,\n                txs=to_json_or_none(txs),\n                env=to_json(env),\n                fork=fork,\n                chain_id=chain_id,\n                reward=fork.get_reward(env.number, env.timestamp),\n                eips=eips,\n            )\n            try:\n                rejected_txs = verify_transactions(txs, result)\n            except Exception as e:\n                print_traces(t8n.get_traces())\n                pprint(result)\n                pprint(previous_alloc)\n                pprint(next_alloc)\n                raise e\n\n            if len(rejected_txs) > 0 and block.exception is None:\n                print_traces(t8n.get_traces())\n                raise Exception(\n                    \"one or more transactions in `BlockchainTest` are \"\n                    + \"intrinsically invalid, but the block was not expected \"\n                    + \"to be invalid. Please verify whether the transaction \"\n                    + \"was indeed expected to fail and add the proper \"\n                    + \"`block.exception`\"\n                )\n\n            header = FixtureHeader.from_dict(\n                result\n                | {\n                    \"parentHash\": env.parent_hash(),\n                    \"miner\": env.coinbase,\n                    \"transactionsRoot\": result.get(\"txRoot\"),\n                    \"difficulty\": str_or_none(result.get(\"currentDifficulty\"), \"0\"),\n                    \"number\": str(env.number),\n                    \"gasLimit\": str(env.gas_limit),\n                    \"timestamp\": str(env.timestamp),\n                    \"extraData\": block.extra_data\n                    if block.extra_data is not None and len(block.extra_data) != 0\n                    else \"0x\",\n                    \"sha3Uncles\": \"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",  # noqa: E501\n                    \"mixHash\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",  # noqa: E501\n                    \"nonce\": \"0x0000000000000000\",\n                    \"baseFeePerGas\": result.get(\"currentBaseFee\"),\n                    \"excessDataGas\": result.get(\"currentExcessDataGas\"),\n                }\n            )\n\n            assert len(header.state_root) == 32\n\n            if block.rlp_modifier is not None:\n                # Modify any parameter specified in the `rlp_modifier` after\n                # transition tool processing.\n                header = header.join(block.rlp_modifier)\n\n            rlp, header.hash = header.build(\n                txs=txs,\n                ommers=[],\n                withdrawals=env.withdrawals,\n            )\n\n            new_payload = FixtureEngineNewPayload.from_fixture_header(\n                fork=fork,\n                header=header,\n                transactions=txs,\n                withdrawals=env.withdrawals,\n                error_code=block.engine_api_error_code,\n            )\n\n            if block.exception is None:\n                # Return environment and allocation of the following block\n                return (\n                    FixtureBlock(\n                        rlp=rlp,\n                        new_payload=new_payload,\n                        block_header=header,\n                        block_number=header.number,\n                        txs=txs,\n                        ommers=[],\n                        withdrawals=env.withdrawals,\n                    ),\n                    env.apply_new_parent(header),\n                    next_alloc,\n                    header.hash,\n                )\n            else:\n                return (\n                    FixtureBlock(\n                        rlp=rlp,\n                        new_payload=new_payload,\n                        expected_exception=block.exception,\n                        block_number=header.number,\n                    ),\n                    previous_env,\n                    previous_alloc,\n                    previous_head,\n                )\n        else:\n            return (\n                FixtureBlock(\n                    rlp=block.rlp,\n                    expected_exception=block.exception,\n                ),\n                previous_env,\n                previous_alloc,\n                previous_head,\n            )\n\n    def make_blocks(\n        self,\n        t8n: TransitionTool,\n        genesis: FixtureHeader,\n        fork: Fork,\n        chain_id=1,\n        eips: Optional[List[int]] = None,\n    ) -> Tuple[List[FixtureBlock], bytes, Dict[str, Any]]:\n\"\"\"\n        Create a block list from the blockchain test definition.\n        Performs checks against the expected behavior of the test.\n        Raises exception on invalid test behavior.\n        \"\"\"\n        alloc = to_json(self.pre)\n        env = Environment.from_parent_header(genesis)\n        blocks: List[FixtureBlock] = []\n        head = genesis.hash if genesis.hash is not None else bytes([0] * 32)\n        for block in self.blocks:\n            fixture_block, env, alloc, head = self.make_block(\n                t8n=t8n,\n                fork=fork,\n                block=block,\n                previous_env=env,\n                previous_alloc=alloc,\n                previous_head=head,\n                chain_id=chain_id,\n                eips=eips,\n            )\n            blocks.append(fixture_block)\n\n        try:\n            verify_post_alloc(self.post, alloc)\n        except Exception as e:\n            print_traces(t8n.get_traces())\n            raise e\n\n        return (blocks, head, alloc)\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.spec.blockchain_test.BlockchainTest.pytest_parameter_name","title":"pytest_parameter_name() classmethod","text":"

Returns the parameter name used to identify this filler in a test.

Source code in src/ethereum_test_tools/spec/blockchain_test.py
@classmethod\ndef pytest_parameter_name(cls) -> str:\n\"\"\"\n    Returns the parameter name used to identify this filler in a test.\n    \"\"\"\n    return \"blockchain_test\"\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.spec.blockchain_test.BlockchainTest.make_genesis","title":"make_genesis(t8n, fork)","text":"

Create a genesis block from the state test definition.

Source code in src/ethereum_test_tools/spec/blockchain_test.py
def make_genesis(\n    self,\n    t8n: TransitionTool,\n    fork: Fork,\n) -> Tuple[bytes, FixtureHeader]:\n\"\"\"\n    Create a genesis block from the state test definition.\n    \"\"\"\n    env = self.genesis_environment.set_fork_requirements(fork)\n\n    genesis = FixtureHeader(\n        parent_hash=EmptyHash,\n        ommers_hash=EmptyOmmersRoot,\n        coinbase=ZeroAddress,\n        state_root=t8n.calc_state_root(\n            to_json(self.pre),\n            fork,\n        ),\n        transactions_root=EmptyTrieRoot,\n        receipt_root=EmptyTrieRoot,\n        bloom=EmptyBloom,\n        difficulty=0x20000 if env.difficulty is None else env.difficulty,\n        number=0,\n        gas_limit=env.gas_limit,\n        gas_used=0,\n        timestamp=0,\n        extra_data=bytes([0]),\n        mix_digest=EmptyHash,\n        nonce=EmptyNonce,\n        base_fee=env.base_fee,\n        data_gas_used=env.data_gas_used,\n        excess_data_gas=env.excess_data_gas,\n        withdrawals_root=t8n.calc_withdrawals_root(env.withdrawals, fork)\n        if env.withdrawals is not None\n        else None,\n    )\n\n    genesis_rlp, genesis.hash = genesis.build(\n        txs=[],\n        ommers=[],\n        withdrawals=env.withdrawals,\n    )\n\n    return genesis_rlp, genesis\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.spec.blockchain_test.BlockchainTest.make_block","title":"make_block(t8n, fork, block, previous_env, previous_alloc, previous_head, chain_id=1, eips=None)","text":"

Produces a block based on the previous environment and allocation. If the block is an invalid block, the environment and allocation returned are the same as passed as parameters. Raises exception on invalid test behavior.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.spec.blockchain_test.BlockchainTest.make_block--returns","title":"Returns","text":"
FixtureBlock: Block to be appended to the fixture.\nEnvironment: Environment for the next block to produce.\n    If the produced block is invalid, this is exactly the same\n    environment as the one passed as parameter.\nDict[str, Any]: Allocation for the next block to produce.\n    If the produced block is invalid, this is exactly the same\n    allocation as the one passed as parameter.\nstr: Hash of the head of the chain, only updated if the produced\n    block is not invalid.\n
Source code in src/ethereum_test_tools/spec/blockchain_test.py
def make_block(\n    self,\n    t8n: TransitionTool,\n    fork: Fork,\n    block: Block,\n    previous_env: Environment,\n    previous_alloc: Dict[str, Any],\n    previous_head: bytes,\n    chain_id=1,\n    eips: Optional[List[int]] = None,\n) -> Tuple[FixtureBlock, Environment, Dict[str, Any], bytes]:\n\"\"\"\n    Produces a block based on the previous environment and allocation.\n    If the block is an invalid block, the environment and allocation\n    returned are the same as passed as parameters.\n    Raises exception on invalid test behavior.\n\n    Returns\n    -------\n        FixtureBlock: Block to be appended to the fixture.\n        Environment: Environment for the next block to produce.\n            If the produced block is invalid, this is exactly the same\n            environment as the one passed as parameter.\n        Dict[str, Any]: Allocation for the next block to produce.\n            If the produced block is invalid, this is exactly the same\n            allocation as the one passed as parameter.\n        str: Hash of the head of the chain, only updated if the produced\n            block is not invalid.\n\n    \"\"\"\n    if block.rlp and block.exception is not None:\n        raise Exception(\n            \"test correctness: post-state cannot be verified if the \"\n            + \"block's rlp is supplied and the block is not supposed \"\n            + \"to produce an exception\"\n        )\n\n    if block.rlp is None:\n        # This is the most common case, the RLP needs to be constructed\n        # based on the transactions to be included in the block.\n        # Set the environment according to the block to execute.\n        env = block.set_environment(previous_env)\n        env = env.set_fork_requirements(fork)\n\n        txs = (\n            [tx.with_signature_and_sender() for tx in block.txs]\n            if block.txs is not None\n            else []\n        )\n\n        next_alloc, result = t8n.evaluate(\n            alloc=previous_alloc,\n            txs=to_json_or_none(txs),\n            env=to_json(env),\n            fork=fork,\n            chain_id=chain_id,\n            reward=fork.get_reward(env.number, env.timestamp),\n            eips=eips,\n        )\n        try:\n            rejected_txs = verify_transactions(txs, result)\n        except Exception as e:\n            print_traces(t8n.get_traces())\n            pprint(result)\n            pprint(previous_alloc)\n            pprint(next_alloc)\n            raise e\n\n        if len(rejected_txs) > 0 and block.exception is None:\n            print_traces(t8n.get_traces())\n            raise Exception(\n                \"one or more transactions in `BlockchainTest` are \"\n                + \"intrinsically invalid, but the block was not expected \"\n                + \"to be invalid. Please verify whether the transaction \"\n                + \"was indeed expected to fail and add the proper \"\n                + \"`block.exception`\"\n            )\n\n        header = FixtureHeader.from_dict(\n            result\n            | {\n                \"parentHash\": env.parent_hash(),\n                \"miner\": env.coinbase,\n                \"transactionsRoot\": result.get(\"txRoot\"),\n                \"difficulty\": str_or_none(result.get(\"currentDifficulty\"), \"0\"),\n                \"number\": str(env.number),\n                \"gasLimit\": str(env.gas_limit),\n                \"timestamp\": str(env.timestamp),\n                \"extraData\": block.extra_data\n                if block.extra_data is not None and len(block.extra_data) != 0\n                else \"0x\",\n                \"sha3Uncles\": \"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",  # noqa: E501\n                \"mixHash\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",  # noqa: E501\n                \"nonce\": \"0x0000000000000000\",\n                \"baseFeePerGas\": result.get(\"currentBaseFee\"),\n                \"excessDataGas\": result.get(\"currentExcessDataGas\"),\n            }\n        )\n\n        assert len(header.state_root) == 32\n\n        if block.rlp_modifier is not None:\n            # Modify any parameter specified in the `rlp_modifier` after\n            # transition tool processing.\n            header = header.join(block.rlp_modifier)\n\n        rlp, header.hash = header.build(\n            txs=txs,\n            ommers=[],\n            withdrawals=env.withdrawals,\n        )\n\n        new_payload = FixtureEngineNewPayload.from_fixture_header(\n            fork=fork,\n            header=header,\n            transactions=txs,\n            withdrawals=env.withdrawals,\n            error_code=block.engine_api_error_code,\n        )\n\n        if block.exception is None:\n            # Return environment and allocation of the following block\n            return (\n                FixtureBlock(\n                    rlp=rlp,\n                    new_payload=new_payload,\n                    block_header=header,\n                    block_number=header.number,\n                    txs=txs,\n                    ommers=[],\n                    withdrawals=env.withdrawals,\n                ),\n                env.apply_new_parent(header),\n                next_alloc,\n                header.hash,\n            )\n        else:\n            return (\n                FixtureBlock(\n                    rlp=rlp,\n                    new_payload=new_payload,\n                    expected_exception=block.exception,\n                    block_number=header.number,\n                ),\n                previous_env,\n                previous_alloc,\n                previous_head,\n            )\n    else:\n        return (\n            FixtureBlock(\n                rlp=block.rlp,\n                expected_exception=block.exception,\n            ),\n            previous_env,\n            previous_alloc,\n            previous_head,\n        )\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.spec.blockchain_test.BlockchainTest.make_blocks","title":"make_blocks(t8n, genesis, fork, chain_id=1, eips=None)","text":"

Create a block list from the blockchain test definition. Performs checks against the expected behavior of the test. Raises exception on invalid test behavior.

Source code in src/ethereum_test_tools/spec/blockchain_test.py
def make_blocks(\n    self,\n    t8n: TransitionTool,\n    genesis: FixtureHeader,\n    fork: Fork,\n    chain_id=1,\n    eips: Optional[List[int]] = None,\n) -> Tuple[List[FixtureBlock], bytes, Dict[str, Any]]:\n\"\"\"\n    Create a block list from the blockchain test definition.\n    Performs checks against the expected behavior of the test.\n    Raises exception on invalid test behavior.\n    \"\"\"\n    alloc = to_json(self.pre)\n    env = Environment.from_parent_header(genesis)\n    blocks: List[FixtureBlock] = []\n    head = genesis.hash if genesis.hash is not None else bytes([0] * 32)\n    for block in self.blocks:\n        fixture_block, env, alloc, head = self.make_block(\n            t8n=t8n,\n            fork=fork,\n            block=block,\n            previous_env=env,\n            previous_alloc=alloc,\n            previous_head=head,\n            chain_id=chain_id,\n            eips=eips,\n        )\n        blocks.append(fixture_block)\n\n    try:\n        verify_post_alloc(self.post, alloc)\n    except Exception as e:\n        print_traces(t8n.get_traces())\n        raise e\n\n    return (blocks, head, alloc)\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.ReferenceSpec","title":"ReferenceSpec","text":"

Reference Specification Description Abstract Class.

Source code in src/ethereum_test_tools/reference_spec/reference_spec.py
class ReferenceSpec:\n\"\"\"\n    Reference Specification Description Abstract Class.\n    \"\"\"\n\n    @abstractmethod\n    def name(self) -> str:\n\"\"\"\n        Returns the name of the spec.\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def has_known_version(self) -> bool:\n\"\"\"\n        Returns true if the reference spec object is hard-coded with a latest\n        known version.\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def known_version(self) -> str:\n\"\"\"\n        Returns the latest known version in the reference.\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def api_url(self) -> str:\n\"\"\"\n        Returns the URL required to poll the version from an API, if needed.\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def latest_version(self) -> str:\n\"\"\"\n        Returns a digest that points to the latest version of the spec.\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def is_outdated(self) -> bool:\n\"\"\"\n        Checks whether the reference specification has been updated since the\n        test was last updated.\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def write_info(self, info: Dict[str, str]):\n\"\"\"\n        Writes info about the reference specification used into the output\n        fixture.\n        \"\"\"\n        pass\n\n    @staticmethod\n    @abstractmethod\n    def parseable_from_module(module_dict: Dict[str, Any]) -> bool:\n\"\"\"\n        Checks whether the module's dict contains required reference spec\n        information.\n        \"\"\"\n        pass\n\n    @staticmethod\n    @abstractmethod\n    def parse_from_module(module_dict: Dict[str, Any]) -> \"ReferenceSpec\":\n\"\"\"\n        Parses the module's dict into a reference spec.\n        \"\"\"\n        pass\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.reference_spec.reference_spec.ReferenceSpec.name","title":"name() abstractmethod","text":"

Returns the name of the spec.

Source code in src/ethereum_test_tools/reference_spec/reference_spec.py
@abstractmethod\ndef name(self) -> str:\n\"\"\"\n    Returns the name of the spec.\n    \"\"\"\n    pass\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.reference_spec.reference_spec.ReferenceSpec.has_known_version","title":"has_known_version() abstractmethod","text":"

Returns true if the reference spec object is hard-coded with a latest known version.

Source code in src/ethereum_test_tools/reference_spec/reference_spec.py
@abstractmethod\ndef has_known_version(self) -> bool:\n\"\"\"\n    Returns true if the reference spec object is hard-coded with a latest\n    known version.\n    \"\"\"\n    pass\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.reference_spec.reference_spec.ReferenceSpec.known_version","title":"known_version() abstractmethod","text":"

Returns the latest known version in the reference.

Source code in src/ethereum_test_tools/reference_spec/reference_spec.py
@abstractmethod\ndef known_version(self) -> str:\n\"\"\"\n    Returns the latest known version in the reference.\n    \"\"\"\n    pass\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.reference_spec.reference_spec.ReferenceSpec.api_url","title":"api_url() abstractmethod","text":"

Returns the URL required to poll the version from an API, if needed.

Source code in src/ethereum_test_tools/reference_spec/reference_spec.py
@abstractmethod\ndef api_url(self) -> str:\n\"\"\"\n    Returns the URL required to poll the version from an API, if needed.\n    \"\"\"\n    pass\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.reference_spec.reference_spec.ReferenceSpec.latest_version","title":"latest_version() abstractmethod","text":"

Returns a digest that points to the latest version of the spec.

Source code in src/ethereum_test_tools/reference_spec/reference_spec.py
@abstractmethod\ndef latest_version(self) -> str:\n\"\"\"\n    Returns a digest that points to the latest version of the spec.\n    \"\"\"\n    pass\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.reference_spec.reference_spec.ReferenceSpec.is_outdated","title":"is_outdated() abstractmethod","text":"

Checks whether the reference specification has been updated since the test was last updated.

Source code in src/ethereum_test_tools/reference_spec/reference_spec.py
@abstractmethod\ndef is_outdated(self) -> bool:\n\"\"\"\n    Checks whether the reference specification has been updated since the\n    test was last updated.\n    \"\"\"\n    pass\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.reference_spec.reference_spec.ReferenceSpec.write_info","title":"write_info(info) abstractmethod","text":"

Writes info about the reference specification used into the output fixture.

Source code in src/ethereum_test_tools/reference_spec/reference_spec.py
@abstractmethod\ndef write_info(self, info: Dict[str, str]):\n\"\"\"\n    Writes info about the reference specification used into the output\n    fixture.\n    \"\"\"\n    pass\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.reference_spec.reference_spec.ReferenceSpec.parseable_from_module","title":"parseable_from_module(module_dict) staticmethod abstractmethod","text":"

Checks whether the module's dict contains required reference spec information.

Source code in src/ethereum_test_tools/reference_spec/reference_spec.py
@staticmethod\n@abstractmethod\ndef parseable_from_module(module_dict: Dict[str, Any]) -> bool:\n\"\"\"\n    Checks whether the module's dict contains required reference spec\n    information.\n    \"\"\"\n    pass\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.reference_spec.reference_spec.ReferenceSpec.parse_from_module","title":"parse_from_module(module_dict) staticmethod abstractmethod","text":"

Parses the module's dict into a reference spec.

Source code in src/ethereum_test_tools/reference_spec/reference_spec.py
@staticmethod\n@abstractmethod\ndef parse_from_module(module_dict: Dict[str, Any]) -> \"ReferenceSpec\":\n\"\"\"\n    Parses the module's dict into a reference spec.\n    \"\"\"\n    pass\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.StateTest","title":"StateTest dataclass","text":"

Bases: BaseTest

Filler type that tests transactions over the period of a single block.

Source code in src/ethereum_test_tools/spec/state_test.py
@dataclass(kw_only=True)\nclass StateTest(BaseTest):\n\"\"\"\n    Filler type that tests transactions over the period of a single block.\n    \"\"\"\n\n    env: Environment\n    pre: Mapping[str, Account]\n    post: Mapping[str, Account]\n    txs: List[Transaction]\n    engine_api_error_code: Optional[EngineAPIError] = None\n    tag: str = \"\"\n\n    @classmethod\n    def pytest_parameter_name(cls) -> str:\n\"\"\"\n        Returns the parameter name used to identify this filler in a test.\n        \"\"\"\n        return \"state_test\"\n\n    def make_genesis(\n        self,\n        t8n: TransitionTool,\n        fork: Fork,\n    ) -> Tuple[bytes, FixtureHeader]:\n\"\"\"\n        Create a genesis block from the state test definition.\n        \"\"\"\n        env = self.env.set_fork_requirements(fork)\n\n        genesis = FixtureHeader(\n            parent_hash=EmptyHash,\n            ommers_hash=EmptyOmmersRoot,\n            coinbase=ZeroAddress,\n            state_root=t8n.calc_state_root(\n                to_json(self.pre),\n                fork,\n            ),\n            transactions_root=EmptyTrieRoot,\n            receipt_root=EmptyTrieRoot,\n            bloom=EmptyBloom,\n            difficulty=0x20000 if env.difficulty is None else env.difficulty,\n            number=env.number - 1,\n            gas_limit=env.gas_limit,\n            gas_used=0,\n            timestamp=0,\n            extra_data=bytes([0]),\n            mix_digest=EmptyHash,\n            nonce=EmptyNonce,\n            base_fee=env.base_fee,\n            data_gas_used=env.data_gas_used,\n            excess_data_gas=env.excess_data_gas,\n            withdrawals_root=t8n.calc_withdrawals_root(env.withdrawals, fork)\n            if env.withdrawals is not None\n            else None,\n        )\n\n        genesis_rlp, genesis.hash = genesis.build(\n            txs=[],\n            ommers=[],\n            withdrawals=env.withdrawals,\n        )\n\n        return genesis_rlp, genesis\n\n    def make_blocks(\n        self,\n        t8n: TransitionTool,\n        genesis: FixtureHeader,\n        fork: Fork,\n        chain_id=1,\n        eips: Optional[List[int]] = None,\n    ) -> Tuple[List[FixtureBlock], bytes, Dict[str, Any]]:\n\"\"\"\n        Create a block from the state test definition.\n        Performs checks against the expected behavior of the test.\n        Raises exception on invalid test behavior.\n        \"\"\"\n        env = self.env.apply_new_parent(genesis)\n        env = env.set_fork_requirements(fork)\n\n        txs = [tx.with_signature_and_sender() for tx in self.txs] if self.txs is not None else []\n\n        alloc, result = t8n.evaluate(\n            alloc=to_json(self.pre),\n            txs=to_json(txs),\n            env=to_json(env),\n            fork=fork,\n            chain_id=chain_id,\n            reward=fork.get_reward(env.number, env.timestamp),\n            eips=eips,\n        )\n\n        rejected_txs = verify_transactions(txs, result)\n        if len(rejected_txs) > 0:\n            raise Exception(\n                \"one or more transactions in `StateTest` are \"\n                + \"intrinsically invalid, which are not allowed. \"\n                + \"Use `BlockchainTest` to verify rejection of blocks \"\n                + \"that include invalid transactions.\"\n            )\n\n        try:\n            verify_post_alloc(self.post, alloc)\n        except Exception as e:\n            print_traces(traces=t8n.get_traces())\n            raise e\n\n        header = FixtureHeader.from_dict(\n            result\n            | {\n                \"parentHash\": genesis.hash,\n                \"miner\": env.coinbase,\n                \"transactionsRoot\": result.get(\"txRoot\"),\n                \"difficulty\": str_or_none(env.difficulty, result.get(\"currentDifficulty\")),\n                \"number\": str(env.number),\n                \"gasLimit\": str(env.gas_limit),\n                \"timestamp\": str(env.timestamp),\n                \"extraData\": \"0x00\",\n                \"sha3Uncles\": \"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\n                \"mixHash\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n                \"nonce\": \"0x0000000000000000\",\n                \"baseFeePerGas\": result.get(\"currentBaseFee\"),\n                \"excessDataGas\": result.get(\"currentExcessDataGas\"),\n            }\n        )\n\n        block, header.hash = header.build(\n            txs=txs,\n            ommers=[],\n            withdrawals=env.withdrawals,\n        )\n\n        new_payload = FixtureEngineNewPayload.from_fixture_header(\n            fork=fork,\n            header=header,\n            transactions=txs,\n            withdrawals=env.withdrawals,\n            error_code=self.engine_api_error_code,\n        )\n\n        return (\n            [\n                FixtureBlock(\n                    rlp=block,\n                    new_payload=new_payload,\n                    block_header=header,\n                    txs=txs,\n                    ommers=[],\n                    withdrawals=env.withdrawals,\n                )\n            ],\n            header.hash,\n            alloc,\n        )\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.spec.state_test.StateTest.pytest_parameter_name","title":"pytest_parameter_name() classmethod","text":"

Returns the parameter name used to identify this filler in a test.

Source code in src/ethereum_test_tools/spec/state_test.py
@classmethod\ndef pytest_parameter_name(cls) -> str:\n\"\"\"\n    Returns the parameter name used to identify this filler in a test.\n    \"\"\"\n    return \"state_test\"\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.spec.state_test.StateTest.make_genesis","title":"make_genesis(t8n, fork)","text":"

Create a genesis block from the state test definition.

Source code in src/ethereum_test_tools/spec/state_test.py
def make_genesis(\n    self,\n    t8n: TransitionTool,\n    fork: Fork,\n) -> Tuple[bytes, FixtureHeader]:\n\"\"\"\n    Create a genesis block from the state test definition.\n    \"\"\"\n    env = self.env.set_fork_requirements(fork)\n\n    genesis = FixtureHeader(\n        parent_hash=EmptyHash,\n        ommers_hash=EmptyOmmersRoot,\n        coinbase=ZeroAddress,\n        state_root=t8n.calc_state_root(\n            to_json(self.pre),\n            fork,\n        ),\n        transactions_root=EmptyTrieRoot,\n        receipt_root=EmptyTrieRoot,\n        bloom=EmptyBloom,\n        difficulty=0x20000 if env.difficulty is None else env.difficulty,\n        number=env.number - 1,\n        gas_limit=env.gas_limit,\n        gas_used=0,\n        timestamp=0,\n        extra_data=bytes([0]),\n        mix_digest=EmptyHash,\n        nonce=EmptyNonce,\n        base_fee=env.base_fee,\n        data_gas_used=env.data_gas_used,\n        excess_data_gas=env.excess_data_gas,\n        withdrawals_root=t8n.calc_withdrawals_root(env.withdrawals, fork)\n        if env.withdrawals is not None\n        else None,\n    )\n\n    genesis_rlp, genesis.hash = genesis.build(\n        txs=[],\n        ommers=[],\n        withdrawals=env.withdrawals,\n    )\n\n    return genesis_rlp, genesis\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.spec.state_test.StateTest.make_blocks","title":"make_blocks(t8n, genesis, fork, chain_id=1, eips=None)","text":"

Create a block from the state test definition. Performs checks against the expected behavior of the test. Raises exception on invalid test behavior.

Source code in src/ethereum_test_tools/spec/state_test.py
def make_blocks(\n    self,\n    t8n: TransitionTool,\n    genesis: FixtureHeader,\n    fork: Fork,\n    chain_id=1,\n    eips: Optional[List[int]] = None,\n) -> Tuple[List[FixtureBlock], bytes, Dict[str, Any]]:\n\"\"\"\n    Create a block from the state test definition.\n    Performs checks against the expected behavior of the test.\n    Raises exception on invalid test behavior.\n    \"\"\"\n    env = self.env.apply_new_parent(genesis)\n    env = env.set_fork_requirements(fork)\n\n    txs = [tx.with_signature_and_sender() for tx in self.txs] if self.txs is not None else []\n\n    alloc, result = t8n.evaluate(\n        alloc=to_json(self.pre),\n        txs=to_json(txs),\n        env=to_json(env),\n        fork=fork,\n        chain_id=chain_id,\n        reward=fork.get_reward(env.number, env.timestamp),\n        eips=eips,\n    )\n\n    rejected_txs = verify_transactions(txs, result)\n    if len(rejected_txs) > 0:\n        raise Exception(\n            \"one or more transactions in `StateTest` are \"\n            + \"intrinsically invalid, which are not allowed. \"\n            + \"Use `BlockchainTest` to verify rejection of blocks \"\n            + \"that include invalid transactions.\"\n        )\n\n    try:\n        verify_post_alloc(self.post, alloc)\n    except Exception as e:\n        print_traces(traces=t8n.get_traces())\n        raise e\n\n    header = FixtureHeader.from_dict(\n        result\n        | {\n            \"parentHash\": genesis.hash,\n            \"miner\": env.coinbase,\n            \"transactionsRoot\": result.get(\"txRoot\"),\n            \"difficulty\": str_or_none(env.difficulty, result.get(\"currentDifficulty\")),\n            \"number\": str(env.number),\n            \"gasLimit\": str(env.gas_limit),\n            \"timestamp\": str(env.timestamp),\n            \"extraData\": \"0x00\",\n            \"sha3Uncles\": \"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\n            \"mixHash\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n            \"nonce\": \"0x0000000000000000\",\n            \"baseFeePerGas\": result.get(\"currentBaseFee\"),\n            \"excessDataGas\": result.get(\"currentExcessDataGas\"),\n        }\n    )\n\n    block, header.hash = header.build(\n        txs=txs,\n        ommers=[],\n        withdrawals=env.withdrawals,\n    )\n\n    new_payload = FixtureEngineNewPayload.from_fixture_header(\n        fork=fork,\n        header=header,\n        transactions=txs,\n        withdrawals=env.withdrawals,\n        error_code=self.engine_api_error_code,\n    )\n\n    return (\n        [\n            FixtureBlock(\n                rlp=block,\n                new_payload=new_payload,\n                block_header=header,\n                txs=txs,\n                ommers=[],\n                withdrawals=env.withdrawals,\n            )\n        ],\n        header.hash,\n        alloc,\n    )\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.Yul","title":"Yul","text":"

Bases: Code

Yul compiler. Compiles Yul source code into bytecode.

Source code in src/ethereum_test_tools/code/yul.py
class Yul(Code):\n\"\"\"\n    Yul compiler.\n    Compiles Yul source code into bytecode.\n    \"\"\"\n\n    source: str\n    compiled: Optional[bytes] = None\n\n    def __init__(\n        self,\n        source: str,\n        fork: Optional[Fork] = None,\n        binary: Optional[Path | str] = None,\n    ):\n        self.source = source\n        self.evm_version = get_evm_version_from_fork(fork)\n        if binary is None:\n            which_path = which(\"solc\")\n            if which_path is not None:\n                binary = Path(which_path)\n        if binary is None or not Path(binary).exists():\n            raise Exception(\n\"\"\"`solc` binary executable not found, please refer to\n                https://docs.soliditylang.org/en/latest/installing-solidity.html\n                for help downloading and installing `solc`\"\"\"\n            )\n        self.binary = Path(binary)\n\n    def assemble(self) -> bytes:\n\"\"\"\n        Assembles using `solc --assemble`.\n        \"\"\"\n        if not self.compiled:\n            solc_args: Tuple[Union[Path, str], ...] = ()\n            if self.evm_version:\n                solc_args = (\n                    self.binary,\n                    \"--evm-version\",\n                    self.evm_version,\n                    *DEFAULT_SOLC_ARGS,\n                )\n            else:\n                solc_args = (self.binary, *DEFAULT_SOLC_ARGS)\n            result = run(\n                solc_args,\n                input=str.encode(self.source),\n                stdout=PIPE,\n                stderr=PIPE,\n            )\n\n            if result.returncode != 0:\n                stderr_lines = result.stderr.decode().split(\"\\n\")\n                stderr_message = \"\\n\".join(line.strip() for line in stderr_lines)\n                raise Exception(f\"failed to compile yul source:\\n{stderr_message[7:]}\")\n\n            lines = result.stdout.decode().split(\"\\n\")\n\n            hex_str = lines[lines.index(\"Binary representation:\") + 1]\n\n            self.compiled = bytes.fromhex(hex_str)\n        return self.compiled\n\n    def version(self) -> str:\n\"\"\"\n        Return solc's version string\n        \"\"\"\n        result = run(\n            [self.binary, \"--version\"],\n            stdout=PIPE,\n            stderr=PIPE,\n        )\n        solc_output = result.stdout.decode().split(\"\\n\")\n        version_pattern = r\"0\\.\\d+\\.\\d+\\+\\S+\"\n        solc_version_string = None\n        for line in solc_output:\n            match = re.search(version_pattern, line)\n            if match:\n                solc_version_string = match.group(0)\n                break\n        if not solc_version_string:\n            warnings.warn(\"Unable to determine solc version.\")\n            solc_version_string = \"unknown\"\n        return solc_version_string\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.code.yul.Yul.assemble","title":"assemble()","text":"

Assembles using solc --assemble.

Source code in src/ethereum_test_tools/code/yul.py
def assemble(self) -> bytes:\n\"\"\"\n    Assembles using `solc --assemble`.\n    \"\"\"\n    if not self.compiled:\n        solc_args: Tuple[Union[Path, str], ...] = ()\n        if self.evm_version:\n            solc_args = (\n                self.binary,\n                \"--evm-version\",\n                self.evm_version,\n                *DEFAULT_SOLC_ARGS,\n            )\n        else:\n            solc_args = (self.binary, *DEFAULT_SOLC_ARGS)\n        result = run(\n            solc_args,\n            input=str.encode(self.source),\n            stdout=PIPE,\n            stderr=PIPE,\n        )\n\n        if result.returncode != 0:\n            stderr_lines = result.stderr.decode().split(\"\\n\")\n            stderr_message = \"\\n\".join(line.strip() for line in stderr_lines)\n            raise Exception(f\"failed to compile yul source:\\n{stderr_message[7:]}\")\n\n        lines = result.stdout.decode().split(\"\\n\")\n\n        hex_str = lines[lines.index(\"Binary representation:\") + 1]\n\n        self.compiled = bytes.fromhex(hex_str)\n    return self.compiled\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.code.yul.Yul.version","title":"version()","text":"

Return solc's version string

Source code in src/ethereum_test_tools/code/yul.py
def version(self) -> str:\n\"\"\"\n    Return solc's version string\n    \"\"\"\n    result = run(\n        [self.binary, \"--version\"],\n        stdout=PIPE,\n        stderr=PIPE,\n    )\n    solc_output = result.stdout.decode().split(\"\\n\")\n    version_pattern = r\"0\\.\\d+\\.\\d+\\+\\S+\"\n    solc_version_string = None\n    for line in solc_output:\n        match = re.search(version_pattern, line)\n        if match:\n            solc_version_string = match.group(0)\n            break\n    if not solc_version_string:\n        warnings.warn(\"Unable to determine solc version.\")\n        solc_version_string = \"unknown\"\n    return solc_version_string\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.compute_create2_address","title":"compute_create2_address(address, salt, initcode)","text":"

Compute address of the resulting contract created using the CREATE2 opcode.

Source code in src/ethereum_test_tools/common/helpers.py
def compute_create2_address(address: str | int, salt: int, initcode: bytes) -> str:\n\"\"\"\n    Compute address of the resulting contract created using the `CREATE2`\n    opcode.\n    \"\"\"\n    ff = bytes([0xFF])\n    if type(address) is str:\n        if address.startswith(\"0x\"):\n            address = address[2:]\n        address_bytes = bytes.fromhex(address)\n    elif type(address) is int:\n        address_bytes = address.to_bytes(length=20, byteorder=\"big\")\n    salt_bytes = salt.to_bytes(length=32, byteorder=\"big\")\n    initcode_hash = keccak256(initcode)\n    hash = keccak256(ff + address_bytes + salt_bytes + initcode_hash)\n    return \"0x\" + hash[-20:].hex()\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.cost_memory_bytes","title":"cost_memory_bytes(new_bytes, previous_bytes)","text":"

Calculates the cost of memory expansion, based on the costs specified in the yellow paper: https://ethereum.github.io/yellowpaper/paper.pdf

Source code in src/ethereum_test_tools/common/helpers.py
def cost_memory_bytes(new_bytes: int, previous_bytes: int) -> int:\n\"\"\"\n    Calculates the cost of memory expansion, based on the costs specified in\n    the yellow paper: https://ethereum.github.io/yellowpaper/paper.pdf\n    \"\"\"\n    if new_bytes <= previous_bytes:\n        return 0\n    new_words = ceiling_division(new_bytes, 32)\n    previous_words = ceiling_division(previous_bytes, 32)\n\n    def c(w: int) -> int:\n        g_memory = 3\n        return (g_memory * w) + ((w * w) // 512)\n\n    return c(new_words) - c(previous_words)\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.Auto","title":"Auto","text":"

Class to use as a sentinel value for parameters that should be automatically calculated.

Source code in src/ethereum_test_tools/common/types.py
class Auto:\n\"\"\"\n    Class to use as a sentinel value for parameters that should be\n    automatically calculated.\n    \"\"\"\n\n    def __repr__(self) -> str:\n\"\"\"Print the correct test id.\"\"\"\n        return \"auto\"\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Auto.__repr__","title":"__repr__()","text":"

Print the correct test id.

Source code in src/ethereum_test_tools/common/types.py
def __repr__(self) -> str:\n\"\"\"Print the correct test id.\"\"\"\n    return \"auto\"\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.BaseTest","title":"BaseTest","text":"

Represents a base Ethereum test which must return a genesis and a blockchain.

Source code in src/ethereum_test_tools/spec/base_test.py
class BaseTest:\n\"\"\"\n    Represents a base Ethereum test which must return a genesis and a\n    blockchain.\n    \"\"\"\n\n    pre: Mapping[str, Account]\n    tag: str = \"\"\n\n    @abstractmethod\n    def make_genesis(\n        self,\n        t8n: TransitionTool,\n        fork: Fork,\n    ) -> Tuple[bytes, FixtureHeader]:\n\"\"\"\n        Create a genesis block from the test definition.\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def make_blocks(\n        self,\n        t8n: TransitionTool,\n        genesis: FixtureHeader,\n        fork: Fork,\n        chain_id: int = 1,\n        eips: Optional[List[int]] = None,\n    ) -> Tuple[List[FixtureBlock], bytes, Dict[str, Any]]:\n\"\"\"\n        Generate the blockchain that must be executed sequentially during test.\n        \"\"\"\n        pass\n\n    @classmethod\n    @abstractmethod\n    def pytest_parameter_name(cls) -> str:\n\"\"\"\n        Must return the name of the parameter used in pytest to select this\n        spec type as filler for the test.\n        \"\"\"\n        pass\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.spec.base_test.BaseTest.make_genesis","title":"make_genesis(t8n, fork) abstractmethod","text":"

Create a genesis block from the test definition.

Source code in src/ethereum_test_tools/spec/base_test.py
@abstractmethod\ndef make_genesis(\n    self,\n    t8n: TransitionTool,\n    fork: Fork,\n) -> Tuple[bytes, FixtureHeader]:\n\"\"\"\n    Create a genesis block from the test definition.\n    \"\"\"\n    pass\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.spec.base_test.BaseTest.make_blocks","title":"make_blocks(t8n, genesis, fork, chain_id=1, eips=None) abstractmethod","text":"

Generate the blockchain that must be executed sequentially during test.

Source code in src/ethereum_test_tools/spec/base_test.py
@abstractmethod\ndef make_blocks(\n    self,\n    t8n: TransitionTool,\n    genesis: FixtureHeader,\n    fork: Fork,\n    chain_id: int = 1,\n    eips: Optional[List[int]] = None,\n) -> Tuple[List[FixtureBlock], bytes, Dict[str, Any]]:\n\"\"\"\n    Generate the blockchain that must be executed sequentially during test.\n    \"\"\"\n    pass\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.spec.base_test.BaseTest.pytest_parameter_name","title":"pytest_parameter_name() classmethod abstractmethod","text":"

Must return the name of the parameter used in pytest to select this spec type as filler for the test.

Source code in src/ethereum_test_tools/spec/base_test.py
@classmethod\n@abstractmethod\ndef pytest_parameter_name(cls) -> str:\n\"\"\"\n    Must return the name of the parameter used in pytest to select this\n    spec type as filler for the test.\n    \"\"\"\n    pass\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.copy_opcode_cost","title":"copy_opcode_cost(length)","text":"

Calculates the cost of the COPY opcodes, assuming memory expansion from empty memory, based on the costs specified in the yellow paper: https://ethereum.github.io/yellowpaper/paper.pdf

Source code in src/ethereum_test_tools/common/helpers.py
def copy_opcode_cost(length: int) -> int:\n\"\"\"\n    Calculates the cost of the COPY opcodes, assuming memory expansion from\n    empty memory, based on the costs specified in the yellow paper:\n    https://ethereum.github.io/yellowpaper/paper.pdf\n    \"\"\"\n    return 3 + (ceiling_division(length, 32) * 3) + cost_memory_bytes(length, 0)\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.Storage","title":"Storage","text":"

Definition of a storage in pre or post state of a test

Source code in src/ethereum_test_tools/common/types.py
class Storage:\n\"\"\"\n    Definition of a storage in pre or post state of a test\n    \"\"\"\n\n    data: Dict[int, int]\n\n    StorageDictType: ClassVar[TypeAlias] = Dict[str | int | bytes, str | int | bytes]\n\"\"\"\n    Dictionary type to be used when defining an input to initialize a storage.\n    \"\"\"\n\n    class InvalidType(Exception):\n\"\"\"\n        Invalid type used when describing test's expected storage key or value.\n        \"\"\"\n\n        key_or_value: Any\n\n        def __init__(self, key_or_value: Any, *args):\n            super().__init__(args)\n            self.key_or_value = key_or_value\n\n        def __str__(self):\n\"\"\"Print exception string\"\"\"\n            return f\"invalid type for key/value: {self.key_or_value}\"\n\n    class InvalidValue(Exception):\n\"\"\"\n        Invalid value used when describing test's expected storage key or\n        value.\n        \"\"\"\n\n        key_or_value: Any\n\n        def __init__(self, key_or_value: Any, *args):\n            super().__init__(args)\n            self.key_or_value = key_or_value\n\n        def __str__(self):\n\"\"\"Print exception string\"\"\"\n            return f\"invalid value for key/value: {self.key_or_value}\"\n\n    class AmbiguousKeyValue(Exception):\n\"\"\"\n        Key is represented twice in the storage.\n        \"\"\"\n\n        key_1: str | int\n        val_1: str | int\n        key_2: str | int\n        val_2: str | int\n\n        def __init__(\n            self,\n            key_1: str | int,\n            val_1: str | int,\n            key_2: str | int,\n            val_2: str | int,\n            *args,\n        ):\n            super().__init__(args)\n            self.key_1 = key_1\n            self.val_1 = val_1\n            self.key_2 = key_2\n            self.val_2 = val_2\n\n        def __str__(self):\n\"\"\"Print exception string\"\"\"\n            return f\"\"\"\n            Key is represented twice (due to negative numbers) with different\n            values in storage:\n            s[{self.key_1}] = {self.val_1} and s[{self.key_2}] = {self.val_2}\n            \"\"\"\n\n    class MissingKey(Exception):\n\"\"\"\n        Test expected to find a storage key set but key was missing.\n        \"\"\"\n\n        key: int\n\n        def __init__(self, key: int, *args):\n            super().__init__(args)\n            self.key = key\n\n        def __str__(self):\n\"\"\"Print exception string\"\"\"\n            return \"key {0} not found in storage\".format(Storage.key_value_to_string(self.key))\n\n    class KeyValueMismatch(Exception):\n\"\"\"\n        Test expected a certain value in a storage key but value found\n        was different.\n        \"\"\"\n\n        key: int\n        want: int\n        got: int\n\n        def __init__(self, key: int, want: int, got: int, *args):\n            super().__init__(args)\n            self.key = key\n            self.want = want\n            self.got = got\n\n        def __str__(self):\n\"\"\"Print exception string\"\"\"\n            return (\n                \"incorrect value for key {0}: want {1} (dec:{2}),\" + \" got {3} (dec:{4})\"\n            ).format(\n                Storage.key_value_to_string(self.key),\n                Storage.key_value_to_string(self.want),\n                self.want,\n                Storage.key_value_to_string(self.got),\n                self.got,\n            )\n\n    @staticmethod\n    def parse_key_value(input: str | int | bytes) -> int:\n\"\"\"\n        Parses a key or value to a valid int key for storage.\n        \"\"\"\n        if type(input) is str:\n            input = int(input, 0)\n        elif type(input) is int:\n            pass\n        elif type(input) is bytes:\n            input = int.from_bytes(input, \"big\")\n        else:\n            raise Storage.InvalidType(input)\n\n        if input > MAX_STORAGE_KEY_VALUE or input < MIN_STORAGE_KEY_VALUE:\n            raise Storage.InvalidValue(input)\n        return input\n\n    @staticmethod\n    def key_value_to_string(value: int) -> str:\n\"\"\"\n        Transforms a key or value into an hex string.\n        \"\"\"\n        hex_str = value.to_bytes(32, \"big\", signed=(value < 0)).hex().lstrip(\"0\")\n        if hex_str == \"\":\n            hex_str = \"00\"\n        if len(hex_str) % 2 != 0:\n            hex_str = \"0\" + hex_str\n        return \"0x\" + hex_str\n\n    def __init__(self, input: StorageDictType):\n\"\"\"\n        Initializes the storage using a given mapping which can have\n        keys and values either as string or int.\n        Strings must be valid decimal or hexadecimal (starting with 0x)\n        numbers.\n        \"\"\"\n        self.data = {}\n        for key in input:\n            value = Storage.parse_key_value(input[key])\n            key = Storage.parse_key_value(key)\n            self.data[key] = value\n        pass\n\n    def __len__(self) -> int:\n\"\"\"Returns number of elements in the storage\"\"\"\n        return len(self.data)\n\n    def __contains__(self, key: str | int) -> bool:\n\"\"\"Checks for an item in the storage\"\"\"\n        key = Storage.parse_key_value(key)\n        return key in self.data\n\n    def __getitem__(self, key: str | int) -> int:\n\"\"\"Returns an item from the storage\"\"\"\n        key = Storage.parse_key_value(key)\n        if key not in self.data:\n            raise KeyError()\n        return self.data[key]\n\n    def __setitem__(self, key: str | int, value: str | int):  # noqa: SC200\n\"\"\"Sets an item in the storage\"\"\"\n        self.data[Storage.parse_key_value(key)] = Storage.parse_key_value(value)\n\n    def __delitem__(self, key: str | int):\n\"\"\"Deletes an item from the storage\"\"\"\n        del self.data[Storage.parse_key_value(key)]\n\n    def to_dict(self) -> Mapping[str, str]:\n\"\"\"\n        Converts the storage into a string dict with appropriate 32-byte\n        hex string formatting.\n        \"\"\"\n        res: Dict[str, str] = {}\n        for key in self.data:\n            key_repr = Storage.key_value_to_string(key)\n            val_repr = Storage.key_value_to_string(self.data[key])\n            if key_repr in res and val_repr != res[key_repr]:\n                raise Storage.AmbiguousKeyValue(key_repr, res[key_repr], key, val_repr)\n            res[key_repr] = val_repr\n        return res\n\n    def contains(self, other: \"Storage\") -> bool:\n\"\"\"\n        Returns True if self contains all keys with equal value as\n        contained by second storage.\n        Used for comparison with test expected post state and alloc returned\n        by the transition tool.\n        \"\"\"\n        for key in other.data:\n            if key not in self.data:\n                return False\n            if self.data[key] != other.data[key]:\n                return False\n        return True\n\n    def must_contain(self, other: \"Storage\"):\n\"\"\"\n        Succeeds only if self contains all keys with equal value as\n        contained by second storage.\n        Used for comparison with test expected post state and alloc returned\n        by the transition tool.\n        Raises detailed exception when a difference is found.\n        \"\"\"\n        for key in other.data:\n            if key not in self.data:\n                # storage[key]==0 is equal to missing storage\n                if other[key] != 0:\n                    raise Storage.MissingKey(key)\n            elif self.data[key] != other.data[key]:\n                raise Storage.KeyValueMismatch(key, self.data[key], other.data[key])\n\n    def must_be_equal(self, other: \"Storage\"):\n\"\"\"\n        Succeeds only if \"self\" is equal to \"other\" storage.\n        \"\"\"\n        # Test keys contained in both storage objects\n        for key in self.data.keys() & other.data.keys():\n            if self.data[key] != other.data[key]:\n                raise Storage.KeyValueMismatch(key, self.data[key], other.data[key])\n\n        # Test keys contained in either one of the storage objects\n        for key in self.data.keys() ^ other.data.keys():\n            if key in self.data:\n                if self.data[key] != 0:\n                    raise Storage.KeyValueMismatch(key, self.data[key], 0)\n\n            elif other.data[key] != 0:\n                raise Storage.KeyValueMismatch(key, 0, other.data[key])\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.StorageDictType","title":"StorageDictType: TypeAlias = Dict[str | int | bytes, str | int | bytes] class-attribute","text":"

Dictionary type to be used when defining an input to initialize a storage.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.InvalidType","title":"InvalidType","text":"

Bases: Exception

Invalid type used when describing test's expected storage key or value.

Source code in src/ethereum_test_tools/common/types.py
class InvalidType(Exception):\n\"\"\"\n    Invalid type used when describing test's expected storage key or value.\n    \"\"\"\n\n    key_or_value: Any\n\n    def __init__(self, key_or_value: Any, *args):\n        super().__init__(args)\n        self.key_or_value = key_or_value\n\n    def __str__(self):\n\"\"\"Print exception string\"\"\"\n        return f\"invalid type for key/value: {self.key_or_value}\"\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.InvalidType.__str__","title":"__str__()","text":"

Print exception string

Source code in src/ethereum_test_tools/common/types.py
def __str__(self):\n\"\"\"Print exception string\"\"\"\n    return f\"invalid type for key/value: {self.key_or_value}\"\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.InvalidValue","title":"InvalidValue","text":"

Bases: Exception

Invalid value used when describing test's expected storage key or value.

Source code in src/ethereum_test_tools/common/types.py
class InvalidValue(Exception):\n\"\"\"\n    Invalid value used when describing test's expected storage key or\n    value.\n    \"\"\"\n\n    key_or_value: Any\n\n    def __init__(self, key_or_value: Any, *args):\n        super().__init__(args)\n        self.key_or_value = key_or_value\n\n    def __str__(self):\n\"\"\"Print exception string\"\"\"\n        return f\"invalid value for key/value: {self.key_or_value}\"\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.InvalidValue.__str__","title":"__str__()","text":"

Print exception string

Source code in src/ethereum_test_tools/common/types.py
def __str__(self):\n\"\"\"Print exception string\"\"\"\n    return f\"invalid value for key/value: {self.key_or_value}\"\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.AmbiguousKeyValue","title":"AmbiguousKeyValue","text":"

Bases: Exception

Key is represented twice in the storage.

Source code in src/ethereum_test_tools/common/types.py
class AmbiguousKeyValue(Exception):\n\"\"\"\n    Key is represented twice in the storage.\n    \"\"\"\n\n    key_1: str | int\n    val_1: str | int\n    key_2: str | int\n    val_2: str | int\n\n    def __init__(\n        self,\n        key_1: str | int,\n        val_1: str | int,\n        key_2: str | int,\n        val_2: str | int,\n        *args,\n    ):\n        super().__init__(args)\n        self.key_1 = key_1\n        self.val_1 = val_1\n        self.key_2 = key_2\n        self.val_2 = val_2\n\n    def __str__(self):\n\"\"\"Print exception string\"\"\"\n        return f\"\"\"\n        Key is represented twice (due to negative numbers) with different\n        values in storage:\n        s[{self.key_1}] = {self.val_1} and s[{self.key_2}] = {self.val_2}\n        \"\"\"\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.AmbiguousKeyValue.__str__","title":"__str__()","text":"

Print exception string

Source code in src/ethereum_test_tools/common/types.py
def __str__(self):\n\"\"\"Print exception string\"\"\"\n    return f\"\"\"\n    Key is represented twice (due to negative numbers) with different\n    values in storage:\n    s[{self.key_1}] = {self.val_1} and s[{self.key_2}] = {self.val_2}\n    \"\"\"\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.MissingKey","title":"MissingKey","text":"

Bases: Exception

Test expected to find a storage key set but key was missing.

Source code in src/ethereum_test_tools/common/types.py
class MissingKey(Exception):\n\"\"\"\n    Test expected to find a storage key set but key was missing.\n    \"\"\"\n\n    key: int\n\n    def __init__(self, key: int, *args):\n        super().__init__(args)\n        self.key = key\n\n    def __str__(self):\n\"\"\"Print exception string\"\"\"\n        return \"key {0} not found in storage\".format(Storage.key_value_to_string(self.key))\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.MissingKey.__str__","title":"__str__()","text":"

Print exception string

Source code in src/ethereum_test_tools/common/types.py
def __str__(self):\n\"\"\"Print exception string\"\"\"\n    return \"key {0} not found in storage\".format(Storage.key_value_to_string(self.key))\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.KeyValueMismatch","title":"KeyValueMismatch","text":"

Bases: Exception

Test expected a certain value in a storage key but value found was different.

Source code in src/ethereum_test_tools/common/types.py
class KeyValueMismatch(Exception):\n\"\"\"\n    Test expected a certain value in a storage key but value found\n    was different.\n    \"\"\"\n\n    key: int\n    want: int\n    got: int\n\n    def __init__(self, key: int, want: int, got: int, *args):\n        super().__init__(args)\n        self.key = key\n        self.want = want\n        self.got = got\n\n    def __str__(self):\n\"\"\"Print exception string\"\"\"\n        return (\n            \"incorrect value for key {0}: want {1} (dec:{2}),\" + \" got {3} (dec:{4})\"\n        ).format(\n            Storage.key_value_to_string(self.key),\n            Storage.key_value_to_string(self.want),\n            self.want,\n            Storage.key_value_to_string(self.got),\n            self.got,\n        )\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.KeyValueMismatch.__str__","title":"__str__()","text":"

Print exception string

Source code in src/ethereum_test_tools/common/types.py
def __str__(self):\n\"\"\"Print exception string\"\"\"\n    return (\n        \"incorrect value for key {0}: want {1} (dec:{2}),\" + \" got {3} (dec:{4})\"\n    ).format(\n        Storage.key_value_to_string(self.key),\n        Storage.key_value_to_string(self.want),\n        self.want,\n        Storage.key_value_to_string(self.got),\n        self.got,\n    )\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.parse_key_value","title":"parse_key_value(input) staticmethod","text":"

Parses a key or value to a valid int key for storage.

Source code in src/ethereum_test_tools/common/types.py
@staticmethod\ndef parse_key_value(input: str | int | bytes) -> int:\n\"\"\"\n    Parses a key or value to a valid int key for storage.\n    \"\"\"\n    if type(input) is str:\n        input = int(input, 0)\n    elif type(input) is int:\n        pass\n    elif type(input) is bytes:\n        input = int.from_bytes(input, \"big\")\n    else:\n        raise Storage.InvalidType(input)\n\n    if input > MAX_STORAGE_KEY_VALUE or input < MIN_STORAGE_KEY_VALUE:\n        raise Storage.InvalidValue(input)\n    return input\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.key_value_to_string","title":"key_value_to_string(value) staticmethod","text":"

Transforms a key or value into an hex string.

Source code in src/ethereum_test_tools/common/types.py
@staticmethod\ndef key_value_to_string(value: int) -> str:\n\"\"\"\n    Transforms a key or value into an hex string.\n    \"\"\"\n    hex_str = value.to_bytes(32, \"big\", signed=(value < 0)).hex().lstrip(\"0\")\n    if hex_str == \"\":\n        hex_str = \"00\"\n    if len(hex_str) % 2 != 0:\n        hex_str = \"0\" + hex_str\n    return \"0x\" + hex_str\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.__init__","title":"__init__(input)","text":"

Initializes the storage using a given mapping which can have keys and values either as string or int. Strings must be valid decimal or hexadecimal (starting with 0x) numbers.

Source code in src/ethereum_test_tools/common/types.py
def __init__(self, input: StorageDictType):\n\"\"\"\n    Initializes the storage using a given mapping which can have\n    keys and values either as string or int.\n    Strings must be valid decimal or hexadecimal (starting with 0x)\n    numbers.\n    \"\"\"\n    self.data = {}\n    for key in input:\n        value = Storage.parse_key_value(input[key])\n        key = Storage.parse_key_value(key)\n        self.data[key] = value\n    pass\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.__len__","title":"__len__()","text":"

Returns number of elements in the storage

Source code in src/ethereum_test_tools/common/types.py
def __len__(self) -> int:\n\"\"\"Returns number of elements in the storage\"\"\"\n    return len(self.data)\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.__contains__","title":"__contains__(key)","text":"

Checks for an item in the storage

Source code in src/ethereum_test_tools/common/types.py
def __contains__(self, key: str | int) -> bool:\n\"\"\"Checks for an item in the storage\"\"\"\n    key = Storage.parse_key_value(key)\n    return key in self.data\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.__getitem__","title":"__getitem__(key)","text":"

Returns an item from the storage

Source code in src/ethereum_test_tools/common/types.py
def __getitem__(self, key: str | int) -> int:\n\"\"\"Returns an item from the storage\"\"\"\n    key = Storage.parse_key_value(key)\n    if key not in self.data:\n        raise KeyError()\n    return self.data[key]\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.__setitem__","title":"__setitem__(key, value)","text":"

Sets an item in the storage

Source code in src/ethereum_test_tools/common/types.py
def __setitem__(self, key: str | int, value: str | int):  # noqa: SC200\n\"\"\"Sets an item in the storage\"\"\"\n    self.data[Storage.parse_key_value(key)] = Storage.parse_key_value(value)\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.__delitem__","title":"__delitem__(key)","text":"

Deletes an item from the storage

Source code in src/ethereum_test_tools/common/types.py
def __delitem__(self, key: str | int):\n\"\"\"Deletes an item from the storage\"\"\"\n    del self.data[Storage.parse_key_value(key)]\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.to_dict","title":"to_dict()","text":"

Converts the storage into a string dict with appropriate 32-byte hex string formatting.

Source code in src/ethereum_test_tools/common/types.py
def to_dict(self) -> Mapping[str, str]:\n\"\"\"\n    Converts the storage into a string dict with appropriate 32-byte\n    hex string formatting.\n    \"\"\"\n    res: Dict[str, str] = {}\n    for key in self.data:\n        key_repr = Storage.key_value_to_string(key)\n        val_repr = Storage.key_value_to_string(self.data[key])\n        if key_repr in res and val_repr != res[key_repr]:\n            raise Storage.AmbiguousKeyValue(key_repr, res[key_repr], key, val_repr)\n        res[key_repr] = val_repr\n    return res\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.contains","title":"contains(other)","text":"

Returns True if self contains all keys with equal value as contained by second storage. Used for comparison with test expected post state and alloc returned by the transition tool.

Source code in src/ethereum_test_tools/common/types.py
def contains(self, other: \"Storage\") -> bool:\n\"\"\"\n    Returns True if self contains all keys with equal value as\n    contained by second storage.\n    Used for comparison with test expected post state and alloc returned\n    by the transition tool.\n    \"\"\"\n    for key in other.data:\n        if key not in self.data:\n            return False\n        if self.data[key] != other.data[key]:\n            return False\n    return True\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.must_contain","title":"must_contain(other)","text":"

Succeeds only if self contains all keys with equal value as contained by second storage. Used for comparison with test expected post state and alloc returned by the transition tool. Raises detailed exception when a difference is found.

Source code in src/ethereum_test_tools/common/types.py
def must_contain(self, other: \"Storage\"):\n\"\"\"\n    Succeeds only if self contains all keys with equal value as\n    contained by second storage.\n    Used for comparison with test expected post state and alloc returned\n    by the transition tool.\n    Raises detailed exception when a difference is found.\n    \"\"\"\n    for key in other.data:\n        if key not in self.data:\n            # storage[key]==0 is equal to missing storage\n            if other[key] != 0:\n                raise Storage.MissingKey(key)\n        elif self.data[key] != other.data[key]:\n            raise Storage.KeyValueMismatch(key, self.data[key], other.data[key])\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.must_be_equal","title":"must_be_equal(other)","text":"

Succeeds only if \"self\" is equal to \"other\" storage.

Source code in src/ethereum_test_tools/common/types.py
def must_be_equal(self, other: \"Storage\"):\n\"\"\"\n    Succeeds only if \"self\" is equal to \"other\" storage.\n    \"\"\"\n    # Test keys contained in both storage objects\n    for key in self.data.keys() & other.data.keys():\n        if self.data[key] != other.data[key]:\n            raise Storage.KeyValueMismatch(key, self.data[key], other.data[key])\n\n    # Test keys contained in either one of the storage objects\n    for key in self.data.keys() ^ other.data.keys():\n        if key in self.data:\n            if self.data[key] != 0:\n                raise Storage.KeyValueMismatch(key, self.data[key], 0)\n\n        elif other.data[key] != 0:\n            raise Storage.KeyValueMismatch(key, 0, other.data[key])\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.eip_2028_transaction_data_cost","title":"eip_2028_transaction_data_cost(data)","text":"

Calculates the cost of a given data as part of a transaction, based on the costs specified in EIP-2028: https://eips.ethereum.org/EIPS/eip-2028

Source code in src/ethereum_test_tools/common/helpers.py
def eip_2028_transaction_data_cost(data: bytes | str) -> int:\n\"\"\"\n    Calculates the cost of a given data as part of a transaction, based on the\n    costs specified in EIP-2028: https://eips.ethereum.org/EIPS/eip-2028\n    \"\"\"\n    if type(data) is str:\n        if data.startswith(\"0x\"):\n            data = data[2:]\n        data = bytes.fromhex(data)\n    cost = 0\n    for b in data:\n        if b == 0:\n            cost += 4\n        else:\n            cost += 16\n    return cost\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.to_address","title":"to_address(input)","text":"

Converts an int or str into proper address 20-byte hex string.

Source code in src/ethereum_test_tools/common/helpers.py
def to_address(input: int | str) -> str:\n\"\"\"\n    Converts an int or str into proper address 20-byte hex string.\n    \"\"\"\n    if type(input) is str:\n        # Convert to int\n        input = int(input, 0)\n    if type(input) is int:\n        return \"0x\" + input.to_bytes(20, \"big\").hex()\n    raise Exception(\"invalid type to convert to account address\")\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.CodeGasMeasure","title":"CodeGasMeasure dataclass","text":"

Bases: Code

Helper class used to generate bytecode that measures gas usage of a bytecode, taking into account and subtracting any extra overhead gas costs required to execute. By default, the result gas calculation is saved to storage key 0.

Source code in src/ethereum_test_tools/code/generators.py
@dataclass(kw_only=True)\nclass CodeGasMeasure(Code):\n\"\"\"\n    Helper class used to generate bytecode that measures gas usage of a\n    bytecode, taking into account and subtracting any extra overhead gas costs\n    required to execute.\n    By default, the result gas calculation is saved to storage key 0.\n    \"\"\"\n\n    code: bytes | str | Code\n\"\"\"\n    Bytecode to be executed to measure the gas usage.\n    \"\"\"\n    overhead_cost: int = 0\n\"\"\"\n    Extra gas cost to be subtracted from extra operations.\n    \"\"\"\n    extra_stack_items: int = 0\n\"\"\"\n    Extra stack items that remain at the end of the execution.\n    To be considered when subtracting the value of the previous GAS operation,\n    and to be popped at the end of the execution.\n    \"\"\"\n    sstore_key: int = 0\n\"\"\"\n    Storage key to save the gas used.\n    \"\"\"\n\n    def assemble(self) -> bytes:\n\"\"\"\n        Assemble the bytecode that measures gas usage.\n        \"\"\"\n        res = bytes()\n        res += bytes(\n            [\n                0x5A,  # GAS\n            ]\n        )\n        res += code_to_bytes(self.code)  # Execute code to measure its gas cost\n        res += bytes(\n            [\n                0x5A,  # GAS\n            ]\n        )\n        # We need to swap and pop for each extra stack item that remained from\n        # the execution of the code\n        res += (\n            bytes(\n                [\n                    0x90,  # SWAP1\n                    0x50,  # POP\n                ]\n            )\n            * self.extra_stack_items\n        )\n        res += bytes(\n            [\n                0x90,  # SWAP1\n                0x03,  # SUB\n                0x60,  # PUSH1\n                self.overhead_cost + 2,  # Overhead cost + GAS opcode price\n                0x90,  # SWAP1\n                0x03,  # SUB\n                0x60,  # PUSH1\n                self.sstore_key,  # -> SSTORE key\n                0x55,  # SSTORE\n                0x00,  # STOP\n            ]\n        )\n        return res\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.code.generators.CodeGasMeasure.code","title":"code: bytes | str | Code instance-attribute","text":"

Bytecode to be executed to measure the gas usage.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.code.generators.CodeGasMeasure.overhead_cost","title":"overhead_cost: int = 0 class-attribute instance-attribute","text":"

Extra gas cost to be subtracted from extra operations.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.code.generators.CodeGasMeasure.extra_stack_items","title":"extra_stack_items: int = 0 class-attribute instance-attribute","text":"

Extra stack items that remain at the end of the execution. To be considered when subtracting the value of the previous GAS operation, and to be popped at the end of the execution.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.code.generators.CodeGasMeasure.sstore_key","title":"sstore_key: int = 0 class-attribute instance-attribute","text":"

Storage key to save the gas used.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.code.generators.CodeGasMeasure.assemble","title":"assemble()","text":"

Assemble the bytecode that measures gas usage.

Source code in src/ethereum_test_tools/code/generators.py
def assemble(self) -> bytes:\n\"\"\"\n    Assemble the bytecode that measures gas usage.\n    \"\"\"\n    res = bytes()\n    res += bytes(\n        [\n            0x5A,  # GAS\n        ]\n    )\n    res += code_to_bytes(self.code)  # Execute code to measure its gas cost\n    res += bytes(\n        [\n            0x5A,  # GAS\n        ]\n    )\n    # We need to swap and pop for each extra stack item that remained from\n    # the execution of the code\n    res += (\n        bytes(\n            [\n                0x90,  # SWAP1\n                0x50,  # POP\n            ]\n        )\n        * self.extra_stack_items\n    )\n    res += bytes(\n        [\n            0x90,  # SWAP1\n            0x03,  # SUB\n            0x60,  # PUSH1\n            self.overhead_cost + 2,  # Overhead cost + GAS opcode price\n            0x90,  # SWAP1\n            0x03,  # SUB\n            0x60,  # PUSH1\n            self.sstore_key,  # -> SSTORE key\n            0x55,  # SSTORE\n            0x00,  # STOP\n        ]\n    )\n    return res\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.to_hash_bytes","title":"to_hash_bytes(input)","text":"

Converts an int or str into proper 32-byte hash.

Source code in src/ethereum_test_tools/common/helpers.py
def to_hash_bytes(input: int | str) -> bytes:\n\"\"\"\n    Converts an int or str into proper 32-byte hash.\n    \"\"\"\n    if type(input) is str:\n        # Convert to int\n        input = int(input, 0)\n    if type(input) is int:\n        return input.to_bytes(32, \"big\")\n    raise Exception(\"invalid type to convert to hash\")\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.to_hash","title":"to_hash(input)","text":"

Converts an int or str into proper 32-byte hash hex string.

Source code in src/ethereum_test_tools/common/helpers.py
def to_hash(input: int | str) -> str:\n\"\"\"\n    Converts an int or str into proper 32-byte hash hex string.\n    \"\"\"\n    return \"0x\" + to_hash_bytes(input).hex()\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.add_kzg_version","title":"add_kzg_version(b_hashes, kzg_version)","text":"

Adds the Kzg Version to each blob hash.

Source code in src/ethereum_test_tools/common/helpers.py
def add_kzg_version(b_hashes: List[bytes | int | str], kzg_version: int) -> List[bytes]:\n\"\"\"\n    Adds the Kzg Version to each blob hash.\n    \"\"\"\n    kzg_version_hex = bytes([kzg_version])\n    kzg_versioned_hashes = []\n\n    for hash in b_hashes:\n        if isinstance(hash, int) or isinstance(hash, str):\n            kzg_versioned_hashes.append(kzg_version_hex + to_hash_bytes(hash)[1:])\n        elif isinstance(hash, bytes):\n            kzg_versioned_hashes.append(kzg_version_hex + hash[1:])\n        else:\n            raise TypeError(\"Blob hash must be either an integer, string or bytes\")\n    return kzg_versioned_hashes\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.Opcodes","title":"Opcodes","text":"

Bases: Opcode, Enum

Enum containing all known opcodes.

Contains deprecated and not yet implemented opcodes.

This enum is !! NOT !! meant to be iterated over by the tests. Instead, create a list with cherry-picked opcodes from this Enum within the test if iteration is needed.

Do !! NOT !! remove or modify existing opcodes from this list.

Source code in src/ethereum_test_tools/vm/opcode.py
class Opcodes(Opcode, Enum):\n\"\"\"\n    Enum containing all known opcodes.\n\n    Contains deprecated and not yet implemented opcodes.\n\n    This enum is !! NOT !! meant to be iterated over by the tests. Instead,\n    create a list with cherry-picked opcodes from this Enum within the test\n    if iteration is needed.\n\n    Do !! NOT !! remove or modify existing opcodes from this list.\n    \"\"\"\n\n    STOP = Opcode(0x00)\n    ADD = Opcode(0x01, popped_stack_items=2, pushed_stack_items=1)\n    MUL = Opcode(0x02, popped_stack_items=2, pushed_stack_items=1)\n    SUB = Opcode(0x03, popped_stack_items=2, pushed_stack_items=1)\n    DIV = Opcode(0x04, popped_stack_items=2, pushed_stack_items=1)\n    SDIV = Opcode(0x05, popped_stack_items=2, pushed_stack_items=1)\n    MOD = Opcode(0x06, popped_stack_items=2, pushed_stack_items=1)\n    SMOD = Opcode(0x07, popped_stack_items=2, pushed_stack_items=1)\n    ADDMOD = Opcode(0x08, popped_stack_items=3, pushed_stack_items=1)\n    MULMOD = Opcode(0x09, popped_stack_items=3, pushed_stack_items=1)\n    EXP = Opcode(0x0A, popped_stack_items=2, pushed_stack_items=1)\n    SIGNEXTEND = Opcode(0x0B, popped_stack_items=2, pushed_stack_items=1)\n\n    LT = Opcode(0x10, popped_stack_items=2, pushed_stack_items=1)\n    GT = Opcode(0x11, popped_stack_items=2, pushed_stack_items=1)\n    SLT = Opcode(0x12, popped_stack_items=2, pushed_stack_items=1)\n    SGT = Opcode(0x13, popped_stack_items=2, pushed_stack_items=1)\n    EQ = Opcode(0x14, popped_stack_items=2, pushed_stack_items=1)\n    ISZERO = Opcode(0x15, popped_stack_items=1, pushed_stack_items=1)\n    AND = Opcode(0x16, popped_stack_items=2, pushed_stack_items=1)\n    OR = Opcode(0x17, popped_stack_items=2, pushed_stack_items=1)\n    XOR = Opcode(0x18, popped_stack_items=2, pushed_stack_items=1)\n    NOT = Opcode(0x19, popped_stack_items=1, pushed_stack_items=1)\n    BYTE = Opcode(0x1A, popped_stack_items=2, pushed_stack_items=1)\n    SHL = Opcode(0x1B, popped_stack_items=2, pushed_stack_items=1)\n    SHR = Opcode(0x1C, popped_stack_items=2, pushed_stack_items=1)\n    SAR = Opcode(0x1D, popped_stack_items=2, pushed_stack_items=1)\n\n    SHA3 = Opcode(0x20, popped_stack_items=2, pushed_stack_items=1)\n\n    ADDRESS = Opcode(0x30, pushed_stack_items=1)\n    BALANCE = Opcode(0x31, popped_stack_items=1, pushed_stack_items=1)\n    ORIGIN = Opcode(0x32, pushed_stack_items=1)\n    CALLER = Opcode(0x33, pushed_stack_items=1)\n    CALLVALUE = Opcode(0x34, pushed_stack_items=1)\n    CALLDATALOAD = Opcode(0x35, popped_stack_items=1, pushed_stack_items=1)\n    CALLDATASIZE = Opcode(0x36, pushed_stack_items=1)\n    CALLDATACOPY = Opcode(0x37, popped_stack_items=3)\n    CODESIZE = Opcode(0x38, pushed_stack_items=1)\n    CODECOPY = Opcode(0x39, popped_stack_items=3)\n    GASPRICE = Opcode(0x3A, pushed_stack_items=1)\n    EXTCODESIZE = Opcode(0x3B, popped_stack_items=1, pushed_stack_items=1)\n    EXTCODECOPY = Opcode(0x3C, popped_stack_items=4)\n    RETURNDATASIZE = Opcode(0x3D, pushed_stack_items=1)\n    RETURNDATACOPY = Opcode(0x3E, popped_stack_items=3)\n    EXTCODEHASH = Opcode(0x3F, popped_stack_items=1, pushed_stack_items=1)\n\n    BLOCKHASH = Opcode(0x40, popped_stack_items=1, pushed_stack_items=1)\n    COINBASE = Opcode(0x41, pushed_stack_items=1)\n    TIMESTAMP = Opcode(0x42, pushed_stack_items=1)\n    NUMBER = Opcode(0x43, pushed_stack_items=1)\n    PREVRANDAO = Opcode(0x44, pushed_stack_items=1)\n    GASLIMIT = Opcode(0x45, pushed_stack_items=1)\n    CHAINID = Opcode(0x46, pushed_stack_items=1)\n    SELFBALANCE = Opcode(0x47, pushed_stack_items=1)\n    BASEFEE = Opcode(0x48, pushed_stack_items=1)\n    BLOBHASH = Opcode(0x49, popped_stack_items=1, pushed_stack_items=1)\n\n    POP = Opcode(0x50, popped_stack_items=1)\n    MLOAD = Opcode(0x51, popped_stack_items=1, pushed_stack_items=1)\n    MSTORE = Opcode(0x52, popped_stack_items=2)\n    MSTORE8 = Opcode(0x53, popped_stack_items=2)\n    SLOAD = Opcode(0x54, popped_stack_items=1, pushed_stack_items=1)\n    SSTORE = Opcode(0x55, popped_stack_items=2)\n    JUMP = Opcode(0x56, popped_stack_items=1)\n    JUMPI = Opcode(0x57, popped_stack_items=2)\n    PC = Opcode(0x58, pushed_stack_items=1)\n    MSIZE = Opcode(0x59, pushed_stack_items=1)\n    GAS = Opcode(0x5A, pushed_stack_items=1)\n    JUMPDEST = Opcode(0x5B)\n    RJUMP = Opcode(0x5C, data_portion_length=2)\n    RJUMPI = Opcode(0x5D, popped_stack_items=1, data_portion_length=2)\n    CALLF = Opcode(0x5E, data_portion_length=2)\n    RETF = Opcode(0x49)\n\n    PUSH0 = Opcode(0x5F, pushed_stack_items=1)\n    PUSH1 = Opcode(0x60, pushed_stack_items=1, data_portion_length=1)\n    PUSH2 = Opcode(0x61, pushed_stack_items=1, data_portion_length=2)\n    PUSH3 = Opcode(0x62, pushed_stack_items=1, data_portion_length=3)\n    PUSH4 = Opcode(0x63, pushed_stack_items=1, data_portion_length=4)\n    PUSH5 = Opcode(0x64, pushed_stack_items=1, data_portion_length=5)\n    PUSH6 = Opcode(0x65, pushed_stack_items=1, data_portion_length=6)\n    PUSH7 = Opcode(0x66, pushed_stack_items=1, data_portion_length=7)\n    PUSH8 = Opcode(0x67, pushed_stack_items=1, data_portion_length=8)\n    PUSH9 = Opcode(0x68, pushed_stack_items=1, data_portion_length=9)\n    PUSH10 = Opcode(0x69, pushed_stack_items=1, data_portion_length=10)\n    PUSH11 = Opcode(0x6A, pushed_stack_items=1, data_portion_length=11)\n    PUSH12 = Opcode(0x6B, pushed_stack_items=1, data_portion_length=12)\n    PUSH13 = Opcode(0x6C, pushed_stack_items=1, data_portion_length=13)\n    PUSH14 = Opcode(0x6D, pushed_stack_items=1, data_portion_length=14)\n    PUSH15 = Opcode(0x6E, pushed_stack_items=1, data_portion_length=15)\n    PUSH16 = Opcode(0x6F, pushed_stack_items=1, data_portion_length=16)\n    PUSH17 = Opcode(0x70, pushed_stack_items=1, data_portion_length=17)\n    PUSH18 = Opcode(0x71, pushed_stack_items=1, data_portion_length=18)\n    PUSH19 = Opcode(0x72, pushed_stack_items=1, data_portion_length=19)\n    PUSH20 = Opcode(0x73, pushed_stack_items=1, data_portion_length=20)\n    PUSH21 = Opcode(0x74, pushed_stack_items=1, data_portion_length=21)\n    PUSH22 = Opcode(0x75, pushed_stack_items=1, data_portion_length=22)\n    PUSH23 = Opcode(0x76, pushed_stack_items=1, data_portion_length=23)\n    PUSH24 = Opcode(0x77, pushed_stack_items=1, data_portion_length=24)\n    PUSH25 = Opcode(0x78, pushed_stack_items=1, data_portion_length=25)\n    PUSH26 = Opcode(0x79, pushed_stack_items=1, data_portion_length=26)\n    PUSH27 = Opcode(0x7A, pushed_stack_items=1, data_portion_length=27)\n    PUSH28 = Opcode(0x7B, pushed_stack_items=1, data_portion_length=28)\n    PUSH29 = Opcode(0x7C, pushed_stack_items=1, data_portion_length=29)\n    PUSH30 = Opcode(0x7D, pushed_stack_items=1, data_portion_length=30)\n    PUSH31 = Opcode(0x7E, pushed_stack_items=1, data_portion_length=31)\n    PUSH32 = Opcode(0x7F, pushed_stack_items=1, data_portion_length=32)\n\n    DUP1 = Opcode(0x80, pushed_stack_items=1, min_stack_height=1)\n    DUP2 = Opcode(0x81, pushed_stack_items=1, min_stack_height=2)\n    DUP3 = Opcode(0x82, pushed_stack_items=1, min_stack_height=3)\n    DUP4 = Opcode(0x83, pushed_stack_items=1, min_stack_height=4)\n    DUP5 = Opcode(0x84, pushed_stack_items=1, min_stack_height=5)\n    DUP6 = Opcode(0x85, pushed_stack_items=1, min_stack_height=6)\n    DUP7 = Opcode(0x86, pushed_stack_items=1, min_stack_height=7)\n    DUP8 = Opcode(0x87, pushed_stack_items=1, min_stack_height=8)\n    DUP9 = Opcode(0x88, pushed_stack_items=1, min_stack_height=9)\n    DUP10 = Opcode(0x89, pushed_stack_items=1, min_stack_height=10)\n    DUP11 = Opcode(0x8A, pushed_stack_items=1, min_stack_height=11)\n    DUP12 = Opcode(0x8B, pushed_stack_items=1, min_stack_height=12)\n    DUP13 = Opcode(0x8C, pushed_stack_items=1, min_stack_height=13)\n    DUP14 = Opcode(0x8D, pushed_stack_items=1, min_stack_height=14)\n    DUP15 = Opcode(0x8E, pushed_stack_items=1, min_stack_height=15)\n    DUP16 = Opcode(0x8F, pushed_stack_items=1, min_stack_height=16)\n\n    SWAP1 = Opcode(0x90, min_stack_height=2)\n    SWAP2 = Opcode(0x91, min_stack_height=3)\n    SWAP3 = Opcode(0x92, min_stack_height=4)\n    SWAP4 = Opcode(0x93, min_stack_height=5)\n    SWAP5 = Opcode(0x94, min_stack_height=6)\n    SWAP6 = Opcode(0x95, min_stack_height=7)\n    SWAP7 = Opcode(0x96, min_stack_height=8)\n    SWAP8 = Opcode(0x97, min_stack_height=9)\n    SWAP9 = Opcode(0x98, min_stack_height=10)\n    SWAP10 = Opcode(0x99, min_stack_height=11)\n    SWAP11 = Opcode(0x9A, min_stack_height=12)\n    SWAP12 = Opcode(0x9B, min_stack_height=13)\n    SWAP13 = Opcode(0x9C, min_stack_height=14)\n    SWAP14 = Opcode(0x9D, min_stack_height=15)\n    SWAP15 = Opcode(0x9E, min_stack_height=16)\n    SWAP16 = Opcode(0x9F, min_stack_height=17)\n\n    LOG0 = Opcode(0xA0, popped_stack_items=2)\n    LOG1 = Opcode(0xA1, popped_stack_items=3)\n    LOG2 = Opcode(0xA2, popped_stack_items=4)\n    LOG3 = Opcode(0xA3, popped_stack_items=5)\n    LOG4 = Opcode(0xA4, popped_stack_items=6)\n\n    TLOAD = Opcode(0xB3, popped_stack_items=1, pushed_stack_items=1)\n    TSTORE = Opcode(0xB4, popped_stack_items=2)\n\n    CREATE = Opcode(0xF0, popped_stack_items=3, pushed_stack_items=1)\n    CALL = Opcode(0xF1, popped_stack_items=7, pushed_stack_items=1)\n    CALLCODE = Opcode(0xF2, popped_stack_items=7, pushed_stack_items=1)\n    RETURN = Opcode(0xF3, popped_stack_items=2)\n    DELEGATECALL = Opcode(0xF4, popped_stack_items=6, pushed_stack_items=1)\n    CREATE2 = Opcode(0xF5, popped_stack_items=4, pushed_stack_items=1)\n\n    STATICCALL = Opcode(0xFA, popped_stack_items=6, pushed_stack_items=1)\n\n    REVERT = Opcode(0xFD, popped_stack_items=2)\n    INVALID = Opcode(0xFE)\n\n    SELFDESTRUCT = Opcode(0xFF, popped_stack_items=1)\n    SENDALL = Opcode(0xFF, popped_stack_items=1)\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.Account","title":"Account","text":"

State associated with an address.

Source code in src/ethereum_test_tools/common/types.py
class Account:\n\"\"\"\n    State associated with an address.\n    \"\"\"\n\n    nonce: int | None = None\n\"\"\"\n    The scalar value equal to a) the number of transactions sent by\n    an Externally Owned Account, b) the amount of contracts created by a\n    contract.\n    \"\"\"\n    balance: int | None = None\n\"\"\"\n    The amount of Wei (10<sup>-18</sup> Eth) the account has.\n    \"\"\"\n    code: str | bytes | Code | None = None\n\"\"\"\n    Bytecode contained by the account.\n    \"\"\"\n    storage: Storage | None = None\n\"\"\"\n    Storage within a contract.\n    \"\"\"\n\n    NONEXISTENT: ClassVar[object] = object()\n\"\"\"\n    Sentinel object used to specify when an account should not exist in the\n    state.\n    \"\"\"\n\n    class NonceMismatch(Exception):\n\"\"\"\n        Test expected a certain nonce value for an account but a different\n        value was found.\n        \"\"\"\n\n        address: str\n        want: int | None\n        got: int | None\n\n        def __init__(self, address: str, want: int | None, got: int | None, *args):\n            super().__init__(args)\n            self.address = address\n            self.want = want\n            self.got = got\n\n        def __str__(self):\n\"\"\"Print exception string\"\"\"\n            return (\n                f\"unexpected nonce for account {self.address}: \"\n                + f\"want {self.want}, got {self.got}\"\n            )\n\n    class BalanceMismatch(Exception):\n\"\"\"\n        Test expected a certain balance for an account but a different\n        value was found.\n        \"\"\"\n\n        address: str\n        want: int | None\n        got: int | None\n\n        def __init__(self, address: str, want: int | None, got: int | None, *args):\n            super().__init__(args)\n            self.address = address\n            self.want = want\n            self.got = got\n\n        def __str__(self):\n\"\"\"Print exception string\"\"\"\n            return (\n                f\"unexpected balance for account {self.address}: \"\n                + f\"want {self.want}, got {self.got}\"\n            )\n\n    class CodeMismatch(Exception):\n\"\"\"\n        Test expected a certain bytecode for an account but a different\n        one was found.\n        \"\"\"\n\n        address: str\n        want: str | None\n        got: str | None\n\n        def __init__(self, address: str, want: str | None, got: str | None, *args):\n            super().__init__(args)\n            self.address = address\n            self.want = want\n            self.got = got\n\n        def __str__(self):\n\"\"\"Print exception string\"\"\"\n            return (\n                f\"unexpected code for account {self.address}: \"\n                + f\"want {self.want}, got {self.got}\"\n            )\n\n    def __init__(\n        self,\n        *,\n        nonce: int | None = None,\n        balance: int | None = None,\n        code: str | bytes | Code | None = None,\n        storage: Storage | Dict[str | int | bytes, str | int | bytes] | None = None,\n    ) -> None:\n\"\"\"Init account members\"\"\"\n        self.nonce = nonce\n        self.balance = balance\n        self.code = code\n        if storage is not None and type(storage) is dict:\n            self.storage = Storage(storage)\n\n    def check_alloc(self: \"Account\", address: str, alloc: dict):\n\"\"\"\n        Checks the returned alloc against an expected account in post state.\n        Raises exception on failure.\n        \"\"\"\n        if self.nonce is not None:\n            actual_nonce = int_or_none(alloc.get(\"nonce\"), 0)\n            if self.nonce != actual_nonce:\n                raise Account.NonceMismatch(\n                    address=address,\n                    want=self.nonce,\n                    got=actual_nonce,\n                )\n\n        if self.balance is not None:\n            actual_balance = int_or_none(alloc.get(\"balance\"), 0)\n            if self.balance != actual_balance:\n                raise Account.BalanceMismatch(\n                    address=address,\n                    want=self.balance,\n                    got=actual_balance,\n                )\n\n        if self.code is not None:\n            expected_code = code_to_hex(self.code)\n            actual_code = str_or_none(alloc.get(\"code\"), \"0x\")\n            if expected_code != actual_code:\n                raise Account.CodeMismatch(\n                    address=address,\n                    want=expected_code,\n                    got=actual_code,\n                )\n\n        if self.storage is not None:\n            expected_storage = (\n                self.storage if isinstance(self.storage, Storage) else Storage(self.storage)\n            )\n            actual_storage = Storage(alloc[\"storage\"]) if \"storage\" in alloc else Storage({})\n            expected_storage.must_be_equal(actual_storage)\n\n    @classmethod\n    def with_code(cls: Type, code: bytes | str | Code) -> \"Account\":\n\"\"\"\n        Create account with provided `code` and nonce of `1`.\n        \"\"\"\n        return Account(nonce=1, code=code)\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Account.storage","title":"storage: Storage | None = None class-attribute instance-attribute","text":"

Storage within a contract.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Account.NONEXISTENT","title":"NONEXISTENT: object = object() class-attribute","text":"

Sentinel object used to specify when an account should not exist in the state.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Account.NonceMismatch","title":"NonceMismatch","text":"

Bases: Exception

Test expected a certain nonce value for an account but a different value was found.

Source code in src/ethereum_test_tools/common/types.py
class NonceMismatch(Exception):\n\"\"\"\n    Test expected a certain nonce value for an account but a different\n    value was found.\n    \"\"\"\n\n    address: str\n    want: int | None\n    got: int | None\n\n    def __init__(self, address: str, want: int | None, got: int | None, *args):\n        super().__init__(args)\n        self.address = address\n        self.want = want\n        self.got = got\n\n    def __str__(self):\n\"\"\"Print exception string\"\"\"\n        return (\n            f\"unexpected nonce for account {self.address}: \"\n            + f\"want {self.want}, got {self.got}\"\n        )\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Account.NonceMismatch.__str__","title":"__str__()","text":"

Print exception string

Source code in src/ethereum_test_tools/common/types.py
def __str__(self):\n\"\"\"Print exception string\"\"\"\n    return (\n        f\"unexpected nonce for account {self.address}: \"\n        + f\"want {self.want}, got {self.got}\"\n    )\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Account.BalanceMismatch","title":"BalanceMismatch","text":"

Bases: Exception

Test expected a certain balance for an account but a different value was found.

Source code in src/ethereum_test_tools/common/types.py
class BalanceMismatch(Exception):\n\"\"\"\n    Test expected a certain balance for an account but a different\n    value was found.\n    \"\"\"\n\n    address: str\n    want: int | None\n    got: int | None\n\n    def __init__(self, address: str, want: int | None, got: int | None, *args):\n        super().__init__(args)\n        self.address = address\n        self.want = want\n        self.got = got\n\n    def __str__(self):\n\"\"\"Print exception string\"\"\"\n        return (\n            f\"unexpected balance for account {self.address}: \"\n            + f\"want {self.want}, got {self.got}\"\n        )\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Account.BalanceMismatch.__str__","title":"__str__()","text":"

Print exception string

Source code in src/ethereum_test_tools/common/types.py
def __str__(self):\n\"\"\"Print exception string\"\"\"\n    return (\n        f\"unexpected balance for account {self.address}: \"\n        + f\"want {self.want}, got {self.got}\"\n    )\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Account.CodeMismatch","title":"CodeMismatch","text":"

Bases: Exception

Test expected a certain bytecode for an account but a different one was found.

Source code in src/ethereum_test_tools/common/types.py
class CodeMismatch(Exception):\n\"\"\"\n    Test expected a certain bytecode for an account but a different\n    one was found.\n    \"\"\"\n\n    address: str\n    want: str | None\n    got: str | None\n\n    def __init__(self, address: str, want: str | None, got: str | None, *args):\n        super().__init__(args)\n        self.address = address\n        self.want = want\n        self.got = got\n\n    def __str__(self):\n\"\"\"Print exception string\"\"\"\n        return (\n            f\"unexpected code for account {self.address}: \"\n            + f\"want {self.want}, got {self.got}\"\n        )\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Account.CodeMismatch.__str__","title":"__str__()","text":"

Print exception string

Source code in src/ethereum_test_tools/common/types.py
def __str__(self):\n\"\"\"Print exception string\"\"\"\n    return (\n        f\"unexpected code for account {self.address}: \"\n        + f\"want {self.want}, got {self.got}\"\n    )\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Account.__init__","title":"__init__(*, nonce=None, balance=None, code=None, storage=None)","text":"

Init account members

Source code in src/ethereum_test_tools/common/types.py
def __init__(\n    self,\n    *,\n    nonce: int | None = None,\n    balance: int | None = None,\n    code: str | bytes | Code | None = None,\n    storage: Storage | Dict[str | int | bytes, str | int | bytes] | None = None,\n) -> None:\n\"\"\"Init account members\"\"\"\n    self.nonce = nonce\n    self.balance = balance\n    self.code = code\n    if storage is not None and type(storage) is dict:\n        self.storage = Storage(storage)\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Account.nonce","title":"nonce: int | None = nonce class-attribute instance-attribute","text":"

The scalar value equal to a) the number of transactions sent by an Externally Owned Account, b) the amount of contracts created by a contract.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Account.balance","title":"balance: int | None = balance class-attribute instance-attribute","text":"

The amount of Wei (10-18 Eth) the account has.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Account.code","title":"code: str | bytes | Code | None = code class-attribute instance-attribute","text":"

Bytecode contained by the account.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Account.check_alloc","title":"check_alloc(address, alloc)","text":"

Checks the returned alloc against an expected account in post state. Raises exception on failure.

Source code in src/ethereum_test_tools/common/types.py
def check_alloc(self: \"Account\", address: str, alloc: dict):\n\"\"\"\n    Checks the returned alloc against an expected account in post state.\n    Raises exception on failure.\n    \"\"\"\n    if self.nonce is not None:\n        actual_nonce = int_or_none(alloc.get(\"nonce\"), 0)\n        if self.nonce != actual_nonce:\n            raise Account.NonceMismatch(\n                address=address,\n                want=self.nonce,\n                got=actual_nonce,\n            )\n\n    if self.balance is not None:\n        actual_balance = int_or_none(alloc.get(\"balance\"), 0)\n        if self.balance != actual_balance:\n            raise Account.BalanceMismatch(\n                address=address,\n                want=self.balance,\n                got=actual_balance,\n            )\n\n    if self.code is not None:\n        expected_code = code_to_hex(self.code)\n        actual_code = str_or_none(alloc.get(\"code\"), \"0x\")\n        if expected_code != actual_code:\n            raise Account.CodeMismatch(\n                address=address,\n                want=expected_code,\n                got=actual_code,\n            )\n\n    if self.storage is not None:\n        expected_storage = (\n            self.storage if isinstance(self.storage, Storage) else Storage(self.storage)\n        )\n        actual_storage = Storage(alloc[\"storage\"]) if \"storage\" in alloc else Storage({})\n        expected_storage.must_be_equal(actual_storage)\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Account.with_code","title":"with_code(code) classmethod","text":"

Create account with provided code and nonce of 1.

Source code in src/ethereum_test_tools/common/types.py
@classmethod\ndef with_code(cls: Type, code: bytes | str | Code) -> \"Account\":\n\"\"\"\n    Create account with provided `code` and nonce of `1`.\n    \"\"\"\n    return Account(nonce=1, code=code)\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.Withdrawal","title":"Withdrawal dataclass","text":"

Structure to represent a single withdrawal of a validator's balance from the beacon chain.

Source code in src/ethereum_test_tools/common/types.py
@dataclass(kw_only=True)\nclass Withdrawal:\n\"\"\"\n    Structure to represent a single withdrawal of a validator's balance from\n    the beacon chain.\n    \"\"\"\n\n    index: int\n    validator: int\n    address: str\n    amount: int\n\n    def to_serializable_list(self) -> List[Any]:\n\"\"\"\n        Returns a list of the withdrawal's attributes in the order they should\n        be serialized.\n        \"\"\"\n        return [\n            Uint(self.index),\n            Uint(self.validator),\n            bytes.fromhex(self.address[2:]),\n            Uint(self.amount),\n        ]\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Withdrawal.to_serializable_list","title":"to_serializable_list()","text":"

Returns a list of the withdrawal's attributes in the order they should be serialized.

Source code in src/ethereum_test_tools/common/types.py
def to_serializable_list(self) -> List[Any]:\n\"\"\"\n    Returns a list of the withdrawal's attributes in the order they should\n    be serialized.\n    \"\"\"\n    return [\n        Uint(self.index),\n        Uint(self.validator),\n        bytes.fromhex(self.address[2:]),\n        Uint(self.amount),\n    ]\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.Environment","title":"Environment dataclass","text":"

Structure used to keep track of the context in which a block must be executed.

Source code in src/ethereum_test_tools/common/types.py
@dataclass(kw_only=True)\nclass Environment:\n\"\"\"\n    Structure used to keep track of the context in which a block\n    must be executed.\n    \"\"\"\n\n    coinbase: str | bytes = \"0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba\"\n    gas_limit: int = 100000000000000000\n    number: int = 1\n    timestamp: int = 1000\n    difficulty: Optional[int] = None\n    prev_randao: Optional[int] = None\n    block_hashes: Dict[int, bytes] = field(default_factory=dict)\n    base_fee: Optional[int] = None\n    parent_difficulty: Optional[int] = None\n    parent_timestamp: Optional[int] = None\n    parent_base_fee: Optional[int] = None\n    parent_gas_used: Optional[int] = None\n    parent_gas_limit: Optional[int] = None\n    parent_ommers_hash: Optional[str | bytes] = None\n    withdrawals: Optional[List[Withdrawal]] = None\n    parent_data_gas_used: Optional[int] = None\n    parent_excess_data_gas: Optional[int] = None\n    excess_data_gas: Optional[int] = None\n    data_gas_used: Optional[int] = None\n\n    @staticmethod\n    def from_parent_header(parent: \"FixtureHeader\") -> \"Environment\":\n\"\"\"\n        Instantiates a new environment with the provided header as parent.\n        \"\"\"\n        return Environment(\n            parent_difficulty=parent.difficulty,\n            parent_timestamp=parent.timestamp,\n            parent_base_fee=parent.base_fee,\n            parent_data_gas_used=parent.data_gas_used,\n            parent_excess_data_gas=parent.excess_data_gas,\n            parent_gas_used=parent.gas_used,\n            parent_gas_limit=parent.gas_limit,\n            parent_ommers_hash=parent.ommers_hash,\n            block_hashes={\n                parent.number: parent.hash if parent.hash is not None else bytes([0] * 32)\n            },\n        )\n\n    def parent_hash(self) -> bytes:\n\"\"\"\n        Obtjains the latest hash according to the highest block number in\n        `block_hashes`.\n        \"\"\"\n        if len(self.block_hashes) == 0:\n            return bytes([0] * 32)\n\n        last_index = max(self.block_hashes.keys())\n        return self.block_hashes[last_index]\n\n    def apply_new_parent(self, new_parent: \"FixtureHeader\") -> \"Environment\":\n\"\"\"\n        Applies a header as parent to a copy of this environment.\n        \"\"\"\n        env = copy(self)\n        env.parent_difficulty = new_parent.difficulty\n        env.parent_timestamp = new_parent.timestamp\n        env.parent_base_fee = new_parent.base_fee\n        env.parent_data_gas_used = new_parent.data_gas_used\n        env.parent_excess_data_gas = new_parent.excess_data_gas\n        env.parent_gas_used = new_parent.gas_used\n        env.parent_gas_limit = new_parent.gas_limit\n        env.parent_ommers_hash = new_parent.ommers_hash\n        env.block_hashes[new_parent.number] = (\n            new_parent.hash if new_parent.hash is not None else bytes([0] * 32)\n        )\n        return env\n\n    def set_fork_requirements(self, fork: Fork) -> \"Environment\":\n\"\"\"\n        Fills the required fields in an environment depending on the fork.\n        \"\"\"\n        res = copy(self)\n\n        if (\n            fork.header_prev_randao_required(self.number, self.timestamp)\n            and res.prev_randao is None\n        ):\n            res.prev_randao = 0\n\n        if (\n            fork.header_withdrawals_required(self.number, self.timestamp)\n            and res.withdrawals is None\n        ):\n            res.withdrawals = []\n\n        if (\n            fork.header_base_fee_required(self.number, self.timestamp)\n            and res.base_fee is None\n            and res.parent_base_fee is None\n        ):\n            res.base_fee = DEFAULT_BASE_FEE\n\n        if fork.header_zero_difficulty_required(self.number, self.timestamp):\n            res.difficulty = 0\n\n        if (\n            fork.header_excess_data_gas_required(self.number, self.timestamp)\n            and res.excess_data_gas is None\n            and res.parent_excess_data_gas is None\n        ):\n            res.excess_data_gas = 0\n\n        if (\n            fork.header_data_gas_used_required(self.number, self.timestamp)\n            and res.data_gas_used is None\n            and res.parent_data_gas_used is None\n        ):\n            res.data_gas_used = 0\n\n        return res\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Environment.from_parent_header","title":"from_parent_header(parent) staticmethod","text":"

Instantiates a new environment with the provided header as parent.

Source code in src/ethereum_test_tools/common/types.py
@staticmethod\ndef from_parent_header(parent: \"FixtureHeader\") -> \"Environment\":\n\"\"\"\n    Instantiates a new environment with the provided header as parent.\n    \"\"\"\n    return Environment(\n        parent_difficulty=parent.difficulty,\n        parent_timestamp=parent.timestamp,\n        parent_base_fee=parent.base_fee,\n        parent_data_gas_used=parent.data_gas_used,\n        parent_excess_data_gas=parent.excess_data_gas,\n        parent_gas_used=parent.gas_used,\n        parent_gas_limit=parent.gas_limit,\n        parent_ommers_hash=parent.ommers_hash,\n        block_hashes={\n            parent.number: parent.hash if parent.hash is not None else bytes([0] * 32)\n        },\n    )\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Environment.parent_hash","title":"parent_hash()","text":"

Obtjains the latest hash according to the highest block number in block_hashes.

Source code in src/ethereum_test_tools/common/types.py
def parent_hash(self) -> bytes:\n\"\"\"\n    Obtjains the latest hash according to the highest block number in\n    `block_hashes`.\n    \"\"\"\n    if len(self.block_hashes) == 0:\n        return bytes([0] * 32)\n\n    last_index = max(self.block_hashes.keys())\n    return self.block_hashes[last_index]\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Environment.apply_new_parent","title":"apply_new_parent(new_parent)","text":"

Applies a header as parent to a copy of this environment.

Source code in src/ethereum_test_tools/common/types.py
def apply_new_parent(self, new_parent: \"FixtureHeader\") -> \"Environment\":\n\"\"\"\n    Applies a header as parent to a copy of this environment.\n    \"\"\"\n    env = copy(self)\n    env.parent_difficulty = new_parent.difficulty\n    env.parent_timestamp = new_parent.timestamp\n    env.parent_base_fee = new_parent.base_fee\n    env.parent_data_gas_used = new_parent.data_gas_used\n    env.parent_excess_data_gas = new_parent.excess_data_gas\n    env.parent_gas_used = new_parent.gas_used\n    env.parent_gas_limit = new_parent.gas_limit\n    env.parent_ommers_hash = new_parent.ommers_hash\n    env.block_hashes[new_parent.number] = (\n        new_parent.hash if new_parent.hash is not None else bytes([0] * 32)\n    )\n    return env\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Environment.set_fork_requirements","title":"set_fork_requirements(fork)","text":"

Fills the required fields in an environment depending on the fork.

Source code in src/ethereum_test_tools/common/types.py
def set_fork_requirements(self, fork: Fork) -> \"Environment\":\n\"\"\"\n    Fills the required fields in an environment depending on the fork.\n    \"\"\"\n    res = copy(self)\n\n    if (\n        fork.header_prev_randao_required(self.number, self.timestamp)\n        and res.prev_randao is None\n    ):\n        res.prev_randao = 0\n\n    if (\n        fork.header_withdrawals_required(self.number, self.timestamp)\n        and res.withdrawals is None\n    ):\n        res.withdrawals = []\n\n    if (\n        fork.header_base_fee_required(self.number, self.timestamp)\n        and res.base_fee is None\n        and res.parent_base_fee is None\n    ):\n        res.base_fee = DEFAULT_BASE_FEE\n\n    if fork.header_zero_difficulty_required(self.number, self.timestamp):\n        res.difficulty = 0\n\n    if (\n        fork.header_excess_data_gas_required(self.number, self.timestamp)\n        and res.excess_data_gas is None\n        and res.parent_excess_data_gas is None\n    ):\n        res.excess_data_gas = 0\n\n    if (\n        fork.header_data_gas_used_required(self.number, self.timestamp)\n        and res.data_gas_used is None\n        and res.parent_data_gas_used is None\n    ):\n        res.data_gas_used = 0\n\n    return res\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.AccessList","title":"AccessList","text":"

Access List for transactions.

Source code in src/ethereum_test_tools/common/types.py
class AccessList:\n\"\"\"\n    Access List for transactions.\n    \"\"\"\n\n    address: bytes\n    storage_keys: List[bytes]\n\n    def __init__(\n        self,\n        *,\n        address: str | int | bytes,\n        storage_keys: List[str | int | bytes],\n    ) -> None:\n\"\"\"\n        Ensures the access list has the correct byte length for each field.\n        \"\"\"\n        self.address = address_to_bytes(address)\n        self.storage_keys = [hash_to_bytes(key) for key in storage_keys]\n\n    def to_list(self) -> List[bytes | List[bytes]]:\n\"\"\"\n        Returns the access list as a list of serializable elements.\n        \"\"\"\n        return [self.address, self.storage_keys]\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.AccessList.__init__","title":"__init__(*, address, storage_keys)","text":"

Ensures the access list has the correct byte length for each field.

Source code in src/ethereum_test_tools/common/types.py
def __init__(\n    self,\n    *,\n    address: str | int | bytes,\n    storage_keys: List[str | int | bytes],\n) -> None:\n\"\"\"\n    Ensures the access list has the correct byte length for each field.\n    \"\"\"\n    self.address = address_to_bytes(address)\n    self.storage_keys = [hash_to_bytes(key) for key in storage_keys]\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.AccessList.to_list","title":"to_list()","text":"

Returns the access list as a list of serializable elements.

Source code in src/ethereum_test_tools/common/types.py
def to_list(self) -> List[bytes | List[bytes]]:\n\"\"\"\n    Returns the access list as a list of serializable elements.\n    \"\"\"\n    return [self.address, self.storage_keys]\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.Transaction","title":"Transaction dataclass","text":"

Generic object that can represent all Ethereum transaction types.

Source code in src/ethereum_test_tools/common/types.py
@dataclass(kw_only=True)\nclass Transaction:\n\"\"\"\n    Generic object that can represent all Ethereum transaction types.\n    \"\"\"\n\n    ty: Optional[int] = None\n\"\"\"\n    Transaction type value.\n    \"\"\"\n    chain_id: int = 1\n    nonce: int = 0\n    to: Optional[str | int] = AddrAA\n    value: int = 0\n    data: bytes | str | Code = bytes()\n    gas_limit: int = 21000\n    access_list: Optional[List[AccessList]] = None\n\n    gas_price: Optional[int] = None\n    max_fee_per_gas: Optional[int] = None\n    max_priority_fee_per_gas: Optional[int] = None\n\n    max_fee_per_data_gas: Optional[int] = None\n    blob_versioned_hashes: Optional[Sequence[str | bytes]] = None\n\n    wrapped_blob_transaction: bool = False\n    blobs: Optional[Sequence[bytes]] = None\n    blob_kzg_commitments: Optional[Sequence[bytes]] = None\n    blob_kzg_proofs: Optional[Sequence[bytes]] = None\n\n    signature: Optional[Tuple[int, int, int]] = None\n    secret_key: Optional[str] = None\n    sender: Optional[str | bytes] = None\n    protected: bool = True\n    error: Optional[str] = None\n\n    class InvalidFeePayment(Exception):\n\"\"\"\n        Transaction described more than one fee payment type.\n        \"\"\"\n\n        def __str__(self):\n\"\"\"Print exception string\"\"\"\n            return \"only one type of fee payment field can be used in a single tx\"\n\n    class InvalidSignaturePrivateKey(Exception):\n\"\"\"\n        Transaction describes both the signature and private key of\n        source account.\n        \"\"\"\n\n        def __str__(self):\n\"\"\"Print exception string\"\"\"\n            return \"can't define both 'signature' and 'private_key'\"\n\n    def __post_init__(self) -> None:\n\"\"\"\n        Ensures the transaction has no conflicting properties.\n        \"\"\"\n        if (\n            self.gas_price is not None\n            and self.max_fee_per_gas is not None\n            and self.max_priority_fee_per_gas is not None\n        ):\n            raise Transaction.InvalidFeePayment()\n\n        if (\n            self.gas_price is None\n            and self.max_fee_per_gas is None\n            and self.max_priority_fee_per_gas is None\n        ):\n            self.gas_price = 10\n\n        if self.signature is not None and self.secret_key is not None:\n            raise Transaction.InvalidSignaturePrivateKey()\n\n        if self.signature is None and self.secret_key is None:\n            self.secret_key = TestPrivateKey\n\n        if self.ty is None:\n            # Try to deduce transaction type from included fields\n            if self.max_fee_per_data_gas is not None:\n                self.ty = 3\n            elif self.max_fee_per_gas is not None:\n                self.ty = 2\n            elif self.access_list is not None:\n                self.ty = 1\n            else:\n                self.ty = 0\n\n    def with_error(self, error: str) -> \"Transaction\":\n\"\"\"\n        Create a copy of the transaction with an added error.\n        \"\"\"\n        tx = copy(self)\n        tx.error = error\n        return tx\n\n    def with_nonce(self, nonce: int) -> \"Transaction\":\n\"\"\"\n        Create a copy of the transaction with a modified nonce.\n        \"\"\"\n        tx = copy(self)\n        tx.nonce = nonce\n        return tx\n\n    def with_fields(self, **kwargs) -> \"Transaction\":\n\"\"\"\n        Create a deepcopy of the transaction with modified fields.\n        \"\"\"\n        tx = deepcopy(self)\n        for key, value in kwargs.items():\n            if hasattr(tx, key):\n                setattr(tx, key, value)\n            else:\n                raise ValueError(f\"Invalid field '{key}' for Transaction\")\n        return tx\n\n    def payload_body(self) -> List[Any]:\n\"\"\"\n        Returns the list of values included in the transaction body.\n        \"\"\"\n        if self.signature is None:\n            raise ValueError(\"signature must be set before serializing any tx type\")\n\n        if self.gas_limit is None:\n            raise ValueError(\"gas_limit must be set for all tx types\")\n        to = address_to_bytes(self.to)\n\n        if self.ty == 3:\n            # EIP-4844: https://eips.ethereum.org/EIPS/eip-4844\n            if self.max_priority_fee_per_gas is None:\n                raise ValueError(\"max_priority_fee_per_gas must be set for type 3 tx\")\n            if self.max_fee_per_gas is None:\n                raise ValueError(\"max_fee_per_gas must be set for type 3 tx\")\n            if self.max_fee_per_data_gas is None:\n                raise ValueError(\"max_fee_per_data_gas must be set for type 3 tx\")\n            if self.blob_versioned_hashes is None:\n                raise ValueError(\"blob_versioned_hashes must be set for type 3 tx\")\n\n            if self.wrapped_blob_transaction:\n                if self.blobs is None:\n                    raise ValueError(\"blobs must be set for network version of type 3 tx\")\n                if self.blob_kzg_commitments is None:\n                    raise ValueError(\n                        \"blob_kzg_commitments must be set for network version of type 3 tx\"\n                    )\n                if self.blob_kzg_proofs is None:\n                    raise ValueError(\n                        \"blob_kzg_proofs must be set for network version of type 3 tx\"\n                    )\n\n                return [\n                    [\n                        Uint(self.chain_id),\n                        Uint(self.nonce),\n                        Uint(self.max_priority_fee_per_gas),\n                        Uint(self.max_fee_per_gas),\n                        Uint(self.gas_limit),\n                        to,\n                        Uint(self.value),\n                        code_to_bytes(self.data),\n                        [a.to_list() for a in self.access_list]\n                        if self.access_list is not None\n                        else [],\n                        Uint(self.max_fee_per_data_gas),\n                        [hash_to_bytes(h) for h in self.blob_versioned_hashes],\n                        Uint(self.signature[0]),\n                        Uint(self.signature[1]),\n                        Uint(self.signature[2]),\n                    ],\n                    self.blobs,\n                    self.blob_kzg_commitments,\n                    self.blob_kzg_proofs,\n                ]\n            else:\n                return [\n                    Uint(self.chain_id),\n                    Uint(self.nonce),\n                    Uint(self.max_priority_fee_per_gas),\n                    Uint(self.max_fee_per_gas),\n                    Uint(self.gas_limit),\n                    to,\n                    Uint(self.value),\n                    code_to_bytes(self.data),\n                    [a.to_list() for a in self.access_list]\n                    if self.access_list is not None\n                    else [],\n                    Uint(self.max_fee_per_data_gas),\n                    [hash_to_bytes(h) for h in self.blob_versioned_hashes],\n                    Uint(self.signature[0]),\n                    Uint(self.signature[1]),\n                    Uint(self.signature[2]),\n                ]\n        elif self.ty == 2:\n            # EIP-1559: https://eips.ethereum.org/EIPS/eip-1559\n            if self.max_priority_fee_per_gas is None:\n                raise ValueError(\"max_priority_fee_per_gas must be set for type 3 tx\")\n            if self.max_fee_per_gas is None:\n                raise ValueError(\"max_fee_per_gas must be set for type 3 tx\")\n            return [\n                Uint(self.chain_id),\n                Uint(self.nonce),\n                Uint(self.max_priority_fee_per_gas),\n                Uint(self.max_fee_per_gas),\n                Uint(self.gas_limit),\n                to,\n                Uint(self.value),\n                code_to_bytes(self.data),\n                [a.to_list() for a in self.access_list] if self.access_list is not None else [],\n                Uint(self.signature[0]),\n                Uint(self.signature[1]),\n                Uint(self.signature[2]),\n            ]\n        elif self.ty == 1:\n            # EIP-2930: https://eips.ethereum.org/EIPS/eip-2930\n            if self.gas_price is None:\n                raise ValueError(\"gas_price must be set for type 1 tx\")\n\n            return [\n                Uint(self.chain_id),\n                Uint(self.nonce),\n                Uint(self.gas_price),\n                Uint(self.gas_limit),\n                to,\n                Uint(self.value),\n                code_to_bytes(self.data),\n                [a.to_list() for a in self.access_list] if self.access_list is not None else [],\n                Uint(self.signature[0]),\n                Uint(self.signature[1]),\n                Uint(self.signature[2]),\n            ]\n        elif self.ty == 0:\n            if self.gas_price is None:\n                raise ValueError(\"gas_price must be set for type 0 tx\")\n            # EIP-155: https://eips.ethereum.org/EIPS/eip-155\n            return [\n                Uint(self.nonce),\n                Uint(self.gas_price),\n                Uint(self.gas_limit),\n                to,\n                Uint(self.value),\n                code_to_bytes(self.data),\n                Uint(self.signature[0]),\n                Uint(self.signature[1]),\n                Uint(self.signature[2]),\n            ]\n\n        raise NotImplementedError(f\"serialized_bytes not implemented for tx type {self.ty}\")\n\n    def serialized_bytes(self) -> bytes:\n\"\"\"\n        Returns bytes of the serialized representation of the transaction,\n        which is almost always RLP encoding.\n        \"\"\"\n        if self.ty is None:\n            raise ValueError(\"ty must be set for all tx types\")\n\n        if self.ty > 0:\n            return bytes([self.ty]) + eth_rlp.encode(self.payload_body())\n        else:\n            return eth_rlp.encode(self.payload_body())\n\n    def signing_envelope(self) -> List[Any]:\n\"\"\"\n        Returns the list of values included in the envelope used for signing.\n        \"\"\"\n        if self.gas_limit is None:\n            raise ValueError(\"gas_limit must be set for all tx types\")\n        to = address_to_bytes(self.to)\n\n        if self.ty == 3:\n            # EIP-4844: https://eips.ethereum.org/EIPS/eip-4844\n            if self.max_priority_fee_per_gas is None:\n                raise ValueError(\"max_priority_fee_per_gas must be set for type 3 tx\")\n            if self.max_fee_per_gas is None:\n                raise ValueError(\"max_fee_per_gas must be set for type 3 tx\")\n            if self.max_fee_per_data_gas is None:\n                raise ValueError(\"max_fee_per_data_gas must be set for type 3 tx\")\n            if self.blob_versioned_hashes is None:\n                raise ValueError(\"blob_versioned_hashes must be set for type 3 tx\")\n            return [\n                Uint(self.chain_id),\n                Uint(self.nonce),\n                Uint(self.max_priority_fee_per_gas),\n                Uint(self.max_fee_per_gas),\n                Uint(self.gas_limit),\n                to,\n                Uint(self.value),\n                code_to_bytes(self.data),\n                [a.to_list() for a in self.access_list] if self.access_list is not None else [],\n                Uint(self.max_fee_per_data_gas),\n                [hash_to_bytes(h) for h in self.blob_versioned_hashes],\n            ]\n        elif self.ty == 2:\n            # EIP-1559: https://eips.ethereum.org/EIPS/eip-1559\n            if self.max_priority_fee_per_gas is None:\n                raise ValueError(\"max_priority_fee_per_gas must be set for type 3 tx\")\n            if self.max_fee_per_gas is None:\n                raise ValueError(\"max_fee_per_gas must be set for type 3 tx\")\n            return [\n                Uint(self.chain_id),\n                Uint(self.nonce),\n                Uint(self.max_priority_fee_per_gas),\n                Uint(self.max_fee_per_gas),\n                Uint(self.gas_limit),\n                to,\n                Uint(self.value),\n                code_to_bytes(self.data),\n                [a.to_list() for a in self.access_list] if self.access_list is not None else [],\n            ]\n        elif self.ty == 1:\n            # EIP-2930: https://eips.ethereum.org/EIPS/eip-2930\n            if self.gas_price is None:\n                raise ValueError(\"gas_price must be set for type 1 tx\")\n\n            return [\n                Uint(self.chain_id),\n                Uint(self.nonce),\n                Uint(self.gas_price),\n                Uint(self.gas_limit),\n                to,\n                Uint(self.value),\n                code_to_bytes(self.data),\n                [a.to_list() for a in self.access_list] if self.access_list is not None else [],\n            ]\n        elif self.ty == 0:\n            if self.gas_price is None:\n                raise ValueError(\"gas_price must be set for type 0 tx\")\n\n            if self.protected:\n                # EIP-155: https://eips.ethereum.org/EIPS/eip-155\n                return [\n                    Uint(self.nonce),\n                    Uint(self.gas_price),\n                    Uint(self.gas_limit),\n                    to,\n                    Uint(self.value),\n                    code_to_bytes(self.data),\n                    Uint(self.chain_id),\n                    Uint(0),\n                    Uint(0),\n                ]\n            else:\n                return [\n                    Uint(self.nonce),\n                    Uint(self.gas_price),\n                    Uint(self.gas_limit),\n                    to,\n                    Uint(self.value),\n                    code_to_bytes(self.data),\n                ]\n        raise NotImplementedError(\"sigining for transaction type {self.ty} not implemented\")\n\n    def signing_bytes(self) -> bytes:\n\"\"\"\n        Returns the serialized bytes of the transaction used for signing.\n        \"\"\"\n        if self.ty is None:\n            raise ValueError(\"ty must be set for all tx types\")\n\n        if self.ty > 0:\n            return bytes([self.ty]) + eth_rlp.encode(self.signing_envelope())\n        else:\n            return eth_rlp.encode(self.signing_envelope())\n\n    def with_signature_and_sender(self) -> \"Transaction\":\n\"\"\"\n        Returns a signed version of the transaction using the private key.\n        \"\"\"\n        tx = copy(self)\n\n        if tx.signature is not None:\n            # Transaction already signed\n            if tx.sender is None:\n                # TODO: We need to recover the sender from the signature\n                raise NotImplementedError(\"recovering sender from signature not implemented\")\n            return tx\n\n        if tx.secret_key is None:\n            raise ValueError(\"secret_key must be set to sign a transaction\")\n\n        # Get the signing bytes\n        signing_hash = keccak256(tx.signing_bytes())\n\n        # Sign the bytes\n        private_key = PrivateKey.from_int(hash_to_int(tx.secret_key))\n        signature_bytes = private_key.sign_recoverable(signing_hash, hasher=None)\n        public_key = PublicKey.from_signature_and_message(\n            signature_bytes, signing_hash, hasher=None\n        )\n        tx.sender = keccak256(public_key.format(compressed=False)[1:])[32 - 20 :]\n\n        v, r, s = (\n            signature_bytes[64],\n            int.from_bytes(signature_bytes[0:32], byteorder=\"big\"),\n            int.from_bytes(signature_bytes[32:64], byteorder=\"big\"),\n        )\n        if tx.ty == 0:\n            if tx.protected:\n                v += 35 + (tx.chain_id * 2)\n            else:  # not protected\n                v += 27\n\n        tx.signature = (v, r, s)\n\n        # Remove the secret key because otherwise we might attempt to sign again (?)\n        tx.secret_key = None\n        return tx\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Transaction.ty","title":"ty: Optional[int] = None class-attribute instance-attribute","text":"

Transaction type value.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Transaction.InvalidFeePayment","title":"InvalidFeePayment","text":"

Bases: Exception

Transaction described more than one fee payment type.

Source code in src/ethereum_test_tools/common/types.py
class InvalidFeePayment(Exception):\n\"\"\"\n    Transaction described more than one fee payment type.\n    \"\"\"\n\n    def __str__(self):\n\"\"\"Print exception string\"\"\"\n        return \"only one type of fee payment field can be used in a single tx\"\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Transaction.InvalidFeePayment.__str__","title":"__str__()","text":"

Print exception string

Source code in src/ethereum_test_tools/common/types.py
def __str__(self):\n\"\"\"Print exception string\"\"\"\n    return \"only one type of fee payment field can be used in a single tx\"\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Transaction.InvalidSignaturePrivateKey","title":"InvalidSignaturePrivateKey","text":"

Bases: Exception

Transaction describes both the signature and private key of source account.

Source code in src/ethereum_test_tools/common/types.py
class InvalidSignaturePrivateKey(Exception):\n\"\"\"\n    Transaction describes both the signature and private key of\n    source account.\n    \"\"\"\n\n    def __str__(self):\n\"\"\"Print exception string\"\"\"\n        return \"can't define both 'signature' and 'private_key'\"\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Transaction.InvalidSignaturePrivateKey.__str__","title":"__str__()","text":"

Print exception string

Source code in src/ethereum_test_tools/common/types.py
def __str__(self):\n\"\"\"Print exception string\"\"\"\n    return \"can't define both 'signature' and 'private_key'\"\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Transaction.__post_init__","title":"__post_init__()","text":"

Ensures the transaction has no conflicting properties.

Source code in src/ethereum_test_tools/common/types.py
def __post_init__(self) -> None:\n\"\"\"\n    Ensures the transaction has no conflicting properties.\n    \"\"\"\n    if (\n        self.gas_price is not None\n        and self.max_fee_per_gas is not None\n        and self.max_priority_fee_per_gas is not None\n    ):\n        raise Transaction.InvalidFeePayment()\n\n    if (\n        self.gas_price is None\n        and self.max_fee_per_gas is None\n        and self.max_priority_fee_per_gas is None\n    ):\n        self.gas_price = 10\n\n    if self.signature is not None and self.secret_key is not None:\n        raise Transaction.InvalidSignaturePrivateKey()\n\n    if self.signature is None and self.secret_key is None:\n        self.secret_key = TestPrivateKey\n\n    if self.ty is None:\n        # Try to deduce transaction type from included fields\n        if self.max_fee_per_data_gas is not None:\n            self.ty = 3\n        elif self.max_fee_per_gas is not None:\n            self.ty = 2\n        elif self.access_list is not None:\n            self.ty = 1\n        else:\n            self.ty = 0\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Transaction.with_error","title":"with_error(error)","text":"

Create a copy of the transaction with an added error.

Source code in src/ethereum_test_tools/common/types.py
def with_error(self, error: str) -> \"Transaction\":\n\"\"\"\n    Create a copy of the transaction with an added error.\n    \"\"\"\n    tx = copy(self)\n    tx.error = error\n    return tx\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Transaction.with_nonce","title":"with_nonce(nonce)","text":"

Create a copy of the transaction with a modified nonce.

Source code in src/ethereum_test_tools/common/types.py
def with_nonce(self, nonce: int) -> \"Transaction\":\n\"\"\"\n    Create a copy of the transaction with a modified nonce.\n    \"\"\"\n    tx = copy(self)\n    tx.nonce = nonce\n    return tx\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Transaction.with_fields","title":"with_fields(**kwargs)","text":"

Create a deepcopy of the transaction with modified fields.

Source code in src/ethereum_test_tools/common/types.py
def with_fields(self, **kwargs) -> \"Transaction\":\n\"\"\"\n    Create a deepcopy of the transaction with modified fields.\n    \"\"\"\n    tx = deepcopy(self)\n    for key, value in kwargs.items():\n        if hasattr(tx, key):\n            setattr(tx, key, value)\n        else:\n            raise ValueError(f\"Invalid field '{key}' for Transaction\")\n    return tx\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Transaction.payload_body","title":"payload_body()","text":"

Returns the list of values included in the transaction body.

Source code in src/ethereum_test_tools/common/types.py
def payload_body(self) -> List[Any]:\n\"\"\"\n    Returns the list of values included in the transaction body.\n    \"\"\"\n    if self.signature is None:\n        raise ValueError(\"signature must be set before serializing any tx type\")\n\n    if self.gas_limit is None:\n        raise ValueError(\"gas_limit must be set for all tx types\")\n    to = address_to_bytes(self.to)\n\n    if self.ty == 3:\n        # EIP-4844: https://eips.ethereum.org/EIPS/eip-4844\n        if self.max_priority_fee_per_gas is None:\n            raise ValueError(\"max_priority_fee_per_gas must be set for type 3 tx\")\n        if self.max_fee_per_gas is None:\n            raise ValueError(\"max_fee_per_gas must be set for type 3 tx\")\n        if self.max_fee_per_data_gas is None:\n            raise ValueError(\"max_fee_per_data_gas must be set for type 3 tx\")\n        if self.blob_versioned_hashes is None:\n            raise ValueError(\"blob_versioned_hashes must be set for type 3 tx\")\n\n        if self.wrapped_blob_transaction:\n            if self.blobs is None:\n                raise ValueError(\"blobs must be set for network version of type 3 tx\")\n            if self.blob_kzg_commitments is None:\n                raise ValueError(\n                    \"blob_kzg_commitments must be set for network version of type 3 tx\"\n                )\n            if self.blob_kzg_proofs is None:\n                raise ValueError(\n                    \"blob_kzg_proofs must be set for network version of type 3 tx\"\n                )\n\n            return [\n                [\n                    Uint(self.chain_id),\n                    Uint(self.nonce),\n                    Uint(self.max_priority_fee_per_gas),\n                    Uint(self.max_fee_per_gas),\n                    Uint(self.gas_limit),\n                    to,\n                    Uint(self.value),\n                    code_to_bytes(self.data),\n                    [a.to_list() for a in self.access_list]\n                    if self.access_list is not None\n                    else [],\n                    Uint(self.max_fee_per_data_gas),\n                    [hash_to_bytes(h) for h in self.blob_versioned_hashes],\n                    Uint(self.signature[0]),\n                    Uint(self.signature[1]),\n                    Uint(self.signature[2]),\n                ],\n                self.blobs,\n                self.blob_kzg_commitments,\n                self.blob_kzg_proofs,\n            ]\n        else:\n            return [\n                Uint(self.chain_id),\n                Uint(self.nonce),\n                Uint(self.max_priority_fee_per_gas),\n                Uint(self.max_fee_per_gas),\n                Uint(self.gas_limit),\n                to,\n                Uint(self.value),\n                code_to_bytes(self.data),\n                [a.to_list() for a in self.access_list]\n                if self.access_list is not None\n                else [],\n                Uint(self.max_fee_per_data_gas),\n                [hash_to_bytes(h) for h in self.blob_versioned_hashes],\n                Uint(self.signature[0]),\n                Uint(self.signature[1]),\n                Uint(self.signature[2]),\n            ]\n    elif self.ty == 2:\n        # EIP-1559: https://eips.ethereum.org/EIPS/eip-1559\n        if self.max_priority_fee_per_gas is None:\n            raise ValueError(\"max_priority_fee_per_gas must be set for type 3 tx\")\n        if self.max_fee_per_gas is None:\n            raise ValueError(\"max_fee_per_gas must be set for type 3 tx\")\n        return [\n            Uint(self.chain_id),\n            Uint(self.nonce),\n            Uint(self.max_priority_fee_per_gas),\n            Uint(self.max_fee_per_gas),\n            Uint(self.gas_limit),\n            to,\n            Uint(self.value),\n            code_to_bytes(self.data),\n            [a.to_list() for a in self.access_list] if self.access_list is not None else [],\n            Uint(self.signature[0]),\n            Uint(self.signature[1]),\n            Uint(self.signature[2]),\n        ]\n    elif self.ty == 1:\n        # EIP-2930: https://eips.ethereum.org/EIPS/eip-2930\n        if self.gas_price is None:\n            raise ValueError(\"gas_price must be set for type 1 tx\")\n\n        return [\n            Uint(self.chain_id),\n            Uint(self.nonce),\n            Uint(self.gas_price),\n            Uint(self.gas_limit),\n            to,\n            Uint(self.value),\n            code_to_bytes(self.data),\n            [a.to_list() for a in self.access_list] if self.access_list is not None else [],\n            Uint(self.signature[0]),\n            Uint(self.signature[1]),\n            Uint(self.signature[2]),\n        ]\n    elif self.ty == 0:\n        if self.gas_price is None:\n            raise ValueError(\"gas_price must be set for type 0 tx\")\n        # EIP-155: https://eips.ethereum.org/EIPS/eip-155\n        return [\n            Uint(self.nonce),\n            Uint(self.gas_price),\n            Uint(self.gas_limit),\n            to,\n            Uint(self.value),\n            code_to_bytes(self.data),\n            Uint(self.signature[0]),\n            Uint(self.signature[1]),\n            Uint(self.signature[2]),\n        ]\n\n    raise NotImplementedError(f\"serialized_bytes not implemented for tx type {self.ty}\")\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Transaction.serialized_bytes","title":"serialized_bytes()","text":"

Returns bytes of the serialized representation of the transaction, which is almost always RLP encoding.

Source code in src/ethereum_test_tools/common/types.py
def serialized_bytes(self) -> bytes:\n\"\"\"\n    Returns bytes of the serialized representation of the transaction,\n    which is almost always RLP encoding.\n    \"\"\"\n    if self.ty is None:\n        raise ValueError(\"ty must be set for all tx types\")\n\n    if self.ty > 0:\n        return bytes([self.ty]) + eth_rlp.encode(self.payload_body())\n    else:\n        return eth_rlp.encode(self.payload_body())\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Transaction.signing_envelope","title":"signing_envelope()","text":"

Returns the list of values included in the envelope used for signing.

Source code in src/ethereum_test_tools/common/types.py
def signing_envelope(self) -> List[Any]:\n\"\"\"\n    Returns the list of values included in the envelope used for signing.\n    \"\"\"\n    if self.gas_limit is None:\n        raise ValueError(\"gas_limit must be set for all tx types\")\n    to = address_to_bytes(self.to)\n\n    if self.ty == 3:\n        # EIP-4844: https://eips.ethereum.org/EIPS/eip-4844\n        if self.max_priority_fee_per_gas is None:\n            raise ValueError(\"max_priority_fee_per_gas must be set for type 3 tx\")\n        if self.max_fee_per_gas is None:\n            raise ValueError(\"max_fee_per_gas must be set for type 3 tx\")\n        if self.max_fee_per_data_gas is None:\n            raise ValueError(\"max_fee_per_data_gas must be set for type 3 tx\")\n        if self.blob_versioned_hashes is None:\n            raise ValueError(\"blob_versioned_hashes must be set for type 3 tx\")\n        return [\n            Uint(self.chain_id),\n            Uint(self.nonce),\n            Uint(self.max_priority_fee_per_gas),\n            Uint(self.max_fee_per_gas),\n            Uint(self.gas_limit),\n            to,\n            Uint(self.value),\n            code_to_bytes(self.data),\n            [a.to_list() for a in self.access_list] if self.access_list is not None else [],\n            Uint(self.max_fee_per_data_gas),\n            [hash_to_bytes(h) for h in self.blob_versioned_hashes],\n        ]\n    elif self.ty == 2:\n        # EIP-1559: https://eips.ethereum.org/EIPS/eip-1559\n        if self.max_priority_fee_per_gas is None:\n            raise ValueError(\"max_priority_fee_per_gas must be set for type 3 tx\")\n        if self.max_fee_per_gas is None:\n            raise ValueError(\"max_fee_per_gas must be set for type 3 tx\")\n        return [\n            Uint(self.chain_id),\n            Uint(self.nonce),\n            Uint(self.max_priority_fee_per_gas),\n            Uint(self.max_fee_per_gas),\n            Uint(self.gas_limit),\n            to,\n            Uint(self.value),\n            code_to_bytes(self.data),\n            [a.to_list() for a in self.access_list] if self.access_list is not None else [],\n        ]\n    elif self.ty == 1:\n        # EIP-2930: https://eips.ethereum.org/EIPS/eip-2930\n        if self.gas_price is None:\n            raise ValueError(\"gas_price must be set for type 1 tx\")\n\n        return [\n            Uint(self.chain_id),\n            Uint(self.nonce),\n            Uint(self.gas_price),\n            Uint(self.gas_limit),\n            to,\n            Uint(self.value),\n            code_to_bytes(self.data),\n            [a.to_list() for a in self.access_list] if self.access_list is not None else [],\n        ]\n    elif self.ty == 0:\n        if self.gas_price is None:\n            raise ValueError(\"gas_price must be set for type 0 tx\")\n\n        if self.protected:\n            # EIP-155: https://eips.ethereum.org/EIPS/eip-155\n            return [\n                Uint(self.nonce),\n                Uint(self.gas_price),\n                Uint(self.gas_limit),\n                to,\n                Uint(self.value),\n                code_to_bytes(self.data),\n                Uint(self.chain_id),\n                Uint(0),\n                Uint(0),\n            ]\n        else:\n            return [\n                Uint(self.nonce),\n                Uint(self.gas_price),\n                Uint(self.gas_limit),\n                to,\n                Uint(self.value),\n                code_to_bytes(self.data),\n            ]\n    raise NotImplementedError(\"sigining for transaction type {self.ty} not implemented\")\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Transaction.signing_bytes","title":"signing_bytes()","text":"

Returns the serialized bytes of the transaction used for signing.

Source code in src/ethereum_test_tools/common/types.py
def signing_bytes(self) -> bytes:\n\"\"\"\n    Returns the serialized bytes of the transaction used for signing.\n    \"\"\"\n    if self.ty is None:\n        raise ValueError(\"ty must be set for all tx types\")\n\n    if self.ty > 0:\n        return bytes([self.ty]) + eth_rlp.encode(self.signing_envelope())\n    else:\n        return eth_rlp.encode(self.signing_envelope())\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Transaction.with_signature_and_sender","title":"with_signature_and_sender()","text":"

Returns a signed version of the transaction using the private key.

Source code in src/ethereum_test_tools/common/types.py
def with_signature_and_sender(self) -> \"Transaction\":\n\"\"\"\n    Returns a signed version of the transaction using the private key.\n    \"\"\"\n    tx = copy(self)\n\n    if tx.signature is not None:\n        # Transaction already signed\n        if tx.sender is None:\n            # TODO: We need to recover the sender from the signature\n            raise NotImplementedError(\"recovering sender from signature not implemented\")\n        return tx\n\n    if tx.secret_key is None:\n        raise ValueError(\"secret_key must be set to sign a transaction\")\n\n    # Get the signing bytes\n    signing_hash = keccak256(tx.signing_bytes())\n\n    # Sign the bytes\n    private_key = PrivateKey.from_int(hash_to_int(tx.secret_key))\n    signature_bytes = private_key.sign_recoverable(signing_hash, hasher=None)\n    public_key = PublicKey.from_signature_and_message(\n        signature_bytes, signing_hash, hasher=None\n    )\n    tx.sender = keccak256(public_key.format(compressed=False)[1:])[32 - 20 :]\n\n    v, r, s = (\n        signature_bytes[64],\n        int.from_bytes(signature_bytes[0:32], byteorder=\"big\"),\n        int.from_bytes(signature_bytes[32:64], byteorder=\"big\"),\n    )\n    if tx.ty == 0:\n        if tx.protected:\n            v += 35 + (tx.chain_id * 2)\n        else:  # not protected\n            v += 27\n\n    tx.signature = (v, r, s)\n\n    # Remove the secret key because otherwise we might attempt to sign again (?)\n    tx.secret_key = None\n    return tx\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.Header","title":"Header dataclass","text":"

Header type used to describe block header properties in test specs.

Source code in src/ethereum_test_tools/common/types.py
@dataclass(kw_only=True)\nclass Header:\n\"\"\"\n    Header type used to describe block header properties in test specs.\n    \"\"\"\n\n    parent_hash: Optional[bytes] = None\n    ommers_hash: Optional[bytes] = None\n    coinbase: Optional[bytes | str] = None\n    state_root: Optional[bytes] = None\n    transactions_root: Optional[bytes] = None\n    receipt_root: Optional[bytes] = None\n    bloom: Optional[bytes] = None\n    difficulty: Optional[int] = None\n    number: Optional[int] = None\n    gas_limit: Optional[int] = None\n    gas_used: Optional[int] = None\n    timestamp: Optional[int] = None\n    extra_data: Optional[bytes] = None\n    mix_digest: Optional[bytes] = None\n    nonce: Optional[bytes] = None\n    base_fee: Optional[int | Removable] = None\n    withdrawals_root: Optional[bytes | Removable] = None\n    data_gas_used: Optional[int | Removable] = None\n    excess_data_gas: Optional[int | Removable] = None\n    hash: Optional[bytes] = None\n\n    REMOVE_FIELD: ClassVar[Removable] = Removable()\n\"\"\"\n    Sentinel object used to specify that a header field should be removed.\n    \"\"\"\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Header.REMOVE_FIELD","title":"REMOVE_FIELD: Removable = Removable() class-attribute","text":"

Sentinel object used to specify that a header field should be removed.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.Block","title":"Block dataclass","text":"

Bases: Header

Block type used to describe block properties in test specs

Source code in src/ethereum_test_tools/common/types.py
@dataclass(kw_only=True)\nclass Block(Header):\n\"\"\"\n    Block type used to describe block properties in test specs\n    \"\"\"\n\n    rlp: Optional[bytes] = None\n\"\"\"\n    If set, blockchain test will skip generating the block and will pass this value directly to\n    the Fixture.\n\n    Only meant to be used to simulate blocks with bad formats, and therefore\n    requires the block to produce an exception.\n    \"\"\"\n    rlp_modifier: Optional[Header] = None\n\"\"\"\n    An RLP modifying header which values would be used to override the ones\n    returned by the  `evm_transition_tool`.\n    \"\"\"\n    exception: Optional[str] = None\n\"\"\"\n    If set, the block is expected to be rejected by the client.\n    \"\"\"\n    engine_api_error_code: Optional[EngineAPIError] = None\n\"\"\"\n    If set, the block is expected to produce an error response from the Engine API.\n    \"\"\"\n    txs: Optional[List[Transaction]] = None\n\"\"\"\n    List of transactions included in the block.\n    \"\"\"\n    ommers: Optional[List[Header]] = None\n\"\"\"\n    List of ommer headers included in the block.\n    \"\"\"\n    withdrawals: Optional[List[Withdrawal]] = None\n\"\"\"\n    List of withdrawals to perform for this block.\n    \"\"\"\n\n    def set_environment(self, env: Environment) -> Environment:\n\"\"\"\n        Creates a copy of the environment with the characteristics of this\n        specific block.\n        \"\"\"\n        new_env = copy(env)\n\n\"\"\"\n        Values that need to be set in the environment and are `None` for\n        this block need to be set to their defaults.\n        \"\"\"\n        environment_default = Environment()\n        new_env.difficulty = self.difficulty\n        new_env.coinbase = (\n            self.coinbase if self.coinbase is not None else environment_default.coinbase\n        )\n        new_env.gas_limit = (\n            self.gas_limit if self.gas_limit is not None else environment_default.gas_limit\n        )\n        if not isinstance(self.base_fee, Removable):\n            new_env.base_fee = self.base_fee\n        new_env.withdrawals = self.withdrawals\n        if not isinstance(self.excess_data_gas, Removable):\n            new_env.excess_data_gas = self.excess_data_gas\n        if not isinstance(self.data_gas_used, Removable):\n            new_env.data_gas_used = self.data_gas_used\n\"\"\"\n        These values are required, but they depend on the previous environment,\n        so they can be calculated here.\n        \"\"\"\n        if self.number is not None:\n            new_env.number = self.number\n        else:\n            # calculate the next block number for the environment\n            if len(new_env.block_hashes) == 0:\n                new_env.number = 0\n            else:\n                new_env.number = max(new_env.block_hashes.keys()) + 1\n\n        if self.timestamp is not None:\n            new_env.timestamp = self.timestamp\n        else:\n            assert new_env.parent_timestamp is not None\n            new_env.timestamp = new_env.parent_timestamp + 12\n\n        return new_env\n\n    def copy_with_rlp(self, rlp: bytes) -> \"Block\":\n\"\"\"\n        Creates a copy of the block and adds the specified RLP.\n        \"\"\"\n        new_block = deepcopy(self)\n        new_block.rlp = rlp\n        return new_block\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Block.rlp","title":"rlp: Optional[bytes] = None class-attribute instance-attribute","text":"

If set, blockchain test will skip generating the block and will pass this value directly to the Fixture.

Only meant to be used to simulate blocks with bad formats, and therefore requires the block to produce an exception.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Block.rlp_modifier","title":"rlp_modifier: Optional[Header] = None class-attribute instance-attribute","text":"

An RLP modifying header which values would be used to override the ones returned by the evm_transition_tool.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Block.exception","title":"exception: Optional[str] = None class-attribute instance-attribute","text":"

If set, the block is expected to be rejected by the client.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Block.engine_api_error_code","title":"engine_api_error_code: Optional[EngineAPIError] = None class-attribute instance-attribute","text":"

If set, the block is expected to produce an error response from the Engine API.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Block.txs","title":"txs: Optional[List[Transaction]] = None class-attribute instance-attribute","text":"

List of transactions included in the block.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Block.ommers","title":"ommers: Optional[List[Header]] = None class-attribute instance-attribute","text":"

List of ommer headers included in the block.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Block.withdrawals","title":"withdrawals: Optional[List[Withdrawal]] = None class-attribute instance-attribute","text":"

List of withdrawals to perform for this block.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Block.set_environment","title":"set_environment(env)","text":"

Creates a copy of the environment with the characteristics of this specific block.

Source code in src/ethereum_test_tools/common/types.py
def set_environment(self, env: Environment) -> Environment:\n\"\"\"\n    Creates a copy of the environment with the characteristics of this\n    specific block.\n    \"\"\"\n    new_env = copy(env)\n\n\"\"\"\n    Values that need to be set in the environment and are `None` for\n    this block need to be set to their defaults.\n    \"\"\"\n    environment_default = Environment()\n    new_env.difficulty = self.difficulty\n    new_env.coinbase = (\n        self.coinbase if self.coinbase is not None else environment_default.coinbase\n    )\n    new_env.gas_limit = (\n        self.gas_limit if self.gas_limit is not None else environment_default.gas_limit\n    )\n    if not isinstance(self.base_fee, Removable):\n        new_env.base_fee = self.base_fee\n    new_env.withdrawals = self.withdrawals\n    if not isinstance(self.excess_data_gas, Removable):\n        new_env.excess_data_gas = self.excess_data_gas\n    if not isinstance(self.data_gas_used, Removable):\n        new_env.data_gas_used = self.data_gas_used\n\"\"\"\n    These values are required, but they depend on the previous environment,\n    so they can be calculated here.\n    \"\"\"\n    if self.number is not None:\n        new_env.number = self.number\n    else:\n        # calculate the next block number for the environment\n        if len(new_env.block_hashes) == 0:\n            new_env.number = 0\n        else:\n            new_env.number = max(new_env.block_hashes.keys()) + 1\n\n    if self.timestamp is not None:\n        new_env.timestamp = self.timestamp\n    else:\n        assert new_env.parent_timestamp is not None\n        new_env.timestamp = new_env.parent_timestamp + 12\n\n    return new_env\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Block.copy_with_rlp","title":"copy_with_rlp(rlp)","text":"

Creates a copy of the block and adds the specified RLP.

Source code in src/ethereum_test_tools/common/types.py
def copy_with_rlp(self, rlp: bytes) -> \"Block\":\n\"\"\"\n    Creates a copy of the block and adds the specified RLP.\n    \"\"\"\n    new_block = deepcopy(self)\n    new_block.rlp = rlp\n    return new_block\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.FixtureEngineNewPayload","title":"FixtureEngineNewPayload dataclass","text":"

Representation of the engine_newPayloadVX information to be sent using the block information.

Source code in src/ethereum_test_tools/common/types.py
@dataclass(kw_only=True)\nclass FixtureEngineNewPayload:\n\"\"\"\n    Representation of the `engine_newPayloadVX` information to be\n    sent using the block information.\n    \"\"\"\n\n    payload: FixtureExecutionPayload\n    version: int\n    blob_versioned_hashes: Optional[List[bytes]] = None\n    error_code: Optional[EngineAPIError] = None\n\n    @classmethod\n    def from_fixture_header(\n        cls,\n        fork: Fork,\n        header: FixtureHeader,\n        transactions: List[Transaction],\n        withdrawals: Optional[List[Withdrawal]],\n        error_code: Optional[EngineAPIError],\n    ) -> Optional[\"FixtureEngineNewPayload\"]:\n\"\"\"\n        Creates a `FixtureEngineNewPayload` from a `FixtureHeader`.\n        \"\"\"\n        new_payload_version = fork.engine_new_payload_version(header.number, header.timestamp)\n\n        if new_payload_version is None:\n            return None\n\n        new_payload = cls(\n            payload=FixtureExecutionPayload(\n                header=header, transactions=transactions, withdrawals=withdrawals\n            ),\n            version=new_payload_version,\n            error_code=error_code,\n        )\n\n        if fork.engine_new_payload_blob_hashes(header.number, header.timestamp):\n            new_payload.blob_versioned_hashes = blob_versioned_hashes_from_transactions(\n                transactions\n            )\n\n        return new_payload\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.FixtureEngineNewPayload.from_fixture_header","title":"from_fixture_header(fork, header, transactions, withdrawals, error_code) classmethod","text":"

Creates a FixtureEngineNewPayload from a FixtureHeader.

Source code in src/ethereum_test_tools/common/types.py
@classmethod\ndef from_fixture_header(\n    cls,\n    fork: Fork,\n    header: FixtureHeader,\n    transactions: List[Transaction],\n    withdrawals: Optional[List[Withdrawal]],\n    error_code: Optional[EngineAPIError],\n) -> Optional[\"FixtureEngineNewPayload\"]:\n\"\"\"\n    Creates a `FixtureEngineNewPayload` from a `FixtureHeader`.\n    \"\"\"\n    new_payload_version = fork.engine_new_payload_version(header.number, header.timestamp)\n\n    if new_payload_version is None:\n        return None\n\n    new_payload = cls(\n        payload=FixtureExecutionPayload(\n            header=header, transactions=transactions, withdrawals=withdrawals\n        ),\n        version=new_payload_version,\n        error_code=error_code,\n    )\n\n    if fork.engine_new_payload_blob_hashes(header.number, header.timestamp):\n        new_payload.blob_versioned_hashes = blob_versioned_hashes_from_transactions(\n            transactions\n        )\n\n    return new_payload\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.Fixture","title":"Fixture dataclass","text":"

Cross-client compatible Ethereum test fixture.

Source code in src/ethereum_test_tools/common/types.py
@dataclass(kw_only=True)\nclass Fixture:\n\"\"\"\n    Cross-client compatible Ethereum test fixture.\n    \"\"\"\n\n    blocks: List[FixtureBlock]\n    genesis: FixtureHeader\n    genesis_rlp: bytes\n    head: bytes\n    fork: str\n    pre_state: Mapping[str, Account]\n    post_state: Optional[Mapping[str, Account]]\n    seal_engine: str\n    info: Dict[str, str] = field(default_factory=dict)\n    name: str = \"\"\n\n    _json: Dict[str, Any] | None = None\n\n    def __post_init__(self):\n\"\"\"\n        Post init hook to convert to JSON after instantiation.\n        \"\"\"\n        self._json = to_json(self)\n\n    def fill_info(\n        self,\n        t8n: TransitionTool,\n        ref_spec: ReferenceSpec | None,\n    ):\n\"\"\"\n        Fill the info field for this fixture\n        \"\"\"\n        self.info[\"filling-transition-tool\"] = t8n.version()\n        if ref_spec is not None:\n            ref_spec.write_info(self.info)\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Fixture.__post_init__","title":"__post_init__()","text":"

Post init hook to convert to JSON after instantiation.

Source code in src/ethereum_test_tools/common/types.py
def __post_init__(self):\n\"\"\"\n    Post init hook to convert to JSON after instantiation.\n    \"\"\"\n    self._json = to_json(self)\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Fixture.fill_info","title":"fill_info(t8n, ref_spec)","text":"

Fill the info field for this fixture

Source code in src/ethereum_test_tools/common/types.py
def fill_info(\n    self,\n    t8n: TransitionTool,\n    ref_spec: ReferenceSpec | None,\n):\n\"\"\"\n    Fill the info field for this fixture\n    \"\"\"\n    self.info[\"filling-transition-tool\"] = t8n.version()\n    if ref_spec is not None:\n        ref_spec.write_info(self.info)\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.JSONEncoder","title":"JSONEncoder","text":"

Bases: json.JSONEncoder

Custom JSON encoder for ethereum_test types.

Source code in src/ethereum_test_tools/common/types.py
class JSONEncoder(json.JSONEncoder):\n\"\"\"\n    Custom JSON encoder for `ethereum_test` types.\n    \"\"\"\n\n    def default(self, obj: JSONEncoderSupportedType) -> Any:\n\"\"\"\n        Enocdes types defined in this module using basic python facilities.\n        \"\"\"\n        if isinstance(obj, Storage):\n            return obj.to_dict()\n        elif isinstance(obj, Account):\n            account = {\n                \"nonce\": hex_or_none(obj.nonce, hex(0)),\n                \"balance\": hex_or_none(obj.balance, hex(0)),\n                \"code\": code_or_none(obj.code, \"0x\"),\n                \"storage\": to_json_or_none(obj.storage, {}),\n            }\n            return even_padding(account, excluded=[\"storage\"])\n        elif isinstance(obj, AccessList):\n            access_list: Dict[str, Any] = {\n                \"address\": address_or_none(obj.address, \"0x\" + ZeroAddress.hex())\n            }\n            if obj.storage_keys is not None:\n                access_list[\"storageKeys\"] = [hex_or_none(k) for k in obj.storage_keys]\n            return access_list\n        elif isinstance(obj, Transaction):\n            assert obj.ty is not None, \"Transaction type must be set\"\n            tx: Dict[str, Any] = {\n                \"type\": hex(obj.ty),\n                \"chainId\": hex(obj.chain_id),\n                \"nonce\": hex(obj.nonce),\n                \"gasPrice\": hex_or_none(obj.gas_price),\n                \"maxPriorityFeePerGas\": hex_or_none(obj.max_priority_fee_per_gas),\n                \"maxFeePerGas\": hex_or_none(obj.max_fee_per_gas),\n                \"gas\": hex(obj.gas_limit),\n                \"value\": hex(obj.value),\n                \"input\": code_to_hex(obj.data),\n                \"to\": address_or_none(obj.to),\n                \"accessList\": obj.access_list,\n                \"secretKey\": obj.secret_key,\n                \"maxFeePerDataGas\": hex_or_none(obj.max_fee_per_data_gas),\n                \"sender\": address_or_none(obj.sender),\n            }\n\n            if obj.blob_versioned_hashes is not None:\n                tx[\"blobVersionedHashes\"] = [hash_string(h) for h in obj.blob_versioned_hashes]\n\n            if obj.secret_key is None:\n                assert obj.signature is not None\n                assert len(obj.signature) == 3\n                tx[\"v\"] = hex(obj.signature[0])\n                tx[\"r\"] = hex(obj.signature[1])\n                tx[\"s\"] = hex(obj.signature[2])\n            else:\n                tx[\"v\"] = \"\"\n                tx[\"r\"] = \"\"\n                tx[\"s\"] = \"\"\n\n            return {k: v for (k, v) in tx.items() if v is not None}\n        elif isinstance(obj, Withdrawal):\n            withdrawal = {\n                \"index\": hex(obj.index),\n                \"validatorIndex\": hex(obj.validator),\n                \"address\": obj.address,\n                \"amount\": hex(obj.amount),\n            }\n            return withdrawal\n        elif isinstance(obj, Environment):\n            env: Dict[str, Any] = {\n                \"currentCoinbase\": address_or_none(obj.coinbase, \"0x\" + ZeroAddress.hex()),\n                \"currentGasLimit\": str_or_none(obj.gas_limit),\n                \"currentNumber\": str_or_none(obj.number),\n                \"currentTimestamp\": str_or_none(obj.timestamp),\n                \"currentRandom\": str_or_none(obj.prev_randao),\n                \"currentDifficulty\": str_or_none(obj.difficulty),\n                \"parentDifficulty\": str_or_none(obj.parent_difficulty),\n                \"parentBaseFee\": str_or_none(obj.parent_base_fee),\n                \"parentGasUsed\": str_or_none(obj.parent_gas_used),\n                \"parentGasLimit\": str_or_none(obj.parent_gas_limit),\n                \"parentTimestamp\": str_or_none(obj.parent_timestamp),\n                \"blockHashes\": {str(k): hex_or_none(v) for (k, v) in obj.block_hashes.items()},\n                \"ommers\": [],\n                \"withdrawals\": to_json_or_none(obj.withdrawals),\n                \"parentUncleHash\": hash_string(obj.parent_ommers_hash),\n                \"currentBaseFee\": str_or_none(obj.base_fee),\n                \"parentDataGasUsed\": str_or_none(obj.parent_data_gas_used),\n                \"parentExcessDataGas\": str_or_none(obj.parent_excess_data_gas),\n                \"currentExcessDataGas\": str_or_none(obj.excess_data_gas),\n                \"currentDataGasUsed\": str_or_none(obj.data_gas_used),\n            }\n\n            return {k: v for (k, v) in env.items() if v is not None}\n        elif isinstance(obj, FixtureHeader):\n            header = {\n                \"parentHash\": hex_or_none(obj.parent_hash),\n                \"uncleHash\": hex_or_none(obj.ommers_hash),\n                \"coinbase\": hex_or_none(obj.coinbase),\n                \"stateRoot\": hex_or_none(obj.state_root),\n                \"transactionsTrie\": hex_or_none(obj.transactions_root),\n                \"receiptTrie\": hex_or_none(obj.receipt_root),\n                \"bloom\": hex_or_none(obj.bloom),\n                \"difficulty\": hex(obj.difficulty),\n                \"number\": hex(obj.number),\n                \"gasLimit\": hex(obj.gas_limit),\n                \"gasUsed\": hex(obj.gas_used),\n                \"timestamp\": hex(obj.timestamp),\n                \"extraData\": hex_or_none(obj.extra_data),\n                \"mixHash\": hex_or_none(obj.mix_digest),\n                \"nonce\": hex_or_none(obj.nonce),\n            }\n            if obj.base_fee is not None:\n                header[\"baseFeePerGas\"] = hex(obj.base_fee)\n            if obj.hash is not None:\n                header[\"hash\"] = \"0x\" + obj.hash.hex()\n            if obj.withdrawals_root is not None:\n                header[\"withdrawalsRoot\"] = hex_or_none(obj.withdrawals_root)\n            if obj.data_gas_used is not None:\n                header[\"dataGasUsed\"] = hex(obj.data_gas_used)\n            if obj.excess_data_gas is not None:\n                header[\"excessDataGas\"] = hex(obj.excess_data_gas)\n            return even_padding(\n                header,\n                excluded=[\n                    \"parentHash\",\n                    \"uncleHash\",\n                    \"stateRoot\",\n                    \"coinbase\",\n                    \"transactionsTrie\",\n                    \"receiptTrie\",\n                    \"bloom\",\n                    \"nonce\",\n                    \"mixHash\",\n                    \"hash\",\n                    \"withdrawalsRoot\",\n                    \"extraData\",\n                ],\n            )\n        elif isinstance(obj, FixtureTransaction):\n            json_tx = to_json(obj.tx)\n            if json_tx[\"v\"] == \"\":\n                del json_tx[\"v\"]\n                del json_tx[\"r\"]\n                del json_tx[\"s\"]\n            if \"input\" in json_tx:\n                json_tx[\"data\"] = json_tx[\"input\"]\n                del json_tx[\"input\"]\n            if \"gas\" in json_tx:\n                json_tx[\"gasLimit\"] = json_tx[\"gas\"]\n                del json_tx[\"gas\"]\n            if \"to\" not in json_tx:\n                json_tx[\"to\"] = \"\"\n            return even_padding(\n                json_tx,\n                excluded=[\"data\", \"to\", \"accessList\"],\n            )\n        elif isinstance(obj, FixtureExecutionPayload):\n            payload: Dict[str, Any] = {\n                \"parentHash\": hex_or_none(obj.header.parent_hash),\n                \"feeRecipient\": hex_or_none(obj.header.coinbase),\n                \"stateRoot\": hex_or_none(obj.header.state_root),\n                \"receiptsRoot\": hex_or_none(obj.header.receipt_root),\n                \"logsBloom\": hex_or_none(obj.header.bloom),\n                \"prevRandao\": hex_or_none(obj.header.mix_digest),\n                \"blockNumber\": hex(obj.header.number),\n                \"gasLimit\": hex(obj.header.gas_limit),\n                \"gasUsed\": hex(obj.header.gas_used),\n                \"timestamp\": hex(obj.header.timestamp),\n                \"extraData\": hex_or_none(obj.header.extra_data),\n            }\n            if obj.header.base_fee is not None:\n                payload[\"baseFeePerGas\"] = hex(obj.header.base_fee)\n            if obj.header.hash is not None:\n                payload[\"blockHash\"] = \"0x\" + obj.header.hash.hex()\n\n            if obj.transactions is not None:\n                payload[\"transactions\"] = [\n                    hex_or_none(tx.serialized_bytes()) for tx in obj.transactions\n                ]\n            if obj.withdrawals is not None:\n                payload[\"withdrawals\"] = obj.withdrawals\n\n            if obj.header.data_gas_used is not None:\n                payload[\"dataGasUsed\"] = hex(obj.header.data_gas_used)\n            if obj.header.excess_data_gas is not None:\n                payload[\"excessDataGas\"] = hex(obj.header.excess_data_gas)\n\n            return payload\n        elif isinstance(obj, FixtureEngineNewPayload):\n            new_payload: Dict[str, Any] = {\n                \"payload\": to_json(obj.payload),\n                \"version\": str_or_none(obj.version),\n            }\n            if obj.blob_versioned_hashes is not None:\n                new_payload[\"blobVersionedHashes\"] = [\n                    \"0x\" + hash_to_bytes(h).hex() for h in obj.blob_versioned_hashes\n                ]\n            if obj.error_code is not None:\n                new_payload[\"errorCode\"] = str(int(obj.error_code))\n            return new_payload\n\n        elif isinstance(obj, FixtureBlock):\n            b: Dict[str, Any] = {\"rlp\": hex_or_none(obj.rlp)}\n            if obj.block_header is not None:\n                b[\"blockHeader\"] = json.loads(json.dumps(obj.block_header, cls=JSONEncoder))\n            if obj.new_payload is not None:\n                b[\"engineNewPayload\"] = to_json_or_none(obj.new_payload)\n            if obj.expected_exception is not None:\n                b[\"expectException\"] = obj.expected_exception\n            if obj.block_number is not None:\n                b[\"blocknumber\"] = str(obj.block_number)\n            if obj.txs is not None:\n                b[\"transactions\"] = [FixtureTransaction(tx=tx) for tx in obj.txs]\n            if obj.ommers is not None:\n                b[\"uncleHeaders\"] = obj.ommers\n            if obj.withdrawals is not None:\n                b[\"withdrawals\"] = [\n                    even_padding(to_json(wd), excluded=[\"address\"]) for wd in obj.withdrawals\n                ]\n            return b\n\n        elif isinstance(obj, Fixture):\n            if obj._json is not None:\n                obj._json[\"_info\"] = obj.info\n                return obj._json\n\n            f = {\n                \"_info\": obj.info,\n                \"blocks\": [json.loads(json.dumps(b, cls=JSONEncoder)) for b in obj.blocks],\n                \"genesisBlockHeader\": self.default(obj.genesis),\n                \"genesisRLP\": hex_or_none(obj.genesis_rlp),\n                \"lastblockhash\": hex_or_none(obj.head),\n                \"network\": obj.fork,\n                \"pre\": json.loads(json.dumps(obj.pre_state, cls=JSONEncoder)),\n                \"postState\": json.loads(json.dumps(obj.post_state, cls=JSONEncoder)),\n                \"sealEngine\": obj.seal_engine,\n            }\n            if f[\"postState\"] is None:\n                del f[\"postState\"]\n            return f\n        else:\n            return super().default(obj)\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.JSONEncoder.default","title":"default(obj)","text":"

Enocdes types defined in this module using basic python facilities.

Source code in src/ethereum_test_tools/common/types.py
def default(self, obj: JSONEncoderSupportedType) -> Any:\n\"\"\"\n    Enocdes types defined in this module using basic python facilities.\n    \"\"\"\n    if isinstance(obj, Storage):\n        return obj.to_dict()\n    elif isinstance(obj, Account):\n        account = {\n            \"nonce\": hex_or_none(obj.nonce, hex(0)),\n            \"balance\": hex_or_none(obj.balance, hex(0)),\n            \"code\": code_or_none(obj.code, \"0x\"),\n            \"storage\": to_json_or_none(obj.storage, {}),\n        }\n        return even_padding(account, excluded=[\"storage\"])\n    elif isinstance(obj, AccessList):\n        access_list: Dict[str, Any] = {\n            \"address\": address_or_none(obj.address, \"0x\" + ZeroAddress.hex())\n        }\n        if obj.storage_keys is not None:\n            access_list[\"storageKeys\"] = [hex_or_none(k) for k in obj.storage_keys]\n        return access_list\n    elif isinstance(obj, Transaction):\n        assert obj.ty is not None, \"Transaction type must be set\"\n        tx: Dict[str, Any] = {\n            \"type\": hex(obj.ty),\n            \"chainId\": hex(obj.chain_id),\n            \"nonce\": hex(obj.nonce),\n            \"gasPrice\": hex_or_none(obj.gas_price),\n            \"maxPriorityFeePerGas\": hex_or_none(obj.max_priority_fee_per_gas),\n            \"maxFeePerGas\": hex_or_none(obj.max_fee_per_gas),\n            \"gas\": hex(obj.gas_limit),\n            \"value\": hex(obj.value),\n            \"input\": code_to_hex(obj.data),\n            \"to\": address_or_none(obj.to),\n            \"accessList\": obj.access_list,\n            \"secretKey\": obj.secret_key,\n            \"maxFeePerDataGas\": hex_or_none(obj.max_fee_per_data_gas),\n            \"sender\": address_or_none(obj.sender),\n        }\n\n        if obj.blob_versioned_hashes is not None:\n            tx[\"blobVersionedHashes\"] = [hash_string(h) for h in obj.blob_versioned_hashes]\n\n        if obj.secret_key is None:\n            assert obj.signature is not None\n            assert len(obj.signature) == 3\n            tx[\"v\"] = hex(obj.signature[0])\n            tx[\"r\"] = hex(obj.signature[1])\n            tx[\"s\"] = hex(obj.signature[2])\n        else:\n            tx[\"v\"] = \"\"\n            tx[\"r\"] = \"\"\n            tx[\"s\"] = \"\"\n\n        return {k: v for (k, v) in tx.items() if v is not None}\n    elif isinstance(obj, Withdrawal):\n        withdrawal = {\n            \"index\": hex(obj.index),\n            \"validatorIndex\": hex(obj.validator),\n            \"address\": obj.address,\n            \"amount\": hex(obj.amount),\n        }\n        return withdrawal\n    elif isinstance(obj, Environment):\n        env: Dict[str, Any] = {\n            \"currentCoinbase\": address_or_none(obj.coinbase, \"0x\" + ZeroAddress.hex()),\n            \"currentGasLimit\": str_or_none(obj.gas_limit),\n            \"currentNumber\": str_or_none(obj.number),\n            \"currentTimestamp\": str_or_none(obj.timestamp),\n            \"currentRandom\": str_or_none(obj.prev_randao),\n            \"currentDifficulty\": str_or_none(obj.difficulty),\n            \"parentDifficulty\": str_or_none(obj.parent_difficulty),\n            \"parentBaseFee\": str_or_none(obj.parent_base_fee),\n            \"parentGasUsed\": str_or_none(obj.parent_gas_used),\n            \"parentGasLimit\": str_or_none(obj.parent_gas_limit),\n            \"parentTimestamp\": str_or_none(obj.parent_timestamp),\n            \"blockHashes\": {str(k): hex_or_none(v) for (k, v) in obj.block_hashes.items()},\n            \"ommers\": [],\n            \"withdrawals\": to_json_or_none(obj.withdrawals),\n            \"parentUncleHash\": hash_string(obj.parent_ommers_hash),\n            \"currentBaseFee\": str_or_none(obj.base_fee),\n            \"parentDataGasUsed\": str_or_none(obj.parent_data_gas_used),\n            \"parentExcessDataGas\": str_or_none(obj.parent_excess_data_gas),\n            \"currentExcessDataGas\": str_or_none(obj.excess_data_gas),\n            \"currentDataGasUsed\": str_or_none(obj.data_gas_used),\n        }\n\n        return {k: v for (k, v) in env.items() if v is not None}\n    elif isinstance(obj, FixtureHeader):\n        header = {\n            \"parentHash\": hex_or_none(obj.parent_hash),\n            \"uncleHash\": hex_or_none(obj.ommers_hash),\n            \"coinbase\": hex_or_none(obj.coinbase),\n            \"stateRoot\": hex_or_none(obj.state_root),\n            \"transactionsTrie\": hex_or_none(obj.transactions_root),\n            \"receiptTrie\": hex_or_none(obj.receipt_root),\n            \"bloom\": hex_or_none(obj.bloom),\n            \"difficulty\": hex(obj.difficulty),\n            \"number\": hex(obj.number),\n            \"gasLimit\": hex(obj.gas_limit),\n            \"gasUsed\": hex(obj.gas_used),\n            \"timestamp\": hex(obj.timestamp),\n            \"extraData\": hex_or_none(obj.extra_data),\n            \"mixHash\": hex_or_none(obj.mix_digest),\n            \"nonce\": hex_or_none(obj.nonce),\n        }\n        if obj.base_fee is not None:\n            header[\"baseFeePerGas\"] = hex(obj.base_fee)\n        if obj.hash is not None:\n            header[\"hash\"] = \"0x\" + obj.hash.hex()\n        if obj.withdrawals_root is not None:\n            header[\"withdrawalsRoot\"] = hex_or_none(obj.withdrawals_root)\n        if obj.data_gas_used is not None:\n            header[\"dataGasUsed\"] = hex(obj.data_gas_used)\n        if obj.excess_data_gas is not None:\n            header[\"excessDataGas\"] = hex(obj.excess_data_gas)\n        return even_padding(\n            header,\n            excluded=[\n                \"parentHash\",\n                \"uncleHash\",\n                \"stateRoot\",\n                \"coinbase\",\n                \"transactionsTrie\",\n                \"receiptTrie\",\n                \"bloom\",\n                \"nonce\",\n                \"mixHash\",\n                \"hash\",\n                \"withdrawalsRoot\",\n                \"extraData\",\n            ],\n        )\n    elif isinstance(obj, FixtureTransaction):\n        json_tx = to_json(obj.tx)\n        if json_tx[\"v\"] == \"\":\n            del json_tx[\"v\"]\n            del json_tx[\"r\"]\n            del json_tx[\"s\"]\n        if \"input\" in json_tx:\n            json_tx[\"data\"] = json_tx[\"input\"]\n            del json_tx[\"input\"]\n        if \"gas\" in json_tx:\n            json_tx[\"gasLimit\"] = json_tx[\"gas\"]\n            del json_tx[\"gas\"]\n        if \"to\" not in json_tx:\n            json_tx[\"to\"] = \"\"\n        return even_padding(\n            json_tx,\n            excluded=[\"data\", \"to\", \"accessList\"],\n        )\n    elif isinstance(obj, FixtureExecutionPayload):\n        payload: Dict[str, Any] = {\n            \"parentHash\": hex_or_none(obj.header.parent_hash),\n            \"feeRecipient\": hex_or_none(obj.header.coinbase),\n            \"stateRoot\": hex_or_none(obj.header.state_root),\n            \"receiptsRoot\": hex_or_none(obj.header.receipt_root),\n            \"logsBloom\": hex_or_none(obj.header.bloom),\n            \"prevRandao\": hex_or_none(obj.header.mix_digest),\n            \"blockNumber\": hex(obj.header.number),\n            \"gasLimit\": hex(obj.header.gas_limit),\n            \"gasUsed\": hex(obj.header.gas_used),\n            \"timestamp\": hex(obj.header.timestamp),\n            \"extraData\": hex_or_none(obj.header.extra_data),\n        }\n        if obj.header.base_fee is not None:\n            payload[\"baseFeePerGas\"] = hex(obj.header.base_fee)\n        if obj.header.hash is not None:\n            payload[\"blockHash\"] = \"0x\" + obj.header.hash.hex()\n\n        if obj.transactions is not None:\n            payload[\"transactions\"] = [\n                hex_or_none(tx.serialized_bytes()) for tx in obj.transactions\n            ]\n        if obj.withdrawals is not None:\n            payload[\"withdrawals\"] = obj.withdrawals\n\n        if obj.header.data_gas_used is not None:\n            payload[\"dataGasUsed\"] = hex(obj.header.data_gas_used)\n        if obj.header.excess_data_gas is not None:\n            payload[\"excessDataGas\"] = hex(obj.header.excess_data_gas)\n\n        return payload\n    elif isinstance(obj, FixtureEngineNewPayload):\n        new_payload: Dict[str, Any] = {\n            \"payload\": to_json(obj.payload),\n            \"version\": str_or_none(obj.version),\n        }\n        if obj.blob_versioned_hashes is not None:\n            new_payload[\"blobVersionedHashes\"] = [\n                \"0x\" + hash_to_bytes(h).hex() for h in obj.blob_versioned_hashes\n            ]\n        if obj.error_code is not None:\n            new_payload[\"errorCode\"] = str(int(obj.error_code))\n        return new_payload\n\n    elif isinstance(obj, FixtureBlock):\n        b: Dict[str, Any] = {\"rlp\": hex_or_none(obj.rlp)}\n        if obj.block_header is not None:\n            b[\"blockHeader\"] = json.loads(json.dumps(obj.block_header, cls=JSONEncoder))\n        if obj.new_payload is not None:\n            b[\"engineNewPayload\"] = to_json_or_none(obj.new_payload)\n        if obj.expected_exception is not None:\n            b[\"expectException\"] = obj.expected_exception\n        if obj.block_number is not None:\n            b[\"blocknumber\"] = str(obj.block_number)\n        if obj.txs is not None:\n            b[\"transactions\"] = [FixtureTransaction(tx=tx) for tx in obj.txs]\n        if obj.ommers is not None:\n            b[\"uncleHeaders\"] = obj.ommers\n        if obj.withdrawals is not None:\n            b[\"withdrawals\"] = [\n                even_padding(to_json(wd), excluded=[\"address\"]) for wd in obj.withdrawals\n            ]\n        return b\n\n    elif isinstance(obj, Fixture):\n        if obj._json is not None:\n            obj._json[\"_info\"] = obj.info\n            return obj._json\n\n        f = {\n            \"_info\": obj.info,\n            \"blocks\": [json.loads(json.dumps(b, cls=JSONEncoder)) for b in obj.blocks],\n            \"genesisBlockHeader\": self.default(obj.genesis),\n            \"genesisRLP\": hex_or_none(obj.genesis_rlp),\n            \"lastblockhash\": hex_or_none(obj.head),\n            \"network\": obj.fork,\n            \"pre\": json.loads(json.dumps(obj.pre_state, cls=JSONEncoder)),\n            \"postState\": json.loads(json.dumps(obj.post_state, cls=JSONEncoder)),\n            \"sealEngine\": obj.seal_engine,\n        }\n        if f[\"postState\"] is None:\n            del f[\"postState\"]\n        return f\n    else:\n        return super().default(obj)\n
"},{"location":"library/evm_transition_tool/","title":"EVM Transition Tool Package","text":"

Library of Python wrappers for the different implementations of transition tools.

"},{"location":"library/evm_transition_tool/#evm_transition_tool.UnknownTransitionTool","title":"UnknownTransitionTool","text":"

Bases: Exception

Exception raised if an unknown t8n is encountered

Source code in src/evm_transition_tool/transition_tool.py
class UnknownTransitionTool(Exception):\n\"\"\"Exception raised if an unknown t8n is encountered\"\"\"\n\n    pass\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.GethTransitionTool","title":"GethTransitionTool","text":"

Bases: TransitionTool

Go-ethereum evm Transition tool frontend wrapper class.

Source code in src/evm_transition_tool/geth.py
class GethTransitionTool(TransitionTool):\n\"\"\"\n    Go-ethereum `evm` Transition tool frontend wrapper class.\n    \"\"\"\n\n    default_binary = Path(\"evm\")\n    detect_binary_pattern = compile(r\"^evm version\\b\")\n\n    binary: Path\n    cached_version: Optional[str] = None\n    trace: bool\n\n    def __init__(\n        self,\n        *,\n        binary: Optional[Path] = None,\n        trace: bool = False,\n    ):\n        super().__init__(binary=binary, trace=trace)\n        args = [str(self.binary), \"t8n\", \"--help\"]\n        try:\n            result = subprocess.run(args, capture_output=True, text=True)\n        except subprocess.CalledProcessError as e:\n            raise Exception(\"evm process unexpectedly returned a non-zero status code: \" f\"{e}.\")\n        except Exception as e:\n            raise Exception(f\"Unexpected exception calling evm tool: {e}.\")\n        self.help_string = result.stdout\n\n    def evaluate(\n        self,\n        alloc: Any,\n        txs: Any,\n        env: Any,\n        fork: Fork,\n        chain_id: int = 1,\n        reward: int = 0,\n        eips: Optional[List[int]] = None,\n    ) -> Tuple[Dict[str, Any], Dict[str, Any]]:\n\"\"\"\n        Executes `evm t8n` with the specified arguments.\n        \"\"\"\n        fork_name = fork.name()\n        if eips is not None:\n            fork_name = \"+\".join([fork_name] + [str(eip) for eip in eips])\n\n        temp_dir = tempfile.TemporaryDirectory()\n\n        if int(env[\"currentNumber\"], 0) == 0:\n            reward = -1\n        args = [\n            str(self.binary),\n            \"t8n\",\n            \"--input.alloc=stdin\",\n            \"--input.txs=stdin\",\n            \"--input.env=stdin\",\n            \"--output.result=stdout\",\n            \"--output.alloc=stdout\",\n            \"--output.body=txs.rlp\",\n            f\"--output.basedir={temp_dir.name}\",\n            f\"--state.fork={fork_name}\",\n            f\"--state.chainid={chain_id}\",\n            f\"--state.reward={reward}\",\n        ]\n\n        if self.trace:\n            args.append(\"--trace\")\n\n        stdin = {\n            \"alloc\": alloc,\n            \"txs\": txs,\n            \"env\": env,\n        }\n\n        encoded_input = str.encode(json.dumps(stdin))\n        result = subprocess.run(\n            args,\n            input=encoded_input,\n            stdout=subprocess.PIPE,\n            stderr=subprocess.PIPE,\n        )\n\n        if result.returncode != 0:\n            raise Exception(\"failed to evaluate: \" + result.stderr.decode())\n\n        output = json.loads(result.stdout)\n\n        if \"alloc\" not in output or \"result\" not in output:\n            raise Exception(\"malformed result\")\n\n        if self.trace:\n            receipts: List[Any] = output[\"result\"][\"receipts\"]\n            traces: List[List[Dict]] = []\n            for i, r in enumerate(receipts):\n                h = r[\"transactionHash\"]\n                trace_file_name = f\"trace-{i}-{h}.jsonl\"\n                with open(os.path.join(temp_dir.name, trace_file_name), \"r\") as trace_file:\n                    tx_traces: List[Dict] = []\n                    for trace_line in trace_file.readlines():\n                        tx_traces.append(json.loads(trace_line))\n                    traces.append(tx_traces)\n            self.append_traces(traces)\n\n        temp_dir.cleanup()\n\n        return output[\"alloc\"], output[\"result\"]\n\n    def version(self) -> str:\n\"\"\"\n        Gets `evm` binary version.\n        \"\"\"\n        if self.cached_version is None:\n            result = subprocess.run(\n                [str(self.binary), \"-v\"],\n                stdout=subprocess.PIPE,\n            )\n\n            if result.returncode != 0:\n                raise Exception(\"failed to evaluate: \" + result.stderr.decode())\n\n            self.cached_version = result.stdout.decode().strip()\n\n        return self.cached_version\n\n    def is_fork_supported(self, fork: Fork) -> bool:\n\"\"\"\n        Returns True if the fork is supported by the tool\n        \"\"\"\n        return fork().name() in self.help_string\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.geth.GethTransitionTool.evaluate","title":"evaluate(alloc, txs, env, fork, chain_id=1, reward=0, eips=None)","text":"

Executes evm t8n with the specified arguments.

Source code in src/evm_transition_tool/geth.py
def evaluate(\n    self,\n    alloc: Any,\n    txs: Any,\n    env: Any,\n    fork: Fork,\n    chain_id: int = 1,\n    reward: int = 0,\n    eips: Optional[List[int]] = None,\n) -> Tuple[Dict[str, Any], Dict[str, Any]]:\n\"\"\"\n    Executes `evm t8n` with the specified arguments.\n    \"\"\"\n    fork_name = fork.name()\n    if eips is not None:\n        fork_name = \"+\".join([fork_name] + [str(eip) for eip in eips])\n\n    temp_dir = tempfile.TemporaryDirectory()\n\n    if int(env[\"currentNumber\"], 0) == 0:\n        reward = -1\n    args = [\n        str(self.binary),\n        \"t8n\",\n        \"--input.alloc=stdin\",\n        \"--input.txs=stdin\",\n        \"--input.env=stdin\",\n        \"--output.result=stdout\",\n        \"--output.alloc=stdout\",\n        \"--output.body=txs.rlp\",\n        f\"--output.basedir={temp_dir.name}\",\n        f\"--state.fork={fork_name}\",\n        f\"--state.chainid={chain_id}\",\n        f\"--state.reward={reward}\",\n    ]\n\n    if self.trace:\n        args.append(\"--trace\")\n\n    stdin = {\n        \"alloc\": alloc,\n        \"txs\": txs,\n        \"env\": env,\n    }\n\n    encoded_input = str.encode(json.dumps(stdin))\n    result = subprocess.run(\n        args,\n        input=encoded_input,\n        stdout=subprocess.PIPE,\n        stderr=subprocess.PIPE,\n    )\n\n    if result.returncode != 0:\n        raise Exception(\"failed to evaluate: \" + result.stderr.decode())\n\n    output = json.loads(result.stdout)\n\n    if \"alloc\" not in output or \"result\" not in output:\n        raise Exception(\"malformed result\")\n\n    if self.trace:\n        receipts: List[Any] = output[\"result\"][\"receipts\"]\n        traces: List[List[Dict]] = []\n        for i, r in enumerate(receipts):\n            h = r[\"transactionHash\"]\n            trace_file_name = f\"trace-{i}-{h}.jsonl\"\n            with open(os.path.join(temp_dir.name, trace_file_name), \"r\") as trace_file:\n                tx_traces: List[Dict] = []\n                for trace_line in trace_file.readlines():\n                    tx_traces.append(json.loads(trace_line))\n                traces.append(tx_traces)\n        self.append_traces(traces)\n\n    temp_dir.cleanup()\n\n    return output[\"alloc\"], output[\"result\"]\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.geth.GethTransitionTool.version","title":"version()","text":"

Gets evm binary version.

Source code in src/evm_transition_tool/geth.py
def version(self) -> str:\n\"\"\"\n    Gets `evm` binary version.\n    \"\"\"\n    if self.cached_version is None:\n        result = subprocess.run(\n            [str(self.binary), \"-v\"],\n            stdout=subprocess.PIPE,\n        )\n\n        if result.returncode != 0:\n            raise Exception(\"failed to evaluate: \" + result.stderr.decode())\n\n        self.cached_version = result.stdout.decode().strip()\n\n    return self.cached_version\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.geth.GethTransitionTool.is_fork_supported","title":"is_fork_supported(fork)","text":"

Returns True if the fork is supported by the tool

Source code in src/evm_transition_tool/geth.py
def is_fork_supported(self, fork: Fork) -> bool:\n\"\"\"\n    Returns True if the fork is supported by the tool\n    \"\"\"\n    return fork().name() in self.help_string\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.TransitionToolNotFoundInPath","title":"TransitionToolNotFoundInPath","text":"

Bases: Exception

Exception raised if the specified t8n tool is not found in the path

Source code in src/evm_transition_tool/transition_tool.py
class TransitionToolNotFoundInPath(Exception):\n\"\"\"Exception raised if the specified t8n tool is not found in the path\"\"\"\n\n    def __init__(self, message=\"The transition tool was not found in the path\", binary=None):\n        if binary:\n            message = f\"{message} ({binary})\"\n        super().__init__(message)\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.EvmOneTransitionTool","title":"EvmOneTransitionTool","text":"

Bases: TransitionTool

Evmone evmone-t8n Transition tool frontend wrapper class.

Source code in src/evm_transition_tool/evmone.py
class EvmOneTransitionTool(TransitionTool):\n\"\"\"\n    Evmone `evmone-t8n` Transition tool frontend wrapper class.\n    \"\"\"\n\n    default_binary = Path(\"evmone-t8n\")\n    detect_binary_pattern = compile(r\"^evmone-t8n\\b\")\n\n    binary: Path\n    cached_version: Optional[str] = None\n    trace: bool\n\n    def __init__(\n        self,\n        *,\n        binary: Optional[Path] = None,\n        trace: bool = False,\n    ):\n        super().__init__(binary=binary, trace=trace)\n        if self.trace:\n            raise Exception(\"`evmone-t8n` does not support tracing.\")\n\n    def evaluate(\n        self,\n        alloc: Any,\n        txs: Any,\n        env: Any,\n        fork: Fork,\n        chain_id: int = 1,\n        reward: int = 0,\n        eips: Optional[List[int]] = None,\n    ) -> Tuple[Dict[str, Any], Dict[str, Any]]:\n\"\"\"\n        Executes `evmone-t8n` with the specified arguments.\n        \"\"\"\n        fork_name = fork.name()\n        if eips is not None:\n            fork_name = \"+\".join([fork_name] + [str(eip) for eip in eips])\n\n        temp_dir = tempfile.TemporaryDirectory()\n\n        input_contents = {\n            \"alloc\": alloc,\n            \"env\": env,\n            \"txs\": txs,\n        }\n        input_paths = {\n            k: os.path.join(temp_dir.name, f\"input_{k}.json\") for k in input_contents.keys()\n        }\n        for key, val in input_contents.items():\n            file_path = os.path.join(temp_dir.name, f\"input_{key}.json\")\n            write_json_file(val, file_path)\n\n        # Construct args for evmone-t8n binary\n        args = [\n            str(self.binary),\n            \"--state.fork\",\n            fork_name,\n            \"--input.alloc\",\n            input_paths[\"alloc\"],\n            \"--input.env\",\n            input_paths[\"env\"],\n            \"--input.txs\",\n            input_paths[\"txs\"],\n            \"--output.basedir\",\n            temp_dir.name,\n            \"--output.result\",\n            \"output_result.json\",\n            \"--output.alloc\",\n            \"output_alloc.json\",\n            \"--output.body\",\n            \"txs.rlp\",\n            \"--state.reward\",\n            str(reward),\n            \"--state.chainid\",\n            str(chain_id),\n        ]\n        result = subprocess.run(\n            args,\n            stdout=subprocess.PIPE,\n            stderr=subprocess.PIPE,\n        )\n\n        if result.returncode != 0:\n            raise Exception(\"failed to evaluate: \" + result.stderr.decode())\n\n        output_paths = {\n            \"alloc\": os.path.join(temp_dir.name, \"output_alloc.json\"),\n            \"result\": os.path.join(temp_dir.name, \"output_result.json\"),\n        }\n\n        output_contents = {}\n        for key, file_path in output_paths.items():\n            with open(file_path, \"r+\") as file:\n                contents = json.load(file)\n                file.seek(0)\n                json.dump(contents, file, ensure_ascii=False, indent=4)\n                file.truncate()\n                output_contents[key] = contents\n\n        temp_dir.cleanup()\n\n        return output_contents[\"alloc\"], output_contents[\"result\"]\n\n    def version(self) -> str:\n\"\"\"\n        Gets `evmone-t8n` binary version.\n        \"\"\"\n        if self.cached_version is None:\n            result = subprocess.run(\n                [str(self.binary), \"-v\"],\n                stdout=subprocess.PIPE,\n            )\n\n            if result.returncode != 0:\n                raise Exception(\"failed to evaluate: \" + result.stderr.decode())\n\n            self.cached_version = result.stdout.decode().strip()\n\n        return self.cached_version\n\n    def is_fork_supported(self, fork: Fork) -> bool:\n\"\"\"\n        Returns True if the fork is supported by the tool.\n        Currently, evmone-t8n provides no way to determine supported forks.\n        \"\"\"\n        return True\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.evmone.EvmOneTransitionTool.evaluate","title":"evaluate(alloc, txs, env, fork, chain_id=1, reward=0, eips=None)","text":"

Executes evmone-t8n with the specified arguments.

Source code in src/evm_transition_tool/evmone.py
def evaluate(\n    self,\n    alloc: Any,\n    txs: Any,\n    env: Any,\n    fork: Fork,\n    chain_id: int = 1,\n    reward: int = 0,\n    eips: Optional[List[int]] = None,\n) -> Tuple[Dict[str, Any], Dict[str, Any]]:\n\"\"\"\n    Executes `evmone-t8n` with the specified arguments.\n    \"\"\"\n    fork_name = fork.name()\n    if eips is not None:\n        fork_name = \"+\".join([fork_name] + [str(eip) for eip in eips])\n\n    temp_dir = tempfile.TemporaryDirectory()\n\n    input_contents = {\n        \"alloc\": alloc,\n        \"env\": env,\n        \"txs\": txs,\n    }\n    input_paths = {\n        k: os.path.join(temp_dir.name, f\"input_{k}.json\") for k in input_contents.keys()\n    }\n    for key, val in input_contents.items():\n        file_path = os.path.join(temp_dir.name, f\"input_{key}.json\")\n        write_json_file(val, file_path)\n\n    # Construct args for evmone-t8n binary\n    args = [\n        str(self.binary),\n        \"--state.fork\",\n        fork_name,\n        \"--input.alloc\",\n        input_paths[\"alloc\"],\n        \"--input.env\",\n        input_paths[\"env\"],\n        \"--input.txs\",\n        input_paths[\"txs\"],\n        \"--output.basedir\",\n        temp_dir.name,\n        \"--output.result\",\n        \"output_result.json\",\n        \"--output.alloc\",\n        \"output_alloc.json\",\n        \"--output.body\",\n        \"txs.rlp\",\n        \"--state.reward\",\n        str(reward),\n        \"--state.chainid\",\n        str(chain_id),\n    ]\n    result = subprocess.run(\n        args,\n        stdout=subprocess.PIPE,\n        stderr=subprocess.PIPE,\n    )\n\n    if result.returncode != 0:\n        raise Exception(\"failed to evaluate: \" + result.stderr.decode())\n\n    output_paths = {\n        \"alloc\": os.path.join(temp_dir.name, \"output_alloc.json\"),\n        \"result\": os.path.join(temp_dir.name, \"output_result.json\"),\n    }\n\n    output_contents = {}\n    for key, file_path in output_paths.items():\n        with open(file_path, \"r+\") as file:\n            contents = json.load(file)\n            file.seek(0)\n            json.dump(contents, file, ensure_ascii=False, indent=4)\n            file.truncate()\n            output_contents[key] = contents\n\n    temp_dir.cleanup()\n\n    return output_contents[\"alloc\"], output_contents[\"result\"]\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.evmone.EvmOneTransitionTool.version","title":"version()","text":"

Gets evmone-t8n binary version.

Source code in src/evm_transition_tool/evmone.py
def version(self) -> str:\n\"\"\"\n    Gets `evmone-t8n` binary version.\n    \"\"\"\n    if self.cached_version is None:\n        result = subprocess.run(\n            [str(self.binary), \"-v\"],\n            stdout=subprocess.PIPE,\n        )\n\n        if result.returncode != 0:\n            raise Exception(\"failed to evaluate: \" + result.stderr.decode())\n\n        self.cached_version = result.stdout.decode().strip()\n\n    return self.cached_version\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.evmone.EvmOneTransitionTool.is_fork_supported","title":"is_fork_supported(fork)","text":"

Returns True if the fork is supported by the tool. Currently, evmone-t8n provides no way to determine supported forks.

Source code in src/evm_transition_tool/evmone.py
def is_fork_supported(self, fork: Fork) -> bool:\n\"\"\"\n    Returns True if the fork is supported by the tool.\n    Currently, evmone-t8n provides no way to determine supported forks.\n    \"\"\"\n    return True\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.TransitionTool","title":"TransitionTool","text":"

Transition tool abstract base class which should be inherited by all transition tool implementations.

Source code in src/evm_transition_tool/transition_tool.py
class TransitionTool:\n\"\"\"\n    Transition tool abstract base class which should be inherited by all transition tool\n    implementations.\n    \"\"\"\n\n    traces: List[List[List[Dict]]] | None = None\n\n    registered_tools: List[Type[\"TransitionTool\"]] = []\n    default_tool: Optional[Type[\"TransitionTool\"]] = None\n    default_binary: Path\n    detect_binary_pattern: Pattern\n    version_flag: str = \"-v\"\n\n    # Abstract methods that each tool must implement\n\n    @abstractmethod\n    def __init__(\n        self,\n        *,\n        binary: Optional[Path] = None,\n        trace: bool = False,\n    ):\n\"\"\"\n        Abstract initialization method that all subclasses must implement.\n        \"\"\"\n        if binary is None:\n            binary = self.default_binary\n        else:\n            # improve behavior of which by resolving the path: ~/relative paths don't work\n            resolved_path = Path(os.path.expanduser(binary)).resolve()\n            if resolved_path.exists():\n                binary = resolved_path\n        binary = shutil.which(binary)  # type: ignore\n        if not binary:\n            raise TransitionToolNotFoundInPath(binary=binary)\n        self.binary = Path(binary)\n        self.trace = trace\n\n    def __init_subclass__(cls):\n\"\"\"\n        Registers all subclasses of TransitionTool as possible tools.\n        \"\"\"\n        TransitionTool.register_tool(cls)\n\n    @classmethod\n    def register_tool(cls, tool_subclass: Type[\"TransitionTool\"]):\n\"\"\"\n        Registers a given subclass as tool option.\n        \"\"\"\n        cls.registered_tools.append(tool_subclass)\n\n    @classmethod\n    def set_default_tool(cls, tool_subclass: Type[\"TransitionTool\"]):\n\"\"\"\n        Registers the default tool subclass.\n        \"\"\"\n        cls.default_tool = tool_subclass\n\n    @classmethod\n    def from_binary_path(cls, *, binary_path: Optional[Path], **kwargs) -> \"TransitionTool\":\n\"\"\"\n        Instantiates the appropriate TransitionTool subclass derived from the\n        tool's binary path.\n        \"\"\"\n        assert cls.default_tool is not None, \"default transition tool was never set\"\n\n        if binary_path is None:\n            return cls.default_tool(binary=binary_path, **kwargs)\n\n        resolved_path = Path(os.path.expanduser(binary_path)).resolve()\n        if resolved_path.exists():\n            binary_path = resolved_path\n        binary = shutil.which(binary_path)  # type: ignore\n\n        if not binary:\n            raise TransitionToolNotFoundInPath(binary=binary)\n\n        binary = Path(binary)\n\n        # Group the tools by version flag, so we only have to call the tool once for all the\n        # classes that share the same version flag\n        for version_flag, subclasses in groupby(\n            cls.registered_tools, key=lambda x: x.version_flag\n        ):\n            try:\n                with os.popen(f\"{binary} {version_flag}\") as f:\n                    binary_output = f.read()\n            except Exception:\n                # If the tool doesn't support the version flag,\n                # we'll get an non-zero exit code.\n                continue\n            for subclass in subclasses:\n                if subclass.detect_binary(binary_output):\n                    return subclass(binary=binary, **kwargs)\n\n        raise UnknownTransitionTool(f\"Unknown transition tool binary: {binary_path}\")\n\n    @classmethod\n    def detect_binary(cls, binary_output: str) -> bool:\n\"\"\"\n        Returns True if the binary matches the tool\n        \"\"\"\n        assert cls.detect_binary_pattern is not None\n\n        return cls.detect_binary_pattern.match(binary_output) is not None\n\n    @abstractmethod\n    def evaluate(\n        self,\n        alloc: Any,\n        txs: Any,\n        env: Any,\n        fork: Fork,\n        chain_id: int = 1,\n        reward: int = 0,\n        eips: Optional[List[int]] = None,\n    ) -> Tuple[Dict[str, Any], Dict[str, Any]]:\n\"\"\"\n        Simulate a state transition with specified parameters\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def version(self) -> str:\n\"\"\"\n        Return name and version of tool used to state transition\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def is_fork_supported(self, fork: Fork) -> bool:\n\"\"\"\n        Returns True if the fork is supported by the tool\n        \"\"\"\n        pass\n\n    def reset_traces(self):\n\"\"\"\n        Resets the internal trace storage for a new test to begin\n        \"\"\"\n        self.traces = None\n\n    def append_traces(self, new_traces: List[List[Dict]]):\n\"\"\"\n        Appends a list of traces of a state transition to the current list\n        \"\"\"\n        if self.traces is None:\n            self.traces = []\n        self.traces.append(new_traces)\n\n    def get_traces(self) -> List[List[List[Dict]]] | None:\n\"\"\"\n        Returns the accumulated traces\n        \"\"\"\n        return self.traces\n\n    def calc_state_root(self, alloc: Any, fork: Fork) -> bytes:\n\"\"\"\n        Calculate the state root for the given `alloc`.\n        \"\"\"\n        env: Dict[str, Any] = {\n            \"currentCoinbase\": \"0x0000000000000000000000000000000000000000\",\n            \"currentDifficulty\": \"0x0\",\n            \"currentGasLimit\": \"0x0\",\n            \"currentNumber\": \"0\",\n            \"currentTimestamp\": \"0\",\n        }\n\n        if fork.header_base_fee_required(0, 0):\n            env[\"currentBaseFee\"] = \"7\"\n\n        if fork.header_prev_randao_required(0, 0):\n            env[\"currentRandom\"] = \"0\"\n\n        if fork.header_withdrawals_required(0, 0):\n            env[\"withdrawals\"] = []\n\n        _, result = self.evaluate(alloc, [], env, fork)\n        state_root = result.get(\"stateRoot\")\n        if state_root is None or not isinstance(state_root, str):\n            raise Exception(\"Unable to calculate state root\")\n        return bytes.fromhex(state_root[2:])\n\n    def calc_withdrawals_root(self, withdrawals: Any, fork: Fork) -> bytes:\n\"\"\"\n        Calculate the state root for the given `alloc`.\n        \"\"\"\n        if type(withdrawals) is list and len(withdrawals) == 0:\n            # Optimize returning the empty root immediately\n            return bytes.fromhex(\n                \"56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\"\n            )\n\n        env: Dict[str, Any] = {\n            \"currentCoinbase\": \"0x0000000000000000000000000000000000000000\",\n            \"currentDifficulty\": \"0x0\",\n            \"currentGasLimit\": \"0x0\",\n            \"currentNumber\": \"0\",\n            \"currentTimestamp\": \"0\",\n            \"withdrawals\": withdrawals,\n        }\n\n        if fork.header_base_fee_required(0, 0):\n            env[\"currentBaseFee\"] = \"7\"\n\n        if fork.header_prev_randao_required(0, 0):\n            env[\"currentRandom\"] = \"0\"\n\n        if fork.header_excess_data_gas_required(0, 0):\n            env[\"currentExcessDataGas\"] = \"0\"\n\n        _, result = self.evaluate({}, [], env, fork)\n        withdrawals_root = result.get(\"withdrawalsRoot\")\n        if withdrawals_root is None:\n            raise Exception(\n                \"Unable to calculate withdrawals root: no value returned from transition tool\"\n            )\n        if type(withdrawals_root) is not str:\n            raise Exception(\n                \"Unable to calculate withdrawals root: \"\n                + \"incorrect type returned from transition tool: \"\n                + f\"{withdrawals_root}\"\n            )\n        return bytes.fromhex(withdrawals_root[2:])\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.transition_tool.TransitionTool.__init__","title":"__init__(*, binary=None, trace=False) abstractmethod","text":"

Abstract initialization method that all subclasses must implement.

Source code in src/evm_transition_tool/transition_tool.py
@abstractmethod\ndef __init__(\n    self,\n    *,\n    binary: Optional[Path] = None,\n    trace: bool = False,\n):\n\"\"\"\n    Abstract initialization method that all subclasses must implement.\n    \"\"\"\n    if binary is None:\n        binary = self.default_binary\n    else:\n        # improve behavior of which by resolving the path: ~/relative paths don't work\n        resolved_path = Path(os.path.expanduser(binary)).resolve()\n        if resolved_path.exists():\n            binary = resolved_path\n    binary = shutil.which(binary)  # type: ignore\n    if not binary:\n        raise TransitionToolNotFoundInPath(binary=binary)\n    self.binary = Path(binary)\n    self.trace = trace\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.transition_tool.TransitionTool.__init_subclass__","title":"__init_subclass__()","text":"

Registers all subclasses of TransitionTool as possible tools.

Source code in src/evm_transition_tool/transition_tool.py
def __init_subclass__(cls):\n\"\"\"\n    Registers all subclasses of TransitionTool as possible tools.\n    \"\"\"\n    TransitionTool.register_tool(cls)\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.transition_tool.TransitionTool.register_tool","title":"register_tool(tool_subclass) classmethod","text":"

Registers a given subclass as tool option.

Source code in src/evm_transition_tool/transition_tool.py
@classmethod\ndef register_tool(cls, tool_subclass: Type[\"TransitionTool\"]):\n\"\"\"\n    Registers a given subclass as tool option.\n    \"\"\"\n    cls.registered_tools.append(tool_subclass)\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.transition_tool.TransitionTool.set_default_tool","title":"set_default_tool(tool_subclass) classmethod","text":"

Registers the default tool subclass.

Source code in src/evm_transition_tool/transition_tool.py
@classmethod\ndef set_default_tool(cls, tool_subclass: Type[\"TransitionTool\"]):\n\"\"\"\n    Registers the default tool subclass.\n    \"\"\"\n    cls.default_tool = tool_subclass\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.transition_tool.TransitionTool.from_binary_path","title":"from_binary_path(*, binary_path, **kwargs) classmethod","text":"

Instantiates the appropriate TransitionTool subclass derived from the tool's binary path.

Source code in src/evm_transition_tool/transition_tool.py
@classmethod\ndef from_binary_path(cls, *, binary_path: Optional[Path], **kwargs) -> \"TransitionTool\":\n\"\"\"\n    Instantiates the appropriate TransitionTool subclass derived from the\n    tool's binary path.\n    \"\"\"\n    assert cls.default_tool is not None, \"default transition tool was never set\"\n\n    if binary_path is None:\n        return cls.default_tool(binary=binary_path, **kwargs)\n\n    resolved_path = Path(os.path.expanduser(binary_path)).resolve()\n    if resolved_path.exists():\n        binary_path = resolved_path\n    binary = shutil.which(binary_path)  # type: ignore\n\n    if not binary:\n        raise TransitionToolNotFoundInPath(binary=binary)\n\n    binary = Path(binary)\n\n    # Group the tools by version flag, so we only have to call the tool once for all the\n    # classes that share the same version flag\n    for version_flag, subclasses in groupby(\n        cls.registered_tools, key=lambda x: x.version_flag\n    ):\n        try:\n            with os.popen(f\"{binary} {version_flag}\") as f:\n                binary_output = f.read()\n        except Exception:\n            # If the tool doesn't support the version flag,\n            # we'll get an non-zero exit code.\n            continue\n        for subclass in subclasses:\n            if subclass.detect_binary(binary_output):\n                return subclass(binary=binary, **kwargs)\n\n    raise UnknownTransitionTool(f\"Unknown transition tool binary: {binary_path}\")\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.transition_tool.TransitionTool.detect_binary","title":"detect_binary(binary_output) classmethod","text":"

Returns True if the binary matches the tool

Source code in src/evm_transition_tool/transition_tool.py
@classmethod\ndef detect_binary(cls, binary_output: str) -> bool:\n\"\"\"\n    Returns True if the binary matches the tool\n    \"\"\"\n    assert cls.detect_binary_pattern is not None\n\n    return cls.detect_binary_pattern.match(binary_output) is not None\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.transition_tool.TransitionTool.evaluate","title":"evaluate(alloc, txs, env, fork, chain_id=1, reward=0, eips=None) abstractmethod","text":"

Simulate a state transition with specified parameters

Source code in src/evm_transition_tool/transition_tool.py
@abstractmethod\ndef evaluate(\n    self,\n    alloc: Any,\n    txs: Any,\n    env: Any,\n    fork: Fork,\n    chain_id: int = 1,\n    reward: int = 0,\n    eips: Optional[List[int]] = None,\n) -> Tuple[Dict[str, Any], Dict[str, Any]]:\n\"\"\"\n    Simulate a state transition with specified parameters\n    \"\"\"\n    pass\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.transition_tool.TransitionTool.version","title":"version() abstractmethod","text":"

Return name and version of tool used to state transition

Source code in src/evm_transition_tool/transition_tool.py
@abstractmethod\ndef version(self) -> str:\n\"\"\"\n    Return name and version of tool used to state transition\n    \"\"\"\n    pass\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.transition_tool.TransitionTool.is_fork_supported","title":"is_fork_supported(fork) abstractmethod","text":"

Returns True if the fork is supported by the tool

Source code in src/evm_transition_tool/transition_tool.py
@abstractmethod\ndef is_fork_supported(self, fork: Fork) -> bool:\n\"\"\"\n    Returns True if the fork is supported by the tool\n    \"\"\"\n    pass\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.transition_tool.TransitionTool.reset_traces","title":"reset_traces()","text":"

Resets the internal trace storage for a new test to begin

Source code in src/evm_transition_tool/transition_tool.py
def reset_traces(self):\n\"\"\"\n    Resets the internal trace storage for a new test to begin\n    \"\"\"\n    self.traces = None\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.transition_tool.TransitionTool.append_traces","title":"append_traces(new_traces)","text":"

Appends a list of traces of a state transition to the current list

Source code in src/evm_transition_tool/transition_tool.py
def append_traces(self, new_traces: List[List[Dict]]):\n\"\"\"\n    Appends a list of traces of a state transition to the current list\n    \"\"\"\n    if self.traces is None:\n        self.traces = []\n    self.traces.append(new_traces)\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.transition_tool.TransitionTool.get_traces","title":"get_traces()","text":"

Returns the accumulated traces

Source code in src/evm_transition_tool/transition_tool.py
def get_traces(self) -> List[List[List[Dict]]] | None:\n\"\"\"\n    Returns the accumulated traces\n    \"\"\"\n    return self.traces\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.transition_tool.TransitionTool.calc_state_root","title":"calc_state_root(alloc, fork)","text":"

Calculate the state root for the given alloc.

Source code in src/evm_transition_tool/transition_tool.py
def calc_state_root(self, alloc: Any, fork: Fork) -> bytes:\n\"\"\"\n    Calculate the state root for the given `alloc`.\n    \"\"\"\n    env: Dict[str, Any] = {\n        \"currentCoinbase\": \"0x0000000000000000000000000000000000000000\",\n        \"currentDifficulty\": \"0x0\",\n        \"currentGasLimit\": \"0x0\",\n        \"currentNumber\": \"0\",\n        \"currentTimestamp\": \"0\",\n    }\n\n    if fork.header_base_fee_required(0, 0):\n        env[\"currentBaseFee\"] = \"7\"\n\n    if fork.header_prev_randao_required(0, 0):\n        env[\"currentRandom\"] = \"0\"\n\n    if fork.header_withdrawals_required(0, 0):\n        env[\"withdrawals\"] = []\n\n    _, result = self.evaluate(alloc, [], env, fork)\n    state_root = result.get(\"stateRoot\")\n    if state_root is None or not isinstance(state_root, str):\n        raise Exception(\"Unable to calculate state root\")\n    return bytes.fromhex(state_root[2:])\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.transition_tool.TransitionTool.calc_withdrawals_root","title":"calc_withdrawals_root(withdrawals, fork)","text":"

Calculate the state root for the given alloc.

Source code in src/evm_transition_tool/transition_tool.py
def calc_withdrawals_root(self, withdrawals: Any, fork: Fork) -> bytes:\n\"\"\"\n    Calculate the state root for the given `alloc`.\n    \"\"\"\n    if type(withdrawals) is list and len(withdrawals) == 0:\n        # Optimize returning the empty root immediately\n        return bytes.fromhex(\n            \"56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\"\n        )\n\n    env: Dict[str, Any] = {\n        \"currentCoinbase\": \"0x0000000000000000000000000000000000000000\",\n        \"currentDifficulty\": \"0x0\",\n        \"currentGasLimit\": \"0x0\",\n        \"currentNumber\": \"0\",\n        \"currentTimestamp\": \"0\",\n        \"withdrawals\": withdrawals,\n    }\n\n    if fork.header_base_fee_required(0, 0):\n        env[\"currentBaseFee\"] = \"7\"\n\n    if fork.header_prev_randao_required(0, 0):\n        env[\"currentRandom\"] = \"0\"\n\n    if fork.header_excess_data_gas_required(0, 0):\n        env[\"currentExcessDataGas\"] = \"0\"\n\n    _, result = self.evaluate({}, [], env, fork)\n    withdrawals_root = result.get(\"withdrawalsRoot\")\n    if withdrawals_root is None:\n        raise Exception(\n            \"Unable to calculate withdrawals root: no value returned from transition tool\"\n        )\n    if type(withdrawals_root) is not str:\n        raise Exception(\n            \"Unable to calculate withdrawals root: \"\n            + \"incorrect type returned from transition tool: \"\n            + f\"{withdrawals_root}\"\n        )\n    return bytes.fromhex(withdrawals_root[2:])\n
"},{"location":"library/pytest_plugins/","title":"Overview","text":""},{"location":"library/pytest_plugins/#pytest-framework-and-customizations","title":"Pytest Framework and Customizations","text":"

Package containing pytest plugins related to test filling.

"},{"location":"library/pytest_plugins/forks/","title":"Forks Plugin","text":"

A pytest plugin to configure the forks in the test session. It parametrizes tests based on the user-provided fork range the tests' specified validity markers.

Pytest plugin to enable fork range configuration for the test session.

"},{"location":"library/pytest_plugins/forks/#pytest_plugins.forks.forks.pytest_addoption","title":"pytest_addoption(parser)","text":"

Adds command-line options to pytest.

Source code in src/pytest_plugins/forks/forks.py
def pytest_addoption(parser):\n\"\"\"\n    Adds command-line options to pytest.\n    \"\"\"\n    fork_group = parser.getgroup(\"Forks\", \"Specify the fork range to generate fixtures for\")\n    fork_group.addoption(\n        \"--forks\",\n        action=\"store_true\",\n        dest=\"show_fork_help\",\n        default=False,\n        help=\"Display forks supported by the test framework and exit.\",\n    )\n    fork_group.addoption(\n        \"--fork\",\n        action=\"store\",\n        dest=\"single_fork\",\n        default=None,\n        help=\"Only fill tests for the specified fork.\",\n    )\n    fork_group.addoption(\n        \"--from\",\n        action=\"store\",\n        dest=\"forks_from\",\n        default=None,\n        help=\"Fill tests from and including the specified fork.\",\n    )\n    fork_group.addoption(\n        \"--until\",\n        action=\"store\",\n        dest=\"forks_until\",\n        default=None,\n        help=\"Fill tests until and including the specified fork.\",\n    )\n
"},{"location":"library/pytest_plugins/forks/#pytest_plugins.forks.forks.get_forks","title":"get_forks()","text":"

Returns a list of all the fork classes implemented by ethereum_test_forks ordered chronologically by deployment.

Source code in src/ethereum_test_forks/helpers.py
def get_forks() -> List[Fork]:\n\"\"\"\n    Returns a list of all the fork classes implemented by\n    `ethereum_test_forks` ordered chronologically by deployment.\n    \"\"\"\n    all_forks: List[Fork] = []\n    for fork_name in forks.__dict__:\n        fork = forks.__dict__[fork_name]\n        if not isinstance(fork, type):\n            continue\n        if issubclass(fork, BaseFork) and fork is not BaseFork:\n            all_forks.append(fork)\n    return all_forks\n
"},{"location":"library/pytest_plugins/forks/#pytest_plugins.forks.forks.TransitionTool","title":"TransitionTool","text":"

Transition tool abstract base class which should be inherited by all transition tool implementations.

Source code in src/evm_transition_tool/transition_tool.py
class TransitionTool:\n\"\"\"\n    Transition tool abstract base class which should be inherited by all transition tool\n    implementations.\n    \"\"\"\n\n    traces: List[List[List[Dict]]] | None = None\n\n    registered_tools: List[Type[\"TransitionTool\"]] = []\n    default_tool: Optional[Type[\"TransitionTool\"]] = None\n    default_binary: Path\n    detect_binary_pattern: Pattern\n    version_flag: str = \"-v\"\n\n    # Abstract methods that each tool must implement\n\n    @abstractmethod\n    def __init__(\n        self,\n        *,\n        binary: Optional[Path] = None,\n        trace: bool = False,\n    ):\n\"\"\"\n        Abstract initialization method that all subclasses must implement.\n        \"\"\"\n        if binary is None:\n            binary = self.default_binary\n        else:\n            # improve behavior of which by resolving the path: ~/relative paths don't work\n            resolved_path = Path(os.path.expanduser(binary)).resolve()\n            if resolved_path.exists():\n                binary = resolved_path\n        binary = shutil.which(binary)  # type: ignore\n        if not binary:\n            raise TransitionToolNotFoundInPath(binary=binary)\n        self.binary = Path(binary)\n        self.trace = trace\n\n    def __init_subclass__(cls):\n\"\"\"\n        Registers all subclasses of TransitionTool as possible tools.\n        \"\"\"\n        TransitionTool.register_tool(cls)\n\n    @classmethod\n    def register_tool(cls, tool_subclass: Type[\"TransitionTool\"]):\n\"\"\"\n        Registers a given subclass as tool option.\n        \"\"\"\n        cls.registered_tools.append(tool_subclass)\n\n    @classmethod\n    def set_default_tool(cls, tool_subclass: Type[\"TransitionTool\"]):\n\"\"\"\n        Registers the default tool subclass.\n        \"\"\"\n        cls.default_tool = tool_subclass\n\n    @classmethod\n    def from_binary_path(cls, *, binary_path: Optional[Path], **kwargs) -> \"TransitionTool\":\n\"\"\"\n        Instantiates the appropriate TransitionTool subclass derived from the\n        tool's binary path.\n        \"\"\"\n        assert cls.default_tool is not None, \"default transition tool was never set\"\n\n        if binary_path is None:\n            return cls.default_tool(binary=binary_path, **kwargs)\n\n        resolved_path = Path(os.path.expanduser(binary_path)).resolve()\n        if resolved_path.exists():\n            binary_path = resolved_path\n        binary = shutil.which(binary_path)  # type: ignore\n\n        if not binary:\n            raise TransitionToolNotFoundInPath(binary=binary)\n\n        binary = Path(binary)\n\n        # Group the tools by version flag, so we only have to call the tool once for all the\n        # classes that share the same version flag\n        for version_flag, subclasses in groupby(\n            cls.registered_tools, key=lambda x: x.version_flag\n        ):\n            try:\n                with os.popen(f\"{binary} {version_flag}\") as f:\n                    binary_output = f.read()\n            except Exception:\n                # If the tool doesn't support the version flag,\n                # we'll get an non-zero exit code.\n                continue\n            for subclass in subclasses:\n                if subclass.detect_binary(binary_output):\n                    return subclass(binary=binary, **kwargs)\n\n        raise UnknownTransitionTool(f\"Unknown transition tool binary: {binary_path}\")\n\n    @classmethod\n    def detect_binary(cls, binary_output: str) -> bool:\n\"\"\"\n        Returns True if the binary matches the tool\n        \"\"\"\n        assert cls.detect_binary_pattern is not None\n\n        return cls.detect_binary_pattern.match(binary_output) is not None\n\n    @abstractmethod\n    def evaluate(\n        self,\n        alloc: Any,\n        txs: Any,\n        env: Any,\n        fork: Fork,\n        chain_id: int = 1,\n        reward: int = 0,\n        eips: Optional[List[int]] = None,\n    ) -> Tuple[Dict[str, Any], Dict[str, Any]]:\n\"\"\"\n        Simulate a state transition with specified parameters\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def version(self) -> str:\n\"\"\"\n        Return name and version of tool used to state transition\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def is_fork_supported(self, fork: Fork) -> bool:\n\"\"\"\n        Returns True if the fork is supported by the tool\n        \"\"\"\n        pass\n\n    def reset_traces(self):\n\"\"\"\n        Resets the internal trace storage for a new test to begin\n        \"\"\"\n        self.traces = None\n\n    def append_traces(self, new_traces: List[List[Dict]]):\n\"\"\"\n        Appends a list of traces of a state transition to the current list\n        \"\"\"\n        if self.traces is None:\n            self.traces = []\n        self.traces.append(new_traces)\n\n    def get_traces(self) -> List[List[List[Dict]]] | None:\n\"\"\"\n        Returns the accumulated traces\n        \"\"\"\n        return self.traces\n\n    def calc_state_root(self, alloc: Any, fork: Fork) -> bytes:\n\"\"\"\n        Calculate the state root for the given `alloc`.\n        \"\"\"\n        env: Dict[str, Any] = {\n            \"currentCoinbase\": \"0x0000000000000000000000000000000000000000\",\n            \"currentDifficulty\": \"0x0\",\n            \"currentGasLimit\": \"0x0\",\n            \"currentNumber\": \"0\",\n            \"currentTimestamp\": \"0\",\n        }\n\n        if fork.header_base_fee_required(0, 0):\n            env[\"currentBaseFee\"] = \"7\"\n\n        if fork.header_prev_randao_required(0, 0):\n            env[\"currentRandom\"] = \"0\"\n\n        if fork.header_withdrawals_required(0, 0):\n            env[\"withdrawals\"] = []\n\n        _, result = self.evaluate(alloc, [], env, fork)\n        state_root = result.get(\"stateRoot\")\n        if state_root is None or not isinstance(state_root, str):\n            raise Exception(\"Unable to calculate state root\")\n        return bytes.fromhex(state_root[2:])\n\n    def calc_withdrawals_root(self, withdrawals: Any, fork: Fork) -> bytes:\n\"\"\"\n        Calculate the state root for the given `alloc`.\n        \"\"\"\n        if type(withdrawals) is list and len(withdrawals) == 0:\n            # Optimize returning the empty root immediately\n            return bytes.fromhex(\n                \"56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\"\n            )\n\n        env: Dict[str, Any] = {\n            \"currentCoinbase\": \"0x0000000000000000000000000000000000000000\",\n            \"currentDifficulty\": \"0x0\",\n            \"currentGasLimit\": \"0x0\",\n            \"currentNumber\": \"0\",\n            \"currentTimestamp\": \"0\",\n            \"withdrawals\": withdrawals,\n        }\n\n        if fork.header_base_fee_required(0, 0):\n            env[\"currentBaseFee\"] = \"7\"\n\n        if fork.header_prev_randao_required(0, 0):\n            env[\"currentRandom\"] = \"0\"\n\n        if fork.header_excess_data_gas_required(0, 0):\n            env[\"currentExcessDataGas\"] = \"0\"\n\n        _, result = self.evaluate({}, [], env, fork)\n        withdrawals_root = result.get(\"withdrawalsRoot\")\n        if withdrawals_root is None:\n            raise Exception(\n                \"Unable to calculate withdrawals root: no value returned from transition tool\"\n            )\n        if type(withdrawals_root) is not str:\n            raise Exception(\n                \"Unable to calculate withdrawals root: \"\n                + \"incorrect type returned from transition tool: \"\n                + f\"{withdrawals_root}\"\n            )\n        return bytes.fromhex(withdrawals_root[2:])\n
"},{"location":"library/pytest_plugins/forks/#evm_transition_tool.transition_tool.TransitionTool.__init__","title":"__init__(*, binary=None, trace=False) abstractmethod","text":"

Abstract initialization method that all subclasses must implement.

Source code in src/evm_transition_tool/transition_tool.py
@abstractmethod\ndef __init__(\n    self,\n    *,\n    binary: Optional[Path] = None,\n    trace: bool = False,\n):\n\"\"\"\n    Abstract initialization method that all subclasses must implement.\n    \"\"\"\n    if binary is None:\n        binary = self.default_binary\n    else:\n        # improve behavior of which by resolving the path: ~/relative paths don't work\n        resolved_path = Path(os.path.expanduser(binary)).resolve()\n        if resolved_path.exists():\n            binary = resolved_path\n    binary = shutil.which(binary)  # type: ignore\n    if not binary:\n        raise TransitionToolNotFoundInPath(binary=binary)\n    self.binary = Path(binary)\n    self.trace = trace\n
"},{"location":"library/pytest_plugins/forks/#evm_transition_tool.transition_tool.TransitionTool.__init_subclass__","title":"__init_subclass__()","text":"

Registers all subclasses of TransitionTool as possible tools.

Source code in src/evm_transition_tool/transition_tool.py
def __init_subclass__(cls):\n\"\"\"\n    Registers all subclasses of TransitionTool as possible tools.\n    \"\"\"\n    TransitionTool.register_tool(cls)\n
"},{"location":"library/pytest_plugins/forks/#evm_transition_tool.transition_tool.TransitionTool.register_tool","title":"register_tool(tool_subclass) classmethod","text":"

Registers a given subclass as tool option.

Source code in src/evm_transition_tool/transition_tool.py
@classmethod\ndef register_tool(cls, tool_subclass: Type[\"TransitionTool\"]):\n\"\"\"\n    Registers a given subclass as tool option.\n    \"\"\"\n    cls.registered_tools.append(tool_subclass)\n
"},{"location":"library/pytest_plugins/forks/#evm_transition_tool.transition_tool.TransitionTool.set_default_tool","title":"set_default_tool(tool_subclass) classmethod","text":"

Registers the default tool subclass.

Source code in src/evm_transition_tool/transition_tool.py
@classmethod\ndef set_default_tool(cls, tool_subclass: Type[\"TransitionTool\"]):\n\"\"\"\n    Registers the default tool subclass.\n    \"\"\"\n    cls.default_tool = tool_subclass\n
"},{"location":"library/pytest_plugins/forks/#evm_transition_tool.transition_tool.TransitionTool.from_binary_path","title":"from_binary_path(*, binary_path, **kwargs) classmethod","text":"

Instantiates the appropriate TransitionTool subclass derived from the tool's binary path.

Source code in src/evm_transition_tool/transition_tool.py
@classmethod\ndef from_binary_path(cls, *, binary_path: Optional[Path], **kwargs) -> \"TransitionTool\":\n\"\"\"\n    Instantiates the appropriate TransitionTool subclass derived from the\n    tool's binary path.\n    \"\"\"\n    assert cls.default_tool is not None, \"default transition tool was never set\"\n\n    if binary_path is None:\n        return cls.default_tool(binary=binary_path, **kwargs)\n\n    resolved_path = Path(os.path.expanduser(binary_path)).resolve()\n    if resolved_path.exists():\n        binary_path = resolved_path\n    binary = shutil.which(binary_path)  # type: ignore\n\n    if not binary:\n        raise TransitionToolNotFoundInPath(binary=binary)\n\n    binary = Path(binary)\n\n    # Group the tools by version flag, so we only have to call the tool once for all the\n    # classes that share the same version flag\n    for version_flag, subclasses in groupby(\n        cls.registered_tools, key=lambda x: x.version_flag\n    ):\n        try:\n            with os.popen(f\"{binary} {version_flag}\") as f:\n                binary_output = f.read()\n        except Exception:\n            # If the tool doesn't support the version flag,\n            # we'll get an non-zero exit code.\n            continue\n        for subclass in subclasses:\n            if subclass.detect_binary(binary_output):\n                return subclass(binary=binary, **kwargs)\n\n    raise UnknownTransitionTool(f\"Unknown transition tool binary: {binary_path}\")\n
"},{"location":"library/pytest_plugins/forks/#evm_transition_tool.transition_tool.TransitionTool.detect_binary","title":"detect_binary(binary_output) classmethod","text":"

Returns True if the binary matches the tool

Source code in src/evm_transition_tool/transition_tool.py
@classmethod\ndef detect_binary(cls, binary_output: str) -> bool:\n\"\"\"\n    Returns True if the binary matches the tool\n    \"\"\"\n    assert cls.detect_binary_pattern is not None\n\n    return cls.detect_binary_pattern.match(binary_output) is not None\n
"},{"location":"library/pytest_plugins/forks/#evm_transition_tool.transition_tool.TransitionTool.evaluate","title":"evaluate(alloc, txs, env, fork, chain_id=1, reward=0, eips=None) abstractmethod","text":"

Simulate a state transition with specified parameters

Source code in src/evm_transition_tool/transition_tool.py
@abstractmethod\ndef evaluate(\n    self,\n    alloc: Any,\n    txs: Any,\n    env: Any,\n    fork: Fork,\n    chain_id: int = 1,\n    reward: int = 0,\n    eips: Optional[List[int]] = None,\n) -> Tuple[Dict[str, Any], Dict[str, Any]]:\n\"\"\"\n    Simulate a state transition with specified parameters\n    \"\"\"\n    pass\n
"},{"location":"library/pytest_plugins/forks/#evm_transition_tool.transition_tool.TransitionTool.version","title":"version() abstractmethod","text":"

Return name and version of tool used to state transition

Source code in src/evm_transition_tool/transition_tool.py
@abstractmethod\ndef version(self) -> str:\n\"\"\"\n    Return name and version of tool used to state transition\n    \"\"\"\n    pass\n
"},{"location":"library/pytest_plugins/forks/#evm_transition_tool.transition_tool.TransitionTool.is_fork_supported","title":"is_fork_supported(fork) abstractmethod","text":"

Returns True if the fork is supported by the tool

Source code in src/evm_transition_tool/transition_tool.py
@abstractmethod\ndef is_fork_supported(self, fork: Fork) -> bool:\n\"\"\"\n    Returns True if the fork is supported by the tool\n    \"\"\"\n    pass\n
"},{"location":"library/pytest_plugins/forks/#evm_transition_tool.transition_tool.TransitionTool.reset_traces","title":"reset_traces()","text":"

Resets the internal trace storage for a new test to begin

Source code in src/evm_transition_tool/transition_tool.py
def reset_traces(self):\n\"\"\"\n    Resets the internal trace storage for a new test to begin\n    \"\"\"\n    self.traces = None\n
"},{"location":"library/pytest_plugins/forks/#evm_transition_tool.transition_tool.TransitionTool.append_traces","title":"append_traces(new_traces)","text":"

Appends a list of traces of a state transition to the current list

Source code in src/evm_transition_tool/transition_tool.py
def append_traces(self, new_traces: List[List[Dict]]):\n\"\"\"\n    Appends a list of traces of a state transition to the current list\n    \"\"\"\n    if self.traces is None:\n        self.traces = []\n    self.traces.append(new_traces)\n
"},{"location":"library/pytest_plugins/forks/#evm_transition_tool.transition_tool.TransitionTool.get_traces","title":"get_traces()","text":"

Returns the accumulated traces

Source code in src/evm_transition_tool/transition_tool.py
def get_traces(self) -> List[List[List[Dict]]] | None:\n\"\"\"\n    Returns the accumulated traces\n    \"\"\"\n    return self.traces\n
"},{"location":"library/pytest_plugins/forks/#evm_transition_tool.transition_tool.TransitionTool.calc_state_root","title":"calc_state_root(alloc, fork)","text":"

Calculate the state root for the given alloc.

Source code in src/evm_transition_tool/transition_tool.py
def calc_state_root(self, alloc: Any, fork: Fork) -> bytes:\n\"\"\"\n    Calculate the state root for the given `alloc`.\n    \"\"\"\n    env: Dict[str, Any] = {\n        \"currentCoinbase\": \"0x0000000000000000000000000000000000000000\",\n        \"currentDifficulty\": \"0x0\",\n        \"currentGasLimit\": \"0x0\",\n        \"currentNumber\": \"0\",\n        \"currentTimestamp\": \"0\",\n    }\n\n    if fork.header_base_fee_required(0, 0):\n        env[\"currentBaseFee\"] = \"7\"\n\n    if fork.header_prev_randao_required(0, 0):\n        env[\"currentRandom\"] = \"0\"\n\n    if fork.header_withdrawals_required(0, 0):\n        env[\"withdrawals\"] = []\n\n    _, result = self.evaluate(alloc, [], env, fork)\n    state_root = result.get(\"stateRoot\")\n    if state_root is None or not isinstance(state_root, str):\n        raise Exception(\"Unable to calculate state root\")\n    return bytes.fromhex(state_root[2:])\n
"},{"location":"library/pytest_plugins/forks/#evm_transition_tool.transition_tool.TransitionTool.calc_withdrawals_root","title":"calc_withdrawals_root(withdrawals, fork)","text":"

Calculate the state root for the given alloc.

Source code in src/evm_transition_tool/transition_tool.py
def calc_withdrawals_root(self, withdrawals: Any, fork: Fork) -> bytes:\n\"\"\"\n    Calculate the state root for the given `alloc`.\n    \"\"\"\n    if type(withdrawals) is list and len(withdrawals) == 0:\n        # Optimize returning the empty root immediately\n        return bytes.fromhex(\n            \"56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\"\n        )\n\n    env: Dict[str, Any] = {\n        \"currentCoinbase\": \"0x0000000000000000000000000000000000000000\",\n        \"currentDifficulty\": \"0x0\",\n        \"currentGasLimit\": \"0x0\",\n        \"currentNumber\": \"0\",\n        \"currentTimestamp\": \"0\",\n        \"withdrawals\": withdrawals,\n    }\n\n    if fork.header_base_fee_required(0, 0):\n        env[\"currentBaseFee\"] = \"7\"\n\n    if fork.header_prev_randao_required(0, 0):\n        env[\"currentRandom\"] = \"0\"\n\n    if fork.header_excess_data_gas_required(0, 0):\n        env[\"currentExcessDataGas\"] = \"0\"\n\n    _, result = self.evaluate({}, [], env, fork)\n    withdrawals_root = result.get(\"withdrawalsRoot\")\n    if withdrawals_root is None:\n        raise Exception(\n            \"Unable to calculate withdrawals root: no value returned from transition tool\"\n        )\n    if type(withdrawals_root) is not str:\n        raise Exception(\n            \"Unable to calculate withdrawals root: \"\n            + \"incorrect type returned from transition tool: \"\n            + f\"{withdrawals_root}\"\n        )\n    return bytes.fromhex(withdrawals_root[2:])\n
"},{"location":"library/pytest_plugins/forks/#pytest_plugins.forks.forks.get_deployed_forks","title":"get_deployed_forks()","text":"

Returns a list of all the fork classes implemented by ethereum_test_forks that have been deployed to mainnet, chronologically ordered by deployment.

Source code in src/ethereum_test_forks/helpers.py
def get_deployed_forks():\n\"\"\"\n    Returns a list of all the fork classes implemented by `ethereum_test_forks`\n    that have been deployed to mainnet, chronologically ordered by deployment.\n    \"\"\"\n    return [fork for fork in get_forks() if fork.is_deployed()]\n
"},{"location":"library/pytest_plugins/forks/#pytest_plugins.forks.forks.pytest_configure","title":"pytest_configure(config)","text":"

Register the plugin's custom markers and process command-line options.

Custom marker registration: https://docs.pytest.org/en/7.1.x/how-to/writing_plugins.html#registering-custom-markers

Source code in src/pytest_plugins/forks/forks.py
@pytest.hookimpl(tryfirst=True)\ndef pytest_configure(config):\n\"\"\"\n    Register the plugin's custom markers and process command-line options.\n\n    Custom marker registration:\n    https://docs.pytest.org/en/7.1.x/how-to/writing_plugins.html#registering-custom-markers\n    \"\"\"\n    config.addinivalue_line(\n        \"markers\",\n        (\n            \"valid_at_transition_to(fork): specifies a test case is valid \"\n            \"only at fork transition boundary to the specified fork\"\n        ),\n    )\n    config.addinivalue_line(\n        \"markers\",\n        \"valid_from(fork): specifies from which fork a test case is valid\",\n    )\n    config.addinivalue_line(\n        \"markers\",\n        \"valid_until(fork): specifies until which fork a test case is valid\",\n    )\n\n    single_fork = config.getoption(\"single_fork\")\n    forks_from = config.getoption(\"forks_from\")\n    forks_until = config.getoption(\"forks_until\")\n    show_fork_help = config.getoption(\"show_fork_help\")\n\n    all_forks = get_forks()\n    # TODO: Tricky, this removes the *Glacier forks.\n    config.all_forks = forks_from_until(all_forks[0], all_forks[-1])\n    config.fork_map = {fork.name(): fork for fork in config.all_forks}\n    config.fork_names = list(config.fork_map.keys())\n\n    available_forks_help = textwrap.dedent(\n        f\"\"\"\\\n        Available forks:\n{\", \".join(config.fork_names)}\n        \"\"\"\n    )\n    available_forks_help += textwrap.dedent(\n        f\"\"\"\\\n        Available transition forks:\n{\", \".join([fork.name() for fork in get_transition_forks()])}\n        \"\"\"\n    )\n    dev_forks_help = textwrap.dedent(\n        \"To run tests for a fork under active development, it must be \"\n        \"specified explicitly via --forks-until=FORK.\\n\"\n        \"Tests are only ran for deployed mainnet forks by default, i.e., \"\n        f\"until {get_deployed_forks()[-1].name()}.\\n\"\n    )\n    if show_fork_help:\n        print(available_forks_help)\n        print(dev_forks_help)\n        pytest.exit(\"After displaying help.\", returncode=0)\n\n    if single_fork and single_fork not in config.fork_map.keys():\n        print(\"Error: Unsupported fork provided to --fork:\", single_fork, \"\\n\", file=sys.stderr)\n        print(available_forks_help, file=sys.stderr)\n        pytest.exit(\"Invalid command-line options.\", returncode=pytest.ExitCode.USAGE_ERROR)\n\n    if single_fork and (forks_from or forks_until):\n        print(\n            \"Error: --fork cannot be used in combination with --from or --until\", file=sys.stderr\n        )\n        pytest.exit(\"Invalid command-line options.\", returncode=pytest.ExitCode.USAGE_ERROR)\n\n    if single_fork:\n        forks_from = single_fork\n        forks_until = single_fork\n    else:\n        if not forks_from:\n            forks_from = config.fork_names[0]\n        if not forks_until:\n            forks_until = get_deployed_forks()[-1].name()\n\n    if forks_from not in config.fork_map.keys():\n        print(f\"Error: Unsupported fork provided to --from: {forks_from}\\n\", file=sys.stderr)\n        print(available_forks_help, file=sys.stderr)\n        pytest.exit(\"Invalid command-line options.\", returncode=pytest.ExitCode.USAGE_ERROR)\n\n    if forks_until not in config.fork_map.keys():\n        print(f\"Error: Unsupported fork provided to --until: {forks_until}\\n\", file=sys.stderr)\n        print(available_forks_help, file=sys.stderr)\n        pytest.exit(\"Invalid command-line options.\", returncode=pytest.ExitCode.USAGE_ERROR)\n\n    config.fork_range = config.fork_names[\n        config.fork_names.index(forks_from) : config.fork_names.index(forks_until) + 1\n    ]\n\n    if not config.fork_range:\n        print(\n            f\"Error: --from {forks_from} --until {forks_until} creates an empty fork range.\",\n            file=sys.stderr,\n        )\n        pytest.exit(\n            \"Command-line options produce empty fork range.\",\n            returncode=pytest.ExitCode.USAGE_ERROR,\n        )\n\n    # with --collect-only, we don't have access to these config options\n    if config.option.collectonly:\n        return\n\n    evm_bin = config.getoption(\"evm_bin\")\n    t8n = TransitionTool.from_binary_path(binary_path=evm_bin)\n    unsupported_forks = [\n        fork for fork in config.fork_range if not t8n.is_fork_supported(config.fork_map[fork])\n    ]\n    if unsupported_forks:\n        print(\n            \"Error: The configured evm tool doesn't support the following \"\n            f\"forks: {', '.join(unsupported_forks)}.\",\n            file=sys.stderr,\n        )\n        print(\n            \"\\nPlease specify a version of the evm tool which supports these \"\n            \"forks or use --until FORK to specify a supported fork.\\n\",\n            file=sys.stderr,\n        )\n        pytest.exit(\n            \"Incompatible evm tool with fork range.\", returncode=pytest.ExitCode.USAGE_ERROR\n        )\n
"},{"location":"library/pytest_plugins/forks/#pytest_plugins.forks.forks.get_transition_forks","title":"get_transition_forks()","text":"

Returns all the transition forks

Source code in src/ethereum_test_forks/helpers.py
def get_transition_forks() -> List[Fork]:\n\"\"\"\n    Returns all the transition forks\n    \"\"\"\n    transition_forks: List[Fork] = []\n\n    for fork_name in transition.__dict__:\n        fork = transition.__dict__[fork_name]\n        if not isinstance(fork, type):\n            continue\n        if issubclass(fork, TransitionBaseClass) and issubclass(fork, BaseFork):\n            transition_forks.append(fork)\n\n    return transition_forks\n
"},{"location":"library/pytest_plugins/forks/#pytest_plugins.forks.forks.transition_fork_to","title":"transition_fork_to(fork_to)","text":"

Returns the transition fork that transitions to the specified fork.

Source code in src/ethereum_test_forks/helpers.py
def transition_fork_to(fork_to: Fork) -> List[Fork]:\n\"\"\"\n    Returns the transition fork that transitions to the specified fork.\n    \"\"\"\n    transition_forks: List[Fork] = []\n    for transition_fork in get_transition_forks():\n        if not issubclass(transition_fork, TransitionBaseClass):\n            continue\n        if transition_fork.transitions_to() == fork_to:\n            transition_forks.append(transition_fork)\n\n    return transition_forks\n
"},{"location":"library/pytest_plugins/forks/#pytest_plugins.forks.forks.forks_from_until","title":"forks_from_until(fork_from, fork_until)","text":"

Returns the specified fork and all forks after it until and including the second specified fork

Source code in src/ethereum_test_forks/helpers.py
def forks_from_until(fork_from: Fork, fork_until: Fork) -> List[Fork]:\n\"\"\"\n    Returns the specified fork and all forks after it until and including the\n    second specified fork\n    \"\"\"\n    prev_fork = fork_until\n\n    forks: List[Fork] = []\n\n    while prev_fork != BaseFork and prev_fork != fork_from:\n        forks.insert(0, prev_fork)\n\n        prev_fork = prev_fork.__base__\n\n    if prev_fork == BaseFork:\n        return []\n\n    forks.insert(0, fork_from)\n\n    return forks\n
"},{"location":"library/pytest_plugins/forks/#pytest_plugins.forks.forks.pytest_report_header","title":"pytest_report_header(config, start_path)","text":"

A pytest hook called to obtain the report header.

Source code in src/pytest_plugins/forks/forks.py
@pytest.hookimpl(trylast=True)\ndef pytest_report_header(config, start_path):\n\"\"\"A pytest hook called to obtain the report header.\"\"\"\n    bold = \"\\033[1m\"\n    warning = \"\\033[93m\"\n    reset = \"\\033[39;49m\"\n    header = [\n        (bold + f\"Executing tests for: {', '.join(config.fork_range)} \" + reset),\n    ]\n    if config.getoption(\"forks_until\") is None:\n        header += [\n            (\n                bold + warning + \"Only executing tests with stable/deployed forks: \"\n                \"Specify an upcoming fork via --until=fork to \"\n                \"add forks under development.\" + reset\n            )\n        ]\n    return header\n
"},{"location":"library/pytest_plugins/forks/#pytest_plugins.forks.forks.fork","title":"fork(request)","text":"

Parametrize test cases by fork.

Source code in src/pytest_plugins/forks/forks.py
@pytest.fixture(autouse=True)\ndef fork(request):\n\"\"\"\n    Parametrize test cases by fork.\n    \"\"\"\n    pass\n
"},{"location":"library/pytest_plugins/forks/#pytest_plugins.forks.forks.get_validity_marker_args","title":"get_validity_marker_args(metafunc, validity_marker_name, test_name)","text":"

Check and return the arguments specified to validity markers.

Check that the validity markers:

  • pytest.mark.valid_from
  • pytest.mark.valid_until
  • pytest.mark.valid_at_transition_to

are applied at most once and have been provided with exactly one argument which is a valid fork name.

Parameters:

Name Type Description Default metafunc Metafunc

Pytest's metafunc object.

required validity_marker_name str

Name of the validity marker to validate and return.

required test_name str

The name of the test being parametrized by pytest_generate_tests.

required

Returns:

Type Description str | None

The name of the fork specified to the validity marker.

Source code in src/pytest_plugins/forks/forks.py
def get_validity_marker_args(\n    metafunc: Metafunc,\n    validity_marker_name: str,\n    test_name: str,\n) -> str | None:\n\"\"\"Check and return the arguments specified to validity markers.\n\n    Check that the validity markers:\n\n    - `pytest.mark.valid_from`\n    - `pytest.mark.valid_until`\n    - `pytest.mark.valid_at_transition_to`\n\n    are applied at most once and have been provided with exactly one\n    argument which is a valid fork name.\n\n    Args:\n        metafunc: Pytest's metafunc object.\n        validity_marker_name: Name of the validity marker to validate\n            and return.\n        test_name: The name of the test being parametrized by\n            `pytest_generate_tests`.\n\n    Returns:\n        The name of the fork specified to the validity marker.\n    \"\"\"\n    validity_markers = [\n        marker for marker in metafunc.definition.iter_markers(validity_marker_name)\n    ]\n    if not validity_markers:\n        return None\n    if len(validity_markers) > 1:\n        pytest.fail(f\"'{test_name}': Too many '{validity_marker_name}' markers applied to test. \")\n    if len(validity_markers[0].args) == 0:\n        pytest.fail(f\"'{test_name}': Missing fork argument with '{validity_marker_name}' marker. \")\n    if len(validity_markers[0].args) > 1:\n        pytest.fail(\n            f\"'{test_name}': Too many arguments specified to '{validity_marker_name}' marker. \"\n        )\n    fork_name = validity_markers[0].args[0]\n    if fork_name not in metafunc.config.fork_names:  # type: ignore\n        pytest.fail(\n            f\"'{test_name}' specifies an invalid fork '{fork_name}' to the \"\n            f\"'{validity_marker_name}'. \"\n            f\"List of valid forks: {', '.join(metafunc.config.fork_names)}\"  # type: ignore\n        )\n\n    return fork_name\n
"},{"location":"library/pytest_plugins/forks/#pytest_plugins.forks.forks.pytest_generate_tests","title":"pytest_generate_tests(metafunc)","text":"

Pytest hook used to dynamically generate test cases.

Source code in src/pytest_plugins/forks/forks.py
def pytest_generate_tests(metafunc):\n\"\"\"\n    Pytest hook used to dynamically generate test cases.\n    \"\"\"\n    test_name = metafunc.function.__name__\n    valid_at_transition_to = get_validity_marker_args(\n        metafunc, \"valid_at_transition_to\", test_name\n    )\n    valid_from = get_validity_marker_args(metafunc, \"valid_from\", test_name)\n    valid_until = get_validity_marker_args(metafunc, \"valid_until\", test_name)\n\n    if valid_at_transition_to and valid_from:\n        pytest.fail(\n            f\"'{test_name}': \"\n            \"The markers 'valid_from' and 'valid_at_transition_to' can't be combined. \"\n        )\n    if valid_at_transition_to and valid_until:\n        pytest.fail(\n            f\"'{test_name}': \"\n            \"The markers 'valid_until' and 'valid_at_transition_to' can't be combined. \"\n        )\n\n    intersection_range = []\n\n    if valid_at_transition_to:\n        if valid_at_transition_to in metafunc.config.fork_range:\n            to_fork = metafunc.config.fork_map[valid_at_transition_to]\n            intersection_range = transition_fork_to(to_fork)\n\n    else:\n        if not valid_from:\n            valid_from = metafunc.config.fork_names[0]\n\n        if not valid_until:\n            valid_until = metafunc.config.fork_names[-1]\n\n        test_fork_range = set(\n            metafunc.config.fork_names[\n                metafunc.config.fork_names.index(valid_from) : metafunc.config.fork_names.index(\n                    valid_until\n                )\n                + 1\n            ]\n        )\n\n        if not test_fork_range:\n            pytest.fail(\n                \"The test function's \"\n                f\"'{test_name}' fork validity markers generate \"\n                \"an empty fork range. Please check the arguments to its \"\n                f\"markers:  @pytest.mark.valid_from ({valid_from}) and \"\n                f\"@pytest.mark.valid_until ({valid_until}).\"\n            )\n\n        intersection_range = list(set(metafunc.config.fork_range) & test_fork_range)\n\n        intersection_range.sort(key=metafunc.config.fork_range.index)\n        intersection_range = [metafunc.config.fork_map[fork] for fork in intersection_range]\n\n    if \"fork\" in metafunc.fixturenames:\n        if not intersection_range:\n            pytest.skip(  # this reason is not reported on the command-line\n                f\"{test_name} is not valid for any any of forks specified on the command-line.\"\n            )\n        else:\n            metafunc.parametrize(\"fork\", intersection_range, scope=\"function\")\n
"},{"location":"library/pytest_plugins/navigation/","title":"Navigation","text":"
  • Overview
  • Forks
  • Test Filler
  • Spec Version Checker
"},{"location":"library/pytest_plugins/spec_version_checker/","title":"Spec Version Checker Plugin","text":"

A pytest plugin that verifies the tested version of an EIP specification against the latest version from the ethereum/EIPs Github repository.

A pytest plugin that checks that the spec version specified in test/filler modules matches that of ethereum/EIPs.

"},{"location":"library/pytest_plugins/spec_version_checker/#pytest_plugins.spec_version_checker.spec_version_checker.pytest_configure","title":"pytest_configure(config)","text":"

Register the plugin's custom markers and process command-line options.

Custom marker registration: https://docs.pytest.org/en/7.1.x/how-to/writing_plugins.html#registering-custom-markers

Source code in src/pytest_plugins/spec_version_checker/spec_version_checker.py
@pytest.hookimpl(tryfirst=True)\ndef pytest_configure(config):\n\"\"\"\n    Register the plugin's custom markers and process command-line options.\n\n    Custom marker registration:\n    https://docs.pytest.org/en/7.1.x/how-to/writing_plugins.html#registering-custom-markers\n    \"\"\"\n    config.addinivalue_line(\n        \"markers\",\n        \"eip_version_check: a test that tests the reference spec defined in an EIP test module.\",\n    )\n
"},{"location":"library/pytest_plugins/spec_version_checker/#pytest_plugins.spec_version_checker.spec_version_checker.ReferenceSpec","title":"ReferenceSpec","text":"

Reference Specification Description Abstract Class.

Source code in src/ethereum_test_tools/reference_spec/reference_spec.py
class ReferenceSpec:\n\"\"\"\n    Reference Specification Description Abstract Class.\n    \"\"\"\n\n    @abstractmethod\n    def name(self) -> str:\n\"\"\"\n        Returns the name of the spec.\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def has_known_version(self) -> bool:\n\"\"\"\n        Returns true if the reference spec object is hard-coded with a latest\n        known version.\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def known_version(self) -> str:\n\"\"\"\n        Returns the latest known version in the reference.\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def api_url(self) -> str:\n\"\"\"\n        Returns the URL required to poll the version from an API, if needed.\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def latest_version(self) -> str:\n\"\"\"\n        Returns a digest that points to the latest version of the spec.\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def is_outdated(self) -> bool:\n\"\"\"\n        Checks whether the reference specification has been updated since the\n        test was last updated.\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def write_info(self, info: Dict[str, str]):\n\"\"\"\n        Writes info about the reference specification used into the output\n        fixture.\n        \"\"\"\n        pass\n\n    @staticmethod\n    @abstractmethod\n    def parseable_from_module(module_dict: Dict[str, Any]) -> bool:\n\"\"\"\n        Checks whether the module's dict contains required reference spec\n        information.\n        \"\"\"\n        pass\n\n    @staticmethod\n    @abstractmethod\n    def parse_from_module(module_dict: Dict[str, Any]) -> \"ReferenceSpec\":\n\"\"\"\n        Parses the module's dict into a reference spec.\n        \"\"\"\n        pass\n
"},{"location":"library/pytest_plugins/spec_version_checker/#ethereum_test_tools.reference_spec.reference_spec.ReferenceSpec.name","title":"name() abstractmethod","text":"

Returns the name of the spec.

Source code in src/ethereum_test_tools/reference_spec/reference_spec.py
@abstractmethod\ndef name(self) -> str:\n\"\"\"\n    Returns the name of the spec.\n    \"\"\"\n    pass\n
"},{"location":"library/pytest_plugins/spec_version_checker/#ethereum_test_tools.reference_spec.reference_spec.ReferenceSpec.has_known_version","title":"has_known_version() abstractmethod","text":"

Returns true if the reference spec object is hard-coded with a latest known version.

Source code in src/ethereum_test_tools/reference_spec/reference_spec.py
@abstractmethod\ndef has_known_version(self) -> bool:\n\"\"\"\n    Returns true if the reference spec object is hard-coded with a latest\n    known version.\n    \"\"\"\n    pass\n
"},{"location":"library/pytest_plugins/spec_version_checker/#ethereum_test_tools.reference_spec.reference_spec.ReferenceSpec.known_version","title":"known_version() abstractmethod","text":"

Returns the latest known version in the reference.

Source code in src/ethereum_test_tools/reference_spec/reference_spec.py
@abstractmethod\ndef known_version(self) -> str:\n\"\"\"\n    Returns the latest known version in the reference.\n    \"\"\"\n    pass\n
"},{"location":"library/pytest_plugins/spec_version_checker/#ethereum_test_tools.reference_spec.reference_spec.ReferenceSpec.api_url","title":"api_url() abstractmethod","text":"

Returns the URL required to poll the version from an API, if needed.

Source code in src/ethereum_test_tools/reference_spec/reference_spec.py
@abstractmethod\ndef api_url(self) -> str:\n\"\"\"\n    Returns the URL required to poll the version from an API, if needed.\n    \"\"\"\n    pass\n
"},{"location":"library/pytest_plugins/spec_version_checker/#ethereum_test_tools.reference_spec.reference_spec.ReferenceSpec.latest_version","title":"latest_version() abstractmethod","text":"

Returns a digest that points to the latest version of the spec.

Source code in src/ethereum_test_tools/reference_spec/reference_spec.py
@abstractmethod\ndef latest_version(self) -> str:\n\"\"\"\n    Returns a digest that points to the latest version of the spec.\n    \"\"\"\n    pass\n
"},{"location":"library/pytest_plugins/spec_version_checker/#ethereum_test_tools.reference_spec.reference_spec.ReferenceSpec.is_outdated","title":"is_outdated() abstractmethod","text":"

Checks whether the reference specification has been updated since the test was last updated.

Source code in src/ethereum_test_tools/reference_spec/reference_spec.py
@abstractmethod\ndef is_outdated(self) -> bool:\n\"\"\"\n    Checks whether the reference specification has been updated since the\n    test was last updated.\n    \"\"\"\n    pass\n
"},{"location":"library/pytest_plugins/spec_version_checker/#ethereum_test_tools.reference_spec.reference_spec.ReferenceSpec.write_info","title":"write_info(info) abstractmethod","text":"

Writes info about the reference specification used into the output fixture.

Source code in src/ethereum_test_tools/reference_spec/reference_spec.py
@abstractmethod\ndef write_info(self, info: Dict[str, str]):\n\"\"\"\n    Writes info about the reference specification used into the output\n    fixture.\n    \"\"\"\n    pass\n
"},{"location":"library/pytest_plugins/spec_version_checker/#ethereum_test_tools.reference_spec.reference_spec.ReferenceSpec.parseable_from_module","title":"parseable_from_module(module_dict) staticmethod abstractmethod","text":"

Checks whether the module's dict contains required reference spec information.

Source code in src/ethereum_test_tools/reference_spec/reference_spec.py
@staticmethod\n@abstractmethod\ndef parseable_from_module(module_dict: Dict[str, Any]) -> bool:\n\"\"\"\n    Checks whether the module's dict contains required reference spec\n    information.\n    \"\"\"\n    pass\n
"},{"location":"library/pytest_plugins/spec_version_checker/#ethereum_test_tools.reference_spec.reference_spec.ReferenceSpec.parse_from_module","title":"parse_from_module(module_dict) staticmethod abstractmethod","text":"

Parses the module's dict into a reference spec.

Source code in src/ethereum_test_tools/reference_spec/reference_spec.py
@staticmethod\n@abstractmethod\ndef parse_from_module(module_dict: Dict[str, Any]) -> \"ReferenceSpec\":\n\"\"\"\n    Parses the module's dict into a reference spec.\n    \"\"\"\n    pass\n
"},{"location":"library/pytest_plugins/spec_version_checker/#pytest_plugins.spec_version_checker.spec_version_checker.get_ref_spec_from_module","title":"get_ref_spec_from_module(module)","text":"

Return the reference spec object defined in a module.

Raises:

Type Description Exception

If the module path contains \"eip\" and the module does not define a reference spec.

Returns:

Name Type Description spec_obj None | ReferenceSpec

Return None if the module path does not contain \"eip\", i.e., the module is not required to define a reference spec, otherwise, return the ReferenceSpec object as defined by the module.

Source code in src/pytest_plugins/spec_version_checker/spec_version_checker.py
def get_ref_spec_from_module(module: ModuleType) -> None | ReferenceSpec:\n\"\"\"\n    Return the reference spec object defined in a module.\n\n    Raises:\n        Exception: If the module path contains \"eip\" and the module\n            does not define a reference spec.\n\n    Returns:\n        spec_obj: Return None if the module path does not contain \"eip\",\n            i.e., the module is not required to define a reference spec,\n            otherwise, return the ReferenceSpec object as defined by the\n            module.\n    \"\"\"\n    if not is_test_for_an_eip(str(module.__file__)):\n        return None\n    module_dict = module.__dict__\n    parseable_ref_specs = [\n        ref_spec_type\n        for ref_spec_type in ReferenceSpecTypes\n        if ref_spec_type.parseable_from_module(module_dict)\n    ]\n    if len(parseable_ref_specs) > 0:\n        module_dict = module.__dict__\n        try:\n            spec_obj = parseable_ref_specs[0].parse_from_module(module_dict)\n        except Exception as e:\n            raise Exception(f\"Error in spec_version_checker: {e} (this test is generated).\")\n    else:\n        raise Exception(\"Test doesn't define REFERENCE_SPEC_GIT_PATH and REFERENCE_SPEC_VERSION\")\n    return spec_obj\n
"},{"location":"library/pytest_plugins/spec_version_checker/#pytest_plugins.spec_version_checker.spec_version_checker.reference_spec","title":"reference_spec(request)","text":"

Pytest fixture that returns the reference spec defined in a module.

See get_ref_spec_from_module.

Source code in src/pytest_plugins/spec_version_checker/spec_version_checker.py
@pytest.fixture(autouse=True, scope=\"module\")\ndef reference_spec(request) -> None | ReferenceSpec:\n\"\"\"\n    Pytest fixture that returns the reference spec defined in a module.\n\n    See `get_ref_spec_from_module`.\n    \"\"\"\n    return get_ref_spec_from_module(request.module)\n
"},{"location":"library/pytest_plugins/spec_version_checker/#pytest_plugins.spec_version_checker.spec_version_checker.is_test_for_an_eip","title":"is_test_for_an_eip(input_string)","text":"

Return True if input_string contains an EIP number, i.e., eipNNNN.

Source code in src/pytest_plugins/spec_version_checker/spec_version_checker.py
def is_test_for_an_eip(input_string: str) -> bool:\n\"\"\"\n    Return True if `input_string` contains an EIP number, i.e., eipNNNN.\n    \"\"\"\n    pattern = re.compile(r\".*eip\\d{1,4}\", re.IGNORECASE)\n    if pattern.match(input_string):\n        return True\n    return False\n
"},{"location":"library/pytest_plugins/spec_version_checker/#pytest_plugins.spec_version_checker.spec_version_checker.test_eip_spec_version","title":"test_eip_spec_version(module)","text":"

Test that the ReferenceSpec object as defined in the test module is not outdated when compared to the remote hash from ethereum/EIPs.

Source code in src/pytest_plugins/spec_version_checker/spec_version_checker.py
def test_eip_spec_version(module: ModuleType):\n\"\"\"\n    Test that the ReferenceSpec object as defined in the test module\n    is not outdated when compared to the remote hash from\n    ethereum/EIPs.\n    \"\"\"\n    ref_spec = get_ref_spec_from_module(module)\n    assert ref_spec, \"No reference spec object defined\"\n\n    message = (\n        \"The version of the spec referenced in \"\n        f\"{module} does not match that from ethereum/EIPs, \"\n        f\"tests might be outdated: Spec: {ref_spec.name()}. \"\n        f\"Referenced version: {ref_spec.known_version()}. \"\n        f\"Latest version: {ref_spec.latest_version()}. The \"\n        f\"version was retrieved from {ref_spec.api_url()}.\"\n    )\n    try:\n        is_up_to_date = not ref_spec.is_outdated()\n    except Exception as e:\n        raise Exception(\n            f\"Error in spec_version_checker: {e} (this test is generated). \"\n            f\"Reference spec URL: {ref_spec.api_url()}.\"\n        )\n\n    assert is_up_to_date, message\n
"},{"location":"library/pytest_plugins/spec_version_checker/#pytest_plugins.spec_version_checker.spec_version_checker.EIPSpecTestItem","title":"EIPSpecTestItem","text":"

Bases: Item

Custom pytest test item to test EIP spec versions.

Source code in src/pytest_plugins/spec_version_checker/spec_version_checker.py
class EIPSpecTestItem(Item):\n\"\"\"\n    Custom pytest test item to test EIP spec versions.\n    \"\"\"\n\n    def __init__(self, name, parent, module):\n        super().__init__(name, parent)\n        self.module = module\n\n    @classmethod\n    def from_parent(cls, parent, module):\n\"\"\"\n        Public constructor to define new tests.\n        https://docs.pytest.org/en/latest/reference/reference.html#pytest.nodes.Node.from_parent\n        \"\"\"\n        return super().from_parent(parent=parent, name=\"test_eip_spec_version\", module=module)\n\n    def runtest(self):\n\"\"\"\n        Define the test to execute for this item.\n        \"\"\"\n        test_eip_spec_version(self.module)\n\n    def reportinfo(self):\n\"\"\"\n        Get location information for this test item to use test reports.\n        \"\"\"\n        return \"spec_version_checker\", 0, f\"{self.name}\"\n
"},{"location":"library/pytest_plugins/spec_version_checker/#pytest_plugins.spec_version_checker.spec_version_checker.EIPSpecTestItem.from_parent","title":"from_parent(parent, module) classmethod","text":"

Public constructor to define new tests. https://docs.pytest.org/en/latest/reference/reference.html#pytest.nodes.Node.from_parent

Source code in src/pytest_plugins/spec_version_checker/spec_version_checker.py
@classmethod\ndef from_parent(cls, parent, module):\n\"\"\"\n    Public constructor to define new tests.\n    https://docs.pytest.org/en/latest/reference/reference.html#pytest.nodes.Node.from_parent\n    \"\"\"\n    return super().from_parent(parent=parent, name=\"test_eip_spec_version\", module=module)\n
"},{"location":"library/pytest_plugins/spec_version_checker/#pytest_plugins.spec_version_checker.spec_version_checker.EIPSpecTestItem.runtest","title":"runtest()","text":"

Define the test to execute for this item.

Source code in src/pytest_plugins/spec_version_checker/spec_version_checker.py
def runtest(self):\n\"\"\"\n    Define the test to execute for this item.\n    \"\"\"\n    test_eip_spec_version(self.module)\n
"},{"location":"library/pytest_plugins/spec_version_checker/#pytest_plugins.spec_version_checker.spec_version_checker.EIPSpecTestItem.reportinfo","title":"reportinfo()","text":"

Get location information for this test item to use test reports.

Source code in src/pytest_plugins/spec_version_checker/spec_version_checker.py
def reportinfo(self):\n\"\"\"\n    Get location information for this test item to use test reports.\n    \"\"\"\n    return \"spec_version_checker\", 0, f\"{self.name}\"\n
"},{"location":"library/pytest_plugins/spec_version_checker/#pytest_plugins.spec_version_checker.spec_version_checker.pytest_collection_modifyitems","title":"pytest_collection_modifyitems(session, config, items)","text":"

Insert a new test EIPSpecTestItem for every test modules that contains 'eip' in its path.

Source code in src/pytest_plugins/spec_version_checker/spec_version_checker.py
def pytest_collection_modifyitems(session, config, items):\n\"\"\"\n    Insert a new test EIPSpecTestItem for every test modules that\n    contains 'eip' in its path.\n    \"\"\"\n    modules = set(item.parent for item in items if isinstance(item.parent, Module))\n    new_test_eip_spec_version_items = [\n        EIPSpecTestItem.from_parent(module, module.obj)\n        for module in modules\n        if is_test_for_an_eip(str(module.path))\n    ]\n    for item in new_test_eip_spec_version_items:\n        item.add_marker(\"eip_version_check\", append=True)\n    items.extend(new_test_eip_spec_version_items)\n
"},{"location":"library/pytest_plugins/test_filler/","title":"Test Filler Plugin","text":"

A pytest plugin that provides fixtures that fill tests and generate fixtures.

Top-level pytest configuration file providing: - Command-line options, - Test-fixtures that can be used by all test cases, and that modifies pytest hooks in order to fill test specs for all tests and writes the generated fixtures to file.

"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.fill_test","title":"fill_test(t8n, test_spec, fork, engine, spec, eips=None)","text":"

Fills fixtures for the specified fork.

Source code in src/ethereum_test_tools/filling/fill.py
def fill_test(\n    t8n: TransitionTool,\n    test_spec: BaseTest,\n    fork: Fork,\n    engine: str,\n    spec: ReferenceSpec | None,\n    eips: Optional[List[int]] = None,\n) -> Fixture:\n\"\"\"\n    Fills fixtures for the specified fork.\n    \"\"\"\n    t8n.reset_traces()\n\n    genesis_rlp, genesis = test_spec.make_genesis(t8n, fork)\n\n    (blocks, head, alloc) = test_spec.make_blocks(\n        t8n,\n        genesis,\n        fork,\n        eips=eips,\n    )\n\n    fork_name = fork.name()\n    fixture = Fixture(\n        blocks=blocks,\n        genesis=genesis,\n        genesis_rlp=genesis_rlp,\n        head=head,\n        fork=\"+\".join([fork_name] + [str(eip) for eip in eips]) if eips is not None else fork_name,\n        pre_state=copy(test_spec.pre),\n        post_state=alloc_to_accounts(alloc),\n        seal_engine=engine,\n        name=test_spec.tag,\n    )\n    fixture.fill_info(t8n, spec)\n\n    return fixture\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.BlockchainTest","title":"BlockchainTest dataclass","text":"

Bases: BaseTest

Filler type that tests multiple blocks (valid or invalid) in a chain.

Source code in src/ethereum_test_tools/spec/blockchain_test.py
@dataclass(kw_only=True)\nclass BlockchainTest(BaseTest):\n\"\"\"\n    Filler type that tests multiple blocks (valid or invalid) in a chain.\n    \"\"\"\n\n    pre: Mapping[str, Account]\n    post: Mapping[str, Account]\n    blocks: List[Block]\n    genesis_environment: Environment = field(default_factory=Environment)\n    tag: str = \"\"\n\n    @classmethod\n    def pytest_parameter_name(cls) -> str:\n\"\"\"\n        Returns the parameter name used to identify this filler in a test.\n        \"\"\"\n        return \"blockchain_test\"\n\n    def make_genesis(\n        self,\n        t8n: TransitionTool,\n        fork: Fork,\n    ) -> Tuple[bytes, FixtureHeader]:\n\"\"\"\n        Create a genesis block from the state test definition.\n        \"\"\"\n        env = self.genesis_environment.set_fork_requirements(fork)\n\n        genesis = FixtureHeader(\n            parent_hash=EmptyHash,\n            ommers_hash=EmptyOmmersRoot,\n            coinbase=ZeroAddress,\n            state_root=t8n.calc_state_root(\n                to_json(self.pre),\n                fork,\n            ),\n            transactions_root=EmptyTrieRoot,\n            receipt_root=EmptyTrieRoot,\n            bloom=EmptyBloom,\n            difficulty=0x20000 if env.difficulty is None else env.difficulty,\n            number=0,\n            gas_limit=env.gas_limit,\n            gas_used=0,\n            timestamp=0,\n            extra_data=bytes([0]),\n            mix_digest=EmptyHash,\n            nonce=EmptyNonce,\n            base_fee=env.base_fee,\n            data_gas_used=env.data_gas_used,\n            excess_data_gas=env.excess_data_gas,\n            withdrawals_root=t8n.calc_withdrawals_root(env.withdrawals, fork)\n            if env.withdrawals is not None\n            else None,\n        )\n\n        genesis_rlp, genesis.hash = genesis.build(\n            txs=[],\n            ommers=[],\n            withdrawals=env.withdrawals,\n        )\n\n        return genesis_rlp, genesis\n\n    def make_block(\n        self,\n        t8n: TransitionTool,\n        fork: Fork,\n        block: Block,\n        previous_env: Environment,\n        previous_alloc: Dict[str, Any],\n        previous_head: bytes,\n        chain_id=1,\n        eips: Optional[List[int]] = None,\n    ) -> Tuple[FixtureBlock, Environment, Dict[str, Any], bytes]:\n\"\"\"\n        Produces a block based on the previous environment and allocation.\n        If the block is an invalid block, the environment and allocation\n        returned are the same as passed as parameters.\n        Raises exception on invalid test behavior.\n\n        Returns\n        -------\n            FixtureBlock: Block to be appended to the fixture.\n            Environment: Environment for the next block to produce.\n                If the produced block is invalid, this is exactly the same\n                environment as the one passed as parameter.\n            Dict[str, Any]: Allocation for the next block to produce.\n                If the produced block is invalid, this is exactly the same\n                allocation as the one passed as parameter.\n            str: Hash of the head of the chain, only updated if the produced\n                block is not invalid.\n\n        \"\"\"\n        if block.rlp and block.exception is not None:\n            raise Exception(\n                \"test correctness: post-state cannot be verified if the \"\n                + \"block's rlp is supplied and the block is not supposed \"\n                + \"to produce an exception\"\n            )\n\n        if block.rlp is None:\n            # This is the most common case, the RLP needs to be constructed\n            # based on the transactions to be included in the block.\n            # Set the environment according to the block to execute.\n            env = block.set_environment(previous_env)\n            env = env.set_fork_requirements(fork)\n\n            txs = (\n                [tx.with_signature_and_sender() for tx in block.txs]\n                if block.txs is not None\n                else []\n            )\n\n            next_alloc, result = t8n.evaluate(\n                alloc=previous_alloc,\n                txs=to_json_or_none(txs),\n                env=to_json(env),\n                fork=fork,\n                chain_id=chain_id,\n                reward=fork.get_reward(env.number, env.timestamp),\n                eips=eips,\n            )\n            try:\n                rejected_txs = verify_transactions(txs, result)\n            except Exception as e:\n                print_traces(t8n.get_traces())\n                pprint(result)\n                pprint(previous_alloc)\n                pprint(next_alloc)\n                raise e\n\n            if len(rejected_txs) > 0 and block.exception is None:\n                print_traces(t8n.get_traces())\n                raise Exception(\n                    \"one or more transactions in `BlockchainTest` are \"\n                    + \"intrinsically invalid, but the block was not expected \"\n                    + \"to be invalid. Please verify whether the transaction \"\n                    + \"was indeed expected to fail and add the proper \"\n                    + \"`block.exception`\"\n                )\n\n            header = FixtureHeader.from_dict(\n                result\n                | {\n                    \"parentHash\": env.parent_hash(),\n                    \"miner\": env.coinbase,\n                    \"transactionsRoot\": result.get(\"txRoot\"),\n                    \"difficulty\": str_or_none(result.get(\"currentDifficulty\"), \"0\"),\n                    \"number\": str(env.number),\n                    \"gasLimit\": str(env.gas_limit),\n                    \"timestamp\": str(env.timestamp),\n                    \"extraData\": block.extra_data\n                    if block.extra_data is not None and len(block.extra_data) != 0\n                    else \"0x\",\n                    \"sha3Uncles\": \"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",  # noqa: E501\n                    \"mixHash\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",  # noqa: E501\n                    \"nonce\": \"0x0000000000000000\",\n                    \"baseFeePerGas\": result.get(\"currentBaseFee\"),\n                    \"excessDataGas\": result.get(\"currentExcessDataGas\"),\n                }\n            )\n\n            assert len(header.state_root) == 32\n\n            if block.rlp_modifier is not None:\n                # Modify any parameter specified in the `rlp_modifier` after\n                # transition tool processing.\n                header = header.join(block.rlp_modifier)\n\n            rlp, header.hash = header.build(\n                txs=txs,\n                ommers=[],\n                withdrawals=env.withdrawals,\n            )\n\n            new_payload = FixtureEngineNewPayload.from_fixture_header(\n                fork=fork,\n                header=header,\n                transactions=txs,\n                withdrawals=env.withdrawals,\n                error_code=block.engine_api_error_code,\n            )\n\n            if block.exception is None:\n                # Return environment and allocation of the following block\n                return (\n                    FixtureBlock(\n                        rlp=rlp,\n                        new_payload=new_payload,\n                        block_header=header,\n                        block_number=header.number,\n                        txs=txs,\n                        ommers=[],\n                        withdrawals=env.withdrawals,\n                    ),\n                    env.apply_new_parent(header),\n                    next_alloc,\n                    header.hash,\n                )\n            else:\n                return (\n                    FixtureBlock(\n                        rlp=rlp,\n                        new_payload=new_payload,\n                        expected_exception=block.exception,\n                        block_number=header.number,\n                    ),\n                    previous_env,\n                    previous_alloc,\n                    previous_head,\n                )\n        else:\n            return (\n                FixtureBlock(\n                    rlp=block.rlp,\n                    expected_exception=block.exception,\n                ),\n                previous_env,\n                previous_alloc,\n                previous_head,\n            )\n\n    def make_blocks(\n        self,\n        t8n: TransitionTool,\n        genesis: FixtureHeader,\n        fork: Fork,\n        chain_id=1,\n        eips: Optional[List[int]] = None,\n    ) -> Tuple[List[FixtureBlock], bytes, Dict[str, Any]]:\n\"\"\"\n        Create a block list from the blockchain test definition.\n        Performs checks against the expected behavior of the test.\n        Raises exception on invalid test behavior.\n        \"\"\"\n        alloc = to_json(self.pre)\n        env = Environment.from_parent_header(genesis)\n        blocks: List[FixtureBlock] = []\n        head = genesis.hash if genesis.hash is not None else bytes([0] * 32)\n        for block in self.blocks:\n            fixture_block, env, alloc, head = self.make_block(\n                t8n=t8n,\n                fork=fork,\n                block=block,\n                previous_env=env,\n                previous_alloc=alloc,\n                previous_head=head,\n                chain_id=chain_id,\n                eips=eips,\n            )\n            blocks.append(fixture_block)\n\n        try:\n            verify_post_alloc(self.post, alloc)\n        except Exception as e:\n            print_traces(t8n.get_traces())\n            raise e\n\n        return (blocks, head, alloc)\n
"},{"location":"library/pytest_plugins/test_filler/#ethereum_test_tools.spec.blockchain_test.BlockchainTest.pytest_parameter_name","title":"pytest_parameter_name() classmethod","text":"

Returns the parameter name used to identify this filler in a test.

Source code in src/ethereum_test_tools/spec/blockchain_test.py
@classmethod\ndef pytest_parameter_name(cls) -> str:\n\"\"\"\n    Returns the parameter name used to identify this filler in a test.\n    \"\"\"\n    return \"blockchain_test\"\n
"},{"location":"library/pytest_plugins/test_filler/#ethereum_test_tools.spec.blockchain_test.BlockchainTest.make_genesis","title":"make_genesis(t8n, fork)","text":"

Create a genesis block from the state test definition.

Source code in src/ethereum_test_tools/spec/blockchain_test.py
def make_genesis(\n    self,\n    t8n: TransitionTool,\n    fork: Fork,\n) -> Tuple[bytes, FixtureHeader]:\n\"\"\"\n    Create a genesis block from the state test definition.\n    \"\"\"\n    env = self.genesis_environment.set_fork_requirements(fork)\n\n    genesis = FixtureHeader(\n        parent_hash=EmptyHash,\n        ommers_hash=EmptyOmmersRoot,\n        coinbase=ZeroAddress,\n        state_root=t8n.calc_state_root(\n            to_json(self.pre),\n            fork,\n        ),\n        transactions_root=EmptyTrieRoot,\n        receipt_root=EmptyTrieRoot,\n        bloom=EmptyBloom,\n        difficulty=0x20000 if env.difficulty is None else env.difficulty,\n        number=0,\n        gas_limit=env.gas_limit,\n        gas_used=0,\n        timestamp=0,\n        extra_data=bytes([0]),\n        mix_digest=EmptyHash,\n        nonce=EmptyNonce,\n        base_fee=env.base_fee,\n        data_gas_used=env.data_gas_used,\n        excess_data_gas=env.excess_data_gas,\n        withdrawals_root=t8n.calc_withdrawals_root(env.withdrawals, fork)\n        if env.withdrawals is not None\n        else None,\n    )\n\n    genesis_rlp, genesis.hash = genesis.build(\n        txs=[],\n        ommers=[],\n        withdrawals=env.withdrawals,\n    )\n\n    return genesis_rlp, genesis\n
"},{"location":"library/pytest_plugins/test_filler/#ethereum_test_tools.spec.blockchain_test.BlockchainTest.make_block","title":"make_block(t8n, fork, block, previous_env, previous_alloc, previous_head, chain_id=1, eips=None)","text":"

Produces a block based on the previous environment and allocation. If the block is an invalid block, the environment and allocation returned are the same as passed as parameters. Raises exception on invalid test behavior.

"},{"location":"library/pytest_plugins/test_filler/#ethereum_test_tools.spec.blockchain_test.BlockchainTest.make_block--returns","title":"Returns","text":"
FixtureBlock: Block to be appended to the fixture.\nEnvironment: Environment for the next block to produce.\n    If the produced block is invalid, this is exactly the same\n    environment as the one passed as parameter.\nDict[str, Any]: Allocation for the next block to produce.\n    If the produced block is invalid, this is exactly the same\n    allocation as the one passed as parameter.\nstr: Hash of the head of the chain, only updated if the produced\n    block is not invalid.\n
Source code in src/ethereum_test_tools/spec/blockchain_test.py
def make_block(\n    self,\n    t8n: TransitionTool,\n    fork: Fork,\n    block: Block,\n    previous_env: Environment,\n    previous_alloc: Dict[str, Any],\n    previous_head: bytes,\n    chain_id=1,\n    eips: Optional[List[int]] = None,\n) -> Tuple[FixtureBlock, Environment, Dict[str, Any], bytes]:\n\"\"\"\n    Produces a block based on the previous environment and allocation.\n    If the block is an invalid block, the environment and allocation\n    returned are the same as passed as parameters.\n    Raises exception on invalid test behavior.\n\n    Returns\n    -------\n        FixtureBlock: Block to be appended to the fixture.\n        Environment: Environment for the next block to produce.\n            If the produced block is invalid, this is exactly the same\n            environment as the one passed as parameter.\n        Dict[str, Any]: Allocation for the next block to produce.\n            If the produced block is invalid, this is exactly the same\n            allocation as the one passed as parameter.\n        str: Hash of the head of the chain, only updated if the produced\n            block is not invalid.\n\n    \"\"\"\n    if block.rlp and block.exception is not None:\n        raise Exception(\n            \"test correctness: post-state cannot be verified if the \"\n            + \"block's rlp is supplied and the block is not supposed \"\n            + \"to produce an exception\"\n        )\n\n    if block.rlp is None:\n        # This is the most common case, the RLP needs to be constructed\n        # based on the transactions to be included in the block.\n        # Set the environment according to the block to execute.\n        env = block.set_environment(previous_env)\n        env = env.set_fork_requirements(fork)\n\n        txs = (\n            [tx.with_signature_and_sender() for tx in block.txs]\n            if block.txs is not None\n            else []\n        )\n\n        next_alloc, result = t8n.evaluate(\n            alloc=previous_alloc,\n            txs=to_json_or_none(txs),\n            env=to_json(env),\n            fork=fork,\n            chain_id=chain_id,\n            reward=fork.get_reward(env.number, env.timestamp),\n            eips=eips,\n        )\n        try:\n            rejected_txs = verify_transactions(txs, result)\n        except Exception as e:\n            print_traces(t8n.get_traces())\n            pprint(result)\n            pprint(previous_alloc)\n            pprint(next_alloc)\n            raise e\n\n        if len(rejected_txs) > 0 and block.exception is None:\n            print_traces(t8n.get_traces())\n            raise Exception(\n                \"one or more transactions in `BlockchainTest` are \"\n                + \"intrinsically invalid, but the block was not expected \"\n                + \"to be invalid. Please verify whether the transaction \"\n                + \"was indeed expected to fail and add the proper \"\n                + \"`block.exception`\"\n            )\n\n        header = FixtureHeader.from_dict(\n            result\n            | {\n                \"parentHash\": env.parent_hash(),\n                \"miner\": env.coinbase,\n                \"transactionsRoot\": result.get(\"txRoot\"),\n                \"difficulty\": str_or_none(result.get(\"currentDifficulty\"), \"0\"),\n                \"number\": str(env.number),\n                \"gasLimit\": str(env.gas_limit),\n                \"timestamp\": str(env.timestamp),\n                \"extraData\": block.extra_data\n                if block.extra_data is not None and len(block.extra_data) != 0\n                else \"0x\",\n                \"sha3Uncles\": \"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",  # noqa: E501\n                \"mixHash\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",  # noqa: E501\n                \"nonce\": \"0x0000000000000000\",\n                \"baseFeePerGas\": result.get(\"currentBaseFee\"),\n                \"excessDataGas\": result.get(\"currentExcessDataGas\"),\n            }\n        )\n\n        assert len(header.state_root) == 32\n\n        if block.rlp_modifier is not None:\n            # Modify any parameter specified in the `rlp_modifier` after\n            # transition tool processing.\n            header = header.join(block.rlp_modifier)\n\n        rlp, header.hash = header.build(\n            txs=txs,\n            ommers=[],\n            withdrawals=env.withdrawals,\n        )\n\n        new_payload = FixtureEngineNewPayload.from_fixture_header(\n            fork=fork,\n            header=header,\n            transactions=txs,\n            withdrawals=env.withdrawals,\n            error_code=block.engine_api_error_code,\n        )\n\n        if block.exception is None:\n            # Return environment and allocation of the following block\n            return (\n                FixtureBlock(\n                    rlp=rlp,\n                    new_payload=new_payload,\n                    block_header=header,\n                    block_number=header.number,\n                    txs=txs,\n                    ommers=[],\n                    withdrawals=env.withdrawals,\n                ),\n                env.apply_new_parent(header),\n                next_alloc,\n                header.hash,\n            )\n        else:\n            return (\n                FixtureBlock(\n                    rlp=rlp,\n                    new_payload=new_payload,\n                    expected_exception=block.exception,\n                    block_number=header.number,\n                ),\n                previous_env,\n                previous_alloc,\n                previous_head,\n            )\n    else:\n        return (\n            FixtureBlock(\n                rlp=block.rlp,\n                expected_exception=block.exception,\n            ),\n            previous_env,\n            previous_alloc,\n            previous_head,\n        )\n
"},{"location":"library/pytest_plugins/test_filler/#ethereum_test_tools.spec.blockchain_test.BlockchainTest.make_blocks","title":"make_blocks(t8n, genesis, fork, chain_id=1, eips=None)","text":"

Create a block list from the blockchain test definition. Performs checks against the expected behavior of the test. Raises exception on invalid test behavior.

Source code in src/ethereum_test_tools/spec/blockchain_test.py
def make_blocks(\n    self,\n    t8n: TransitionTool,\n    genesis: FixtureHeader,\n    fork: Fork,\n    chain_id=1,\n    eips: Optional[List[int]] = None,\n) -> Tuple[List[FixtureBlock], bytes, Dict[str, Any]]:\n\"\"\"\n    Create a block list from the blockchain test definition.\n    Performs checks against the expected behavior of the test.\n    Raises exception on invalid test behavior.\n    \"\"\"\n    alloc = to_json(self.pre)\n    env = Environment.from_parent_header(genesis)\n    blocks: List[FixtureBlock] = []\n    head = genesis.hash if genesis.hash is not None else bytes([0] * 32)\n    for block in self.blocks:\n        fixture_block, env, alloc, head = self.make_block(\n            t8n=t8n,\n            fork=fork,\n            block=block,\n            previous_env=env,\n            previous_alloc=alloc,\n            previous_head=head,\n            chain_id=chain_id,\n            eips=eips,\n        )\n        blocks.append(fixture_block)\n\n    try:\n        verify_post_alloc(self.post, alloc)\n    except Exception as e:\n        print_traces(t8n.get_traces())\n        raise e\n\n    return (blocks, head, alloc)\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.TransitionTool","title":"TransitionTool","text":"

Transition tool abstract base class which should be inherited by all transition tool implementations.

Source code in src/evm_transition_tool/transition_tool.py
class TransitionTool:\n\"\"\"\n    Transition tool abstract base class which should be inherited by all transition tool\n    implementations.\n    \"\"\"\n\n    traces: List[List[List[Dict]]] | None = None\n\n    registered_tools: List[Type[\"TransitionTool\"]] = []\n    default_tool: Optional[Type[\"TransitionTool\"]] = None\n    default_binary: Path\n    detect_binary_pattern: Pattern\n    version_flag: str = \"-v\"\n\n    # Abstract methods that each tool must implement\n\n    @abstractmethod\n    def __init__(\n        self,\n        *,\n        binary: Optional[Path] = None,\n        trace: bool = False,\n    ):\n\"\"\"\n        Abstract initialization method that all subclasses must implement.\n        \"\"\"\n        if binary is None:\n            binary = self.default_binary\n        else:\n            # improve behavior of which by resolving the path: ~/relative paths don't work\n            resolved_path = Path(os.path.expanduser(binary)).resolve()\n            if resolved_path.exists():\n                binary = resolved_path\n        binary = shutil.which(binary)  # type: ignore\n        if not binary:\n            raise TransitionToolNotFoundInPath(binary=binary)\n        self.binary = Path(binary)\n        self.trace = trace\n\n    def __init_subclass__(cls):\n\"\"\"\n        Registers all subclasses of TransitionTool as possible tools.\n        \"\"\"\n        TransitionTool.register_tool(cls)\n\n    @classmethod\n    def register_tool(cls, tool_subclass: Type[\"TransitionTool\"]):\n\"\"\"\n        Registers a given subclass as tool option.\n        \"\"\"\n        cls.registered_tools.append(tool_subclass)\n\n    @classmethod\n    def set_default_tool(cls, tool_subclass: Type[\"TransitionTool\"]):\n\"\"\"\n        Registers the default tool subclass.\n        \"\"\"\n        cls.default_tool = tool_subclass\n\n    @classmethod\n    def from_binary_path(cls, *, binary_path: Optional[Path], **kwargs) -> \"TransitionTool\":\n\"\"\"\n        Instantiates the appropriate TransitionTool subclass derived from the\n        tool's binary path.\n        \"\"\"\n        assert cls.default_tool is not None, \"default transition tool was never set\"\n\n        if binary_path is None:\n            return cls.default_tool(binary=binary_path, **kwargs)\n\n        resolved_path = Path(os.path.expanduser(binary_path)).resolve()\n        if resolved_path.exists():\n            binary_path = resolved_path\n        binary = shutil.which(binary_path)  # type: ignore\n\n        if not binary:\n            raise TransitionToolNotFoundInPath(binary=binary)\n\n        binary = Path(binary)\n\n        # Group the tools by version flag, so we only have to call the tool once for all the\n        # classes that share the same version flag\n        for version_flag, subclasses in groupby(\n            cls.registered_tools, key=lambda x: x.version_flag\n        ):\n            try:\n                with os.popen(f\"{binary} {version_flag}\") as f:\n                    binary_output = f.read()\n            except Exception:\n                # If the tool doesn't support the version flag,\n                # we'll get an non-zero exit code.\n                continue\n            for subclass in subclasses:\n                if subclass.detect_binary(binary_output):\n                    return subclass(binary=binary, **kwargs)\n\n        raise UnknownTransitionTool(f\"Unknown transition tool binary: {binary_path}\")\n\n    @classmethod\n    def detect_binary(cls, binary_output: str) -> bool:\n\"\"\"\n        Returns True if the binary matches the tool\n        \"\"\"\n        assert cls.detect_binary_pattern is not None\n\n        return cls.detect_binary_pattern.match(binary_output) is not None\n\n    @abstractmethod\n    def evaluate(\n        self,\n        alloc: Any,\n        txs: Any,\n        env: Any,\n        fork: Fork,\n        chain_id: int = 1,\n        reward: int = 0,\n        eips: Optional[List[int]] = None,\n    ) -> Tuple[Dict[str, Any], Dict[str, Any]]:\n\"\"\"\n        Simulate a state transition with specified parameters\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def version(self) -> str:\n\"\"\"\n        Return name and version of tool used to state transition\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def is_fork_supported(self, fork: Fork) -> bool:\n\"\"\"\n        Returns True if the fork is supported by the tool\n        \"\"\"\n        pass\n\n    def reset_traces(self):\n\"\"\"\n        Resets the internal trace storage for a new test to begin\n        \"\"\"\n        self.traces = None\n\n    def append_traces(self, new_traces: List[List[Dict]]):\n\"\"\"\n        Appends a list of traces of a state transition to the current list\n        \"\"\"\n        if self.traces is None:\n            self.traces = []\n        self.traces.append(new_traces)\n\n    def get_traces(self) -> List[List[List[Dict]]] | None:\n\"\"\"\n        Returns the accumulated traces\n        \"\"\"\n        return self.traces\n\n    def calc_state_root(self, alloc: Any, fork: Fork) -> bytes:\n\"\"\"\n        Calculate the state root for the given `alloc`.\n        \"\"\"\n        env: Dict[str, Any] = {\n            \"currentCoinbase\": \"0x0000000000000000000000000000000000000000\",\n            \"currentDifficulty\": \"0x0\",\n            \"currentGasLimit\": \"0x0\",\n            \"currentNumber\": \"0\",\n            \"currentTimestamp\": \"0\",\n        }\n\n        if fork.header_base_fee_required(0, 0):\n            env[\"currentBaseFee\"] = \"7\"\n\n        if fork.header_prev_randao_required(0, 0):\n            env[\"currentRandom\"] = \"0\"\n\n        if fork.header_withdrawals_required(0, 0):\n            env[\"withdrawals\"] = []\n\n        _, result = self.evaluate(alloc, [], env, fork)\n        state_root = result.get(\"stateRoot\")\n        if state_root is None or not isinstance(state_root, str):\n            raise Exception(\"Unable to calculate state root\")\n        return bytes.fromhex(state_root[2:])\n\n    def calc_withdrawals_root(self, withdrawals: Any, fork: Fork) -> bytes:\n\"\"\"\n        Calculate the state root for the given `alloc`.\n        \"\"\"\n        if type(withdrawals) is list and len(withdrawals) == 0:\n            # Optimize returning the empty root immediately\n            return bytes.fromhex(\n                \"56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\"\n            )\n\n        env: Dict[str, Any] = {\n            \"currentCoinbase\": \"0x0000000000000000000000000000000000000000\",\n            \"currentDifficulty\": \"0x0\",\n            \"currentGasLimit\": \"0x0\",\n            \"currentNumber\": \"0\",\n            \"currentTimestamp\": \"0\",\n            \"withdrawals\": withdrawals,\n        }\n\n        if fork.header_base_fee_required(0, 0):\n            env[\"currentBaseFee\"] = \"7\"\n\n        if fork.header_prev_randao_required(0, 0):\n            env[\"currentRandom\"] = \"0\"\n\n        if fork.header_excess_data_gas_required(0, 0):\n            env[\"currentExcessDataGas\"] = \"0\"\n\n        _, result = self.evaluate({}, [], env, fork)\n        withdrawals_root = result.get(\"withdrawalsRoot\")\n        if withdrawals_root is None:\n            raise Exception(\n                \"Unable to calculate withdrawals root: no value returned from transition tool\"\n            )\n        if type(withdrawals_root) is not str:\n            raise Exception(\n                \"Unable to calculate withdrawals root: \"\n                + \"incorrect type returned from transition tool: \"\n                + f\"{withdrawals_root}\"\n            )\n        return bytes.fromhex(withdrawals_root[2:])\n
"},{"location":"library/pytest_plugins/test_filler/#evm_transition_tool.transition_tool.TransitionTool.__init__","title":"__init__(*, binary=None, trace=False) abstractmethod","text":"

Abstract initialization method that all subclasses must implement.

Source code in src/evm_transition_tool/transition_tool.py
@abstractmethod\ndef __init__(\n    self,\n    *,\n    binary: Optional[Path] = None,\n    trace: bool = False,\n):\n\"\"\"\n    Abstract initialization method that all subclasses must implement.\n    \"\"\"\n    if binary is None:\n        binary = self.default_binary\n    else:\n        # improve behavior of which by resolving the path: ~/relative paths don't work\n        resolved_path = Path(os.path.expanduser(binary)).resolve()\n        if resolved_path.exists():\n            binary = resolved_path\n    binary = shutil.which(binary)  # type: ignore\n    if not binary:\n        raise TransitionToolNotFoundInPath(binary=binary)\n    self.binary = Path(binary)\n    self.trace = trace\n
"},{"location":"library/pytest_plugins/test_filler/#evm_transition_tool.transition_tool.TransitionTool.__init_subclass__","title":"__init_subclass__()","text":"

Registers all subclasses of TransitionTool as possible tools.

Source code in src/evm_transition_tool/transition_tool.py
def __init_subclass__(cls):\n\"\"\"\n    Registers all subclasses of TransitionTool as possible tools.\n    \"\"\"\n    TransitionTool.register_tool(cls)\n
"},{"location":"library/pytest_plugins/test_filler/#evm_transition_tool.transition_tool.TransitionTool.register_tool","title":"register_tool(tool_subclass) classmethod","text":"

Registers a given subclass as tool option.

Source code in src/evm_transition_tool/transition_tool.py
@classmethod\ndef register_tool(cls, tool_subclass: Type[\"TransitionTool\"]):\n\"\"\"\n    Registers a given subclass as tool option.\n    \"\"\"\n    cls.registered_tools.append(tool_subclass)\n
"},{"location":"library/pytest_plugins/test_filler/#evm_transition_tool.transition_tool.TransitionTool.set_default_tool","title":"set_default_tool(tool_subclass) classmethod","text":"

Registers the default tool subclass.

Source code in src/evm_transition_tool/transition_tool.py
@classmethod\ndef set_default_tool(cls, tool_subclass: Type[\"TransitionTool\"]):\n\"\"\"\n    Registers the default tool subclass.\n    \"\"\"\n    cls.default_tool = tool_subclass\n
"},{"location":"library/pytest_plugins/test_filler/#evm_transition_tool.transition_tool.TransitionTool.from_binary_path","title":"from_binary_path(*, binary_path, **kwargs) classmethod","text":"

Instantiates the appropriate TransitionTool subclass derived from the tool's binary path.

Source code in src/evm_transition_tool/transition_tool.py
@classmethod\ndef from_binary_path(cls, *, binary_path: Optional[Path], **kwargs) -> \"TransitionTool\":\n\"\"\"\n    Instantiates the appropriate TransitionTool subclass derived from the\n    tool's binary path.\n    \"\"\"\n    assert cls.default_tool is not None, \"default transition tool was never set\"\n\n    if binary_path is None:\n        return cls.default_tool(binary=binary_path, **kwargs)\n\n    resolved_path = Path(os.path.expanduser(binary_path)).resolve()\n    if resolved_path.exists():\n        binary_path = resolved_path\n    binary = shutil.which(binary_path)  # type: ignore\n\n    if not binary:\n        raise TransitionToolNotFoundInPath(binary=binary)\n\n    binary = Path(binary)\n\n    # Group the tools by version flag, so we only have to call the tool once for all the\n    # classes that share the same version flag\n    for version_flag, subclasses in groupby(\n        cls.registered_tools, key=lambda x: x.version_flag\n    ):\n        try:\n            with os.popen(f\"{binary} {version_flag}\") as f:\n                binary_output = f.read()\n        except Exception:\n            # If the tool doesn't support the version flag,\n            # we'll get an non-zero exit code.\n            continue\n        for subclass in subclasses:\n            if subclass.detect_binary(binary_output):\n                return subclass(binary=binary, **kwargs)\n\n    raise UnknownTransitionTool(f\"Unknown transition tool binary: {binary_path}\")\n
"},{"location":"library/pytest_plugins/test_filler/#evm_transition_tool.transition_tool.TransitionTool.detect_binary","title":"detect_binary(binary_output) classmethod","text":"

Returns True if the binary matches the tool

Source code in src/evm_transition_tool/transition_tool.py
@classmethod\ndef detect_binary(cls, binary_output: str) -> bool:\n\"\"\"\n    Returns True if the binary matches the tool\n    \"\"\"\n    assert cls.detect_binary_pattern is not None\n\n    return cls.detect_binary_pattern.match(binary_output) is not None\n
"},{"location":"library/pytest_plugins/test_filler/#evm_transition_tool.transition_tool.TransitionTool.evaluate","title":"evaluate(alloc, txs, env, fork, chain_id=1, reward=0, eips=None) abstractmethod","text":"

Simulate a state transition with specified parameters

Source code in src/evm_transition_tool/transition_tool.py
@abstractmethod\ndef evaluate(\n    self,\n    alloc: Any,\n    txs: Any,\n    env: Any,\n    fork: Fork,\n    chain_id: int = 1,\n    reward: int = 0,\n    eips: Optional[List[int]] = None,\n) -> Tuple[Dict[str, Any], Dict[str, Any]]:\n\"\"\"\n    Simulate a state transition with specified parameters\n    \"\"\"\n    pass\n
"},{"location":"library/pytest_plugins/test_filler/#evm_transition_tool.transition_tool.TransitionTool.version","title":"version() abstractmethod","text":"

Return name and version of tool used to state transition

Source code in src/evm_transition_tool/transition_tool.py
@abstractmethod\ndef version(self) -> str:\n\"\"\"\n    Return name and version of tool used to state transition\n    \"\"\"\n    pass\n
"},{"location":"library/pytest_plugins/test_filler/#evm_transition_tool.transition_tool.TransitionTool.is_fork_supported","title":"is_fork_supported(fork) abstractmethod","text":"

Returns True if the fork is supported by the tool

Source code in src/evm_transition_tool/transition_tool.py
@abstractmethod\ndef is_fork_supported(self, fork: Fork) -> bool:\n\"\"\"\n    Returns True if the fork is supported by the tool\n    \"\"\"\n    pass\n
"},{"location":"library/pytest_plugins/test_filler/#evm_transition_tool.transition_tool.TransitionTool.reset_traces","title":"reset_traces()","text":"

Resets the internal trace storage for a new test to begin

Source code in src/evm_transition_tool/transition_tool.py
def reset_traces(self):\n\"\"\"\n    Resets the internal trace storage for a new test to begin\n    \"\"\"\n    self.traces = None\n
"},{"location":"library/pytest_plugins/test_filler/#evm_transition_tool.transition_tool.TransitionTool.append_traces","title":"append_traces(new_traces)","text":"

Appends a list of traces of a state transition to the current list

Source code in src/evm_transition_tool/transition_tool.py
def append_traces(self, new_traces: List[List[Dict]]):\n\"\"\"\n    Appends a list of traces of a state transition to the current list\n    \"\"\"\n    if self.traces is None:\n        self.traces = []\n    self.traces.append(new_traces)\n
"},{"location":"library/pytest_plugins/test_filler/#evm_transition_tool.transition_tool.TransitionTool.get_traces","title":"get_traces()","text":"

Returns the accumulated traces

Source code in src/evm_transition_tool/transition_tool.py
def get_traces(self) -> List[List[List[Dict]]] | None:\n\"\"\"\n    Returns the accumulated traces\n    \"\"\"\n    return self.traces\n
"},{"location":"library/pytest_plugins/test_filler/#evm_transition_tool.transition_tool.TransitionTool.calc_state_root","title":"calc_state_root(alloc, fork)","text":"

Calculate the state root for the given alloc.

Source code in src/evm_transition_tool/transition_tool.py
def calc_state_root(self, alloc: Any, fork: Fork) -> bytes:\n\"\"\"\n    Calculate the state root for the given `alloc`.\n    \"\"\"\n    env: Dict[str, Any] = {\n        \"currentCoinbase\": \"0x0000000000000000000000000000000000000000\",\n        \"currentDifficulty\": \"0x0\",\n        \"currentGasLimit\": \"0x0\",\n        \"currentNumber\": \"0\",\n        \"currentTimestamp\": \"0\",\n    }\n\n    if fork.header_base_fee_required(0, 0):\n        env[\"currentBaseFee\"] = \"7\"\n\n    if fork.header_prev_randao_required(0, 0):\n        env[\"currentRandom\"] = \"0\"\n\n    if fork.header_withdrawals_required(0, 0):\n        env[\"withdrawals\"] = []\n\n    _, result = self.evaluate(alloc, [], env, fork)\n    state_root = result.get(\"stateRoot\")\n    if state_root is None or not isinstance(state_root, str):\n        raise Exception(\"Unable to calculate state root\")\n    return bytes.fromhex(state_root[2:])\n
"},{"location":"library/pytest_plugins/test_filler/#evm_transition_tool.transition_tool.TransitionTool.calc_withdrawals_root","title":"calc_withdrawals_root(withdrawals, fork)","text":"

Calculate the state root for the given alloc.

Source code in src/evm_transition_tool/transition_tool.py
def calc_withdrawals_root(self, withdrawals: Any, fork: Fork) -> bytes:\n\"\"\"\n    Calculate the state root for the given `alloc`.\n    \"\"\"\n    if type(withdrawals) is list and len(withdrawals) == 0:\n        # Optimize returning the empty root immediately\n        return bytes.fromhex(\n            \"56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\"\n        )\n\n    env: Dict[str, Any] = {\n        \"currentCoinbase\": \"0x0000000000000000000000000000000000000000\",\n        \"currentDifficulty\": \"0x0\",\n        \"currentGasLimit\": \"0x0\",\n        \"currentNumber\": \"0\",\n        \"currentTimestamp\": \"0\",\n        \"withdrawals\": withdrawals,\n    }\n\n    if fork.header_base_fee_required(0, 0):\n        env[\"currentBaseFee\"] = \"7\"\n\n    if fork.header_prev_randao_required(0, 0):\n        env[\"currentRandom\"] = \"0\"\n\n    if fork.header_excess_data_gas_required(0, 0):\n        env[\"currentExcessDataGas\"] = \"0\"\n\n    _, result = self.evaluate({}, [], env, fork)\n    withdrawals_root = result.get(\"withdrawalsRoot\")\n    if withdrawals_root is None:\n        raise Exception(\n            \"Unable to calculate withdrawals root: no value returned from transition tool\"\n        )\n    if type(withdrawals_root) is not str:\n        raise Exception(\n            \"Unable to calculate withdrawals root: \"\n            + \"incorrect type returned from transition tool: \"\n            + f\"{withdrawals_root}\"\n        )\n    return bytes.fromhex(withdrawals_root[2:])\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.pytest_addoption","title":"pytest_addoption(parser)","text":"

Adds command-line options to pytest.

Source code in src/pytest_plugins/test_filler/test_filler.py
def pytest_addoption(parser):\n\"\"\"\n    Adds command-line options to pytest.\n    \"\"\"\n    evm_group = parser.getgroup(\"evm\", \"Arguments defining evm executable behavior\")\n    evm_group.addoption(\n        \"--evm-bin\",\n        action=\"store\",\n        dest=\"evm_bin\",\n        type=Path,\n        default=None,\n        help=(\n            \"Path to an evm executable that provides `t8n`. \" \"Default: First 'evm' entry in PATH\"\n        ),\n    )\n    evm_group.addoption(\n        \"--traces\",\n        action=\"store_true\",\n        dest=\"evm_collect_traces\",\n        default=None,\n        help=\"Collect traces of the execution information from the \" + \"transition tool\",\n    )\n\n    solc_group = parser.getgroup(\"solc\", \"Arguments defining the solc executable\")\n    solc_group.addoption(\n        \"--solc-bin\",\n        action=\"store\",\n        dest=\"solc_bin\",\n        default=None,\n        help=(\n            \"Path to a solc executable (for Yul source compilation). \"\n            \"Default: First 'solc' entry in PATH\"\n        ),\n    )\n\n    test_group = parser.getgroup(\"tests\", \"Arguments defining filler location and output\")\n    test_group.addoption(\n        \"--filler-path\",\n        action=\"store\",\n        dest=\"filler_path\",\n        default=\"./tests/\",\n        help=\"Path to filler directives\",\n    )\n    test_group.addoption(\n        \"--output\",\n        action=\"store\",\n        dest=\"output\",\n        default=\"./fixtures/\",\n        help=\"Directory to store the generated test fixtures. Can be deleted.\",\n    )\n    test_group.addoption(\n        \"--flat-output\",\n        action=\"store_true\",\n        dest=\"flat_output\",\n        default=False,\n        help=\"Output each test case in the directory without the folder structure.\",\n    )\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.StateTest","title":"StateTest dataclass","text":"

Bases: BaseTest

Filler type that tests transactions over the period of a single block.

Source code in src/ethereum_test_tools/spec/state_test.py
@dataclass(kw_only=True)\nclass StateTest(BaseTest):\n\"\"\"\n    Filler type that tests transactions over the period of a single block.\n    \"\"\"\n\n    env: Environment\n    pre: Mapping[str, Account]\n    post: Mapping[str, Account]\n    txs: List[Transaction]\n    engine_api_error_code: Optional[EngineAPIError] = None\n    tag: str = \"\"\n\n    @classmethod\n    def pytest_parameter_name(cls) -> str:\n\"\"\"\n        Returns the parameter name used to identify this filler in a test.\n        \"\"\"\n        return \"state_test\"\n\n    def make_genesis(\n        self,\n        t8n: TransitionTool,\n        fork: Fork,\n    ) -> Tuple[bytes, FixtureHeader]:\n\"\"\"\n        Create a genesis block from the state test definition.\n        \"\"\"\n        env = self.env.set_fork_requirements(fork)\n\n        genesis = FixtureHeader(\n            parent_hash=EmptyHash,\n            ommers_hash=EmptyOmmersRoot,\n            coinbase=ZeroAddress,\n            state_root=t8n.calc_state_root(\n                to_json(self.pre),\n                fork,\n            ),\n            transactions_root=EmptyTrieRoot,\n            receipt_root=EmptyTrieRoot,\n            bloom=EmptyBloom,\n            difficulty=0x20000 if env.difficulty is None else env.difficulty,\n            number=env.number - 1,\n            gas_limit=env.gas_limit,\n            gas_used=0,\n            timestamp=0,\n            extra_data=bytes([0]),\n            mix_digest=EmptyHash,\n            nonce=EmptyNonce,\n            base_fee=env.base_fee,\n            data_gas_used=env.data_gas_used,\n            excess_data_gas=env.excess_data_gas,\n            withdrawals_root=t8n.calc_withdrawals_root(env.withdrawals, fork)\n            if env.withdrawals is not None\n            else None,\n        )\n\n        genesis_rlp, genesis.hash = genesis.build(\n            txs=[],\n            ommers=[],\n            withdrawals=env.withdrawals,\n        )\n\n        return genesis_rlp, genesis\n\n    def make_blocks(\n        self,\n        t8n: TransitionTool,\n        genesis: FixtureHeader,\n        fork: Fork,\n        chain_id=1,\n        eips: Optional[List[int]] = None,\n    ) -> Tuple[List[FixtureBlock], bytes, Dict[str, Any]]:\n\"\"\"\n        Create a block from the state test definition.\n        Performs checks against the expected behavior of the test.\n        Raises exception on invalid test behavior.\n        \"\"\"\n        env = self.env.apply_new_parent(genesis)\n        env = env.set_fork_requirements(fork)\n\n        txs = [tx.with_signature_and_sender() for tx in self.txs] if self.txs is not None else []\n\n        alloc, result = t8n.evaluate(\n            alloc=to_json(self.pre),\n            txs=to_json(txs),\n            env=to_json(env),\n            fork=fork,\n            chain_id=chain_id,\n            reward=fork.get_reward(env.number, env.timestamp),\n            eips=eips,\n        )\n\n        rejected_txs = verify_transactions(txs, result)\n        if len(rejected_txs) > 0:\n            raise Exception(\n                \"one or more transactions in `StateTest` are \"\n                + \"intrinsically invalid, which are not allowed. \"\n                + \"Use `BlockchainTest` to verify rejection of blocks \"\n                + \"that include invalid transactions.\"\n            )\n\n        try:\n            verify_post_alloc(self.post, alloc)\n        except Exception as e:\n            print_traces(traces=t8n.get_traces())\n            raise e\n\n        header = FixtureHeader.from_dict(\n            result\n            | {\n                \"parentHash\": genesis.hash,\n                \"miner\": env.coinbase,\n                \"transactionsRoot\": result.get(\"txRoot\"),\n                \"difficulty\": str_or_none(env.difficulty, result.get(\"currentDifficulty\")),\n                \"number\": str(env.number),\n                \"gasLimit\": str(env.gas_limit),\n                \"timestamp\": str(env.timestamp),\n                \"extraData\": \"0x00\",\n                \"sha3Uncles\": \"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\n                \"mixHash\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n                \"nonce\": \"0x0000000000000000\",\n                \"baseFeePerGas\": result.get(\"currentBaseFee\"),\n                \"excessDataGas\": result.get(\"currentExcessDataGas\"),\n            }\n        )\n\n        block, header.hash = header.build(\n            txs=txs,\n            ommers=[],\n            withdrawals=env.withdrawals,\n        )\n\n        new_payload = FixtureEngineNewPayload.from_fixture_header(\n            fork=fork,\n            header=header,\n            transactions=txs,\n            withdrawals=env.withdrawals,\n            error_code=self.engine_api_error_code,\n        )\n\n        return (\n            [\n                FixtureBlock(\n                    rlp=block,\n                    new_payload=new_payload,\n                    block_header=header,\n                    txs=txs,\n                    ommers=[],\n                    withdrawals=env.withdrawals,\n                )\n            ],\n            header.hash,\n            alloc,\n        )\n
"},{"location":"library/pytest_plugins/test_filler/#ethereum_test_tools.spec.state_test.StateTest.pytest_parameter_name","title":"pytest_parameter_name() classmethod","text":"

Returns the parameter name used to identify this filler in a test.

Source code in src/ethereum_test_tools/spec/state_test.py
@classmethod\ndef pytest_parameter_name(cls) -> str:\n\"\"\"\n    Returns the parameter name used to identify this filler in a test.\n    \"\"\"\n    return \"state_test\"\n
"},{"location":"library/pytest_plugins/test_filler/#ethereum_test_tools.spec.state_test.StateTest.make_genesis","title":"make_genesis(t8n, fork)","text":"

Create a genesis block from the state test definition.

Source code in src/ethereum_test_tools/spec/state_test.py
def make_genesis(\n    self,\n    t8n: TransitionTool,\n    fork: Fork,\n) -> Tuple[bytes, FixtureHeader]:\n\"\"\"\n    Create a genesis block from the state test definition.\n    \"\"\"\n    env = self.env.set_fork_requirements(fork)\n\n    genesis = FixtureHeader(\n        parent_hash=EmptyHash,\n        ommers_hash=EmptyOmmersRoot,\n        coinbase=ZeroAddress,\n        state_root=t8n.calc_state_root(\n            to_json(self.pre),\n            fork,\n        ),\n        transactions_root=EmptyTrieRoot,\n        receipt_root=EmptyTrieRoot,\n        bloom=EmptyBloom,\n        difficulty=0x20000 if env.difficulty is None else env.difficulty,\n        number=env.number - 1,\n        gas_limit=env.gas_limit,\n        gas_used=0,\n        timestamp=0,\n        extra_data=bytes([0]),\n        mix_digest=EmptyHash,\n        nonce=EmptyNonce,\n        base_fee=env.base_fee,\n        data_gas_used=env.data_gas_used,\n        excess_data_gas=env.excess_data_gas,\n        withdrawals_root=t8n.calc_withdrawals_root(env.withdrawals, fork)\n        if env.withdrawals is not None\n        else None,\n    )\n\n    genesis_rlp, genesis.hash = genesis.build(\n        txs=[],\n        ommers=[],\n        withdrawals=env.withdrawals,\n    )\n\n    return genesis_rlp, genesis\n
"},{"location":"library/pytest_plugins/test_filler/#ethereum_test_tools.spec.state_test.StateTest.make_blocks","title":"make_blocks(t8n, genesis, fork, chain_id=1, eips=None)","text":"

Create a block from the state test definition. Performs checks against the expected behavior of the test. Raises exception on invalid test behavior.

Source code in src/ethereum_test_tools/spec/state_test.py
def make_blocks(\n    self,\n    t8n: TransitionTool,\n    genesis: FixtureHeader,\n    fork: Fork,\n    chain_id=1,\n    eips: Optional[List[int]] = None,\n) -> Tuple[List[FixtureBlock], bytes, Dict[str, Any]]:\n\"\"\"\n    Create a block from the state test definition.\n    Performs checks against the expected behavior of the test.\n    Raises exception on invalid test behavior.\n    \"\"\"\n    env = self.env.apply_new_parent(genesis)\n    env = env.set_fork_requirements(fork)\n\n    txs = [tx.with_signature_and_sender() for tx in self.txs] if self.txs is not None else []\n\n    alloc, result = t8n.evaluate(\n        alloc=to_json(self.pre),\n        txs=to_json(txs),\n        env=to_json(env),\n        fork=fork,\n        chain_id=chain_id,\n        reward=fork.get_reward(env.number, env.timestamp),\n        eips=eips,\n    )\n\n    rejected_txs = verify_transactions(txs, result)\n    if len(rejected_txs) > 0:\n        raise Exception(\n            \"one or more transactions in `StateTest` are \"\n            + \"intrinsically invalid, which are not allowed. \"\n            + \"Use `BlockchainTest` to verify rejection of blocks \"\n            + \"that include invalid transactions.\"\n        )\n\n    try:\n        verify_post_alloc(self.post, alloc)\n    except Exception as e:\n        print_traces(traces=t8n.get_traces())\n        raise e\n\n    header = FixtureHeader.from_dict(\n        result\n        | {\n            \"parentHash\": genesis.hash,\n            \"miner\": env.coinbase,\n            \"transactionsRoot\": result.get(\"txRoot\"),\n            \"difficulty\": str_or_none(env.difficulty, result.get(\"currentDifficulty\")),\n            \"number\": str(env.number),\n            \"gasLimit\": str(env.gas_limit),\n            \"timestamp\": str(env.timestamp),\n            \"extraData\": \"0x00\",\n            \"sha3Uncles\": \"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\n            \"mixHash\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n            \"nonce\": \"0x0000000000000000\",\n            \"baseFeePerGas\": result.get(\"currentBaseFee\"),\n            \"excessDataGas\": result.get(\"currentExcessDataGas\"),\n        }\n    )\n\n    block, header.hash = header.build(\n        txs=txs,\n        ommers=[],\n        withdrawals=env.withdrawals,\n    )\n\n    new_payload = FixtureEngineNewPayload.from_fixture_header(\n        fork=fork,\n        header=header,\n        transactions=txs,\n        withdrawals=env.withdrawals,\n        error_code=self.engine_api_error_code,\n    )\n\n    return (\n        [\n            FixtureBlock(\n                rlp=block,\n                new_payload=new_payload,\n                block_header=header,\n                txs=txs,\n                ommers=[],\n                withdrawals=env.withdrawals,\n            )\n        ],\n        header.hash,\n        alloc,\n    )\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.Yul","title":"Yul","text":"

Bases: Code

Yul compiler. Compiles Yul source code into bytecode.

Source code in src/ethereum_test_tools/code/yul.py
class Yul(Code):\n\"\"\"\n    Yul compiler.\n    Compiles Yul source code into bytecode.\n    \"\"\"\n\n    source: str\n    compiled: Optional[bytes] = None\n\n    def __init__(\n        self,\n        source: str,\n        fork: Optional[Fork] = None,\n        binary: Optional[Path | str] = None,\n    ):\n        self.source = source\n        self.evm_version = get_evm_version_from_fork(fork)\n        if binary is None:\n            which_path = which(\"solc\")\n            if which_path is not None:\n                binary = Path(which_path)\n        if binary is None or not Path(binary).exists():\n            raise Exception(\n\"\"\"`solc` binary executable not found, please refer to\n                https://docs.soliditylang.org/en/latest/installing-solidity.html\n                for help downloading and installing `solc`\"\"\"\n            )\n        self.binary = Path(binary)\n\n    def assemble(self) -> bytes:\n\"\"\"\n        Assembles using `solc --assemble`.\n        \"\"\"\n        if not self.compiled:\n            solc_args: Tuple[Union[Path, str], ...] = ()\n            if self.evm_version:\n                solc_args = (\n                    self.binary,\n                    \"--evm-version\",\n                    self.evm_version,\n                    *DEFAULT_SOLC_ARGS,\n                )\n            else:\n                solc_args = (self.binary, *DEFAULT_SOLC_ARGS)\n            result = run(\n                solc_args,\n                input=str.encode(self.source),\n                stdout=PIPE,\n                stderr=PIPE,\n            )\n\n            if result.returncode != 0:\n                stderr_lines = result.stderr.decode().split(\"\\n\")\n                stderr_message = \"\\n\".join(line.strip() for line in stderr_lines)\n                raise Exception(f\"failed to compile yul source:\\n{stderr_message[7:]}\")\n\n            lines = result.stdout.decode().split(\"\\n\")\n\n            hex_str = lines[lines.index(\"Binary representation:\") + 1]\n\n            self.compiled = bytes.fromhex(hex_str)\n        return self.compiled\n\n    def version(self) -> str:\n\"\"\"\n        Return solc's version string\n        \"\"\"\n        result = run(\n            [self.binary, \"--version\"],\n            stdout=PIPE,\n            stderr=PIPE,\n        )\n        solc_output = result.stdout.decode().split(\"\\n\")\n        version_pattern = r\"0\\.\\d+\\.\\d+\\+\\S+\"\n        solc_version_string = None\n        for line in solc_output:\n            match = re.search(version_pattern, line)\n            if match:\n                solc_version_string = match.group(0)\n                break\n        if not solc_version_string:\n            warnings.warn(\"Unable to determine solc version.\")\n            solc_version_string = \"unknown\"\n        return solc_version_string\n
"},{"location":"library/pytest_plugins/test_filler/#ethereum_test_tools.code.yul.Yul.assemble","title":"assemble()","text":"

Assembles using solc --assemble.

Source code in src/ethereum_test_tools/code/yul.py
def assemble(self) -> bytes:\n\"\"\"\n    Assembles using `solc --assemble`.\n    \"\"\"\n    if not self.compiled:\n        solc_args: Tuple[Union[Path, str], ...] = ()\n        if self.evm_version:\n            solc_args = (\n                self.binary,\n                \"--evm-version\",\n                self.evm_version,\n                *DEFAULT_SOLC_ARGS,\n            )\n        else:\n            solc_args = (self.binary, *DEFAULT_SOLC_ARGS)\n        result = run(\n            solc_args,\n            input=str.encode(self.source),\n            stdout=PIPE,\n            stderr=PIPE,\n        )\n\n        if result.returncode != 0:\n            stderr_lines = result.stderr.decode().split(\"\\n\")\n            stderr_message = \"\\n\".join(line.strip() for line in stderr_lines)\n            raise Exception(f\"failed to compile yul source:\\n{stderr_message[7:]}\")\n\n        lines = result.stdout.decode().split(\"\\n\")\n\n        hex_str = lines[lines.index(\"Binary representation:\") + 1]\n\n        self.compiled = bytes.fromhex(hex_str)\n    return self.compiled\n
"},{"location":"library/pytest_plugins/test_filler/#ethereum_test_tools.code.yul.Yul.version","title":"version()","text":"

Return solc's version string

Source code in src/ethereum_test_tools/code/yul.py
def version(self) -> str:\n\"\"\"\n    Return solc's version string\n    \"\"\"\n    result = run(\n        [self.binary, \"--version\"],\n        stdout=PIPE,\n        stderr=PIPE,\n    )\n    solc_output = result.stdout.decode().split(\"\\n\")\n    version_pattern = r\"0\\.\\d+\\.\\d+\\+\\S+\"\n    solc_version_string = None\n    for line in solc_output:\n        match = re.search(version_pattern, line)\n        if match:\n            solc_version_string = match.group(0)\n            break\n    if not solc_version_string:\n        warnings.warn(\"Unable to determine solc version.\")\n        solc_version_string = \"unknown\"\n    return solc_version_string\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.BaseTest","title":"BaseTest","text":"

Represents a base Ethereum test which must return a genesis and a blockchain.

Source code in src/ethereum_test_tools/spec/base_test.py
class BaseTest:\n\"\"\"\n    Represents a base Ethereum test which must return a genesis and a\n    blockchain.\n    \"\"\"\n\n    pre: Mapping[str, Account]\n    tag: str = \"\"\n\n    @abstractmethod\n    def make_genesis(\n        self,\n        t8n: TransitionTool,\n        fork: Fork,\n    ) -> Tuple[bytes, FixtureHeader]:\n\"\"\"\n        Create a genesis block from the test definition.\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def make_blocks(\n        self,\n        t8n: TransitionTool,\n        genesis: FixtureHeader,\n        fork: Fork,\n        chain_id: int = 1,\n        eips: Optional[List[int]] = None,\n    ) -> Tuple[List[FixtureBlock], bytes, Dict[str, Any]]:\n\"\"\"\n        Generate the blockchain that must be executed sequentially during test.\n        \"\"\"\n        pass\n\n    @classmethod\n    @abstractmethod\n    def pytest_parameter_name(cls) -> str:\n\"\"\"\n        Must return the name of the parameter used in pytest to select this\n        spec type as filler for the test.\n        \"\"\"\n        pass\n
"},{"location":"library/pytest_plugins/test_filler/#ethereum_test_tools.spec.base_test.BaseTest.make_genesis","title":"make_genesis(t8n, fork) abstractmethod","text":"

Create a genesis block from the test definition.

Source code in src/ethereum_test_tools/spec/base_test.py
@abstractmethod\ndef make_genesis(\n    self,\n    t8n: TransitionTool,\n    fork: Fork,\n) -> Tuple[bytes, FixtureHeader]:\n\"\"\"\n    Create a genesis block from the test definition.\n    \"\"\"\n    pass\n
"},{"location":"library/pytest_plugins/test_filler/#ethereum_test_tools.spec.base_test.BaseTest.make_blocks","title":"make_blocks(t8n, genesis, fork, chain_id=1, eips=None) abstractmethod","text":"

Generate the blockchain that must be executed sequentially during test.

Source code in src/ethereum_test_tools/spec/base_test.py
@abstractmethod\ndef make_blocks(\n    self,\n    t8n: TransitionTool,\n    genesis: FixtureHeader,\n    fork: Fork,\n    chain_id: int = 1,\n    eips: Optional[List[int]] = None,\n) -> Tuple[List[FixtureBlock], bytes, Dict[str, Any]]:\n\"\"\"\n    Generate the blockchain that must be executed sequentially during test.\n    \"\"\"\n    pass\n
"},{"location":"library/pytest_plugins/test_filler/#ethereum_test_tools.spec.base_test.BaseTest.pytest_parameter_name","title":"pytest_parameter_name() classmethod abstractmethod","text":"

Must return the name of the parameter used in pytest to select this spec type as filler for the test.

Source code in src/ethereum_test_tools/spec/base_test.py
@classmethod\n@abstractmethod\ndef pytest_parameter_name(cls) -> str:\n\"\"\"\n    Must return the name of the parameter used in pytest to select this\n    spec type as filler for the test.\n    \"\"\"\n    pass\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.pytest_configure","title":"pytest_configure(config)","text":"

Register the plugin's custom markers and process command-line options.

Custom marker registration: https://docs.pytest.org/en/7.1.x/how-to/writing_plugins.html#registering-custom-markers

Source code in src/pytest_plugins/test_filler/test_filler.py
@pytest.hookimpl(tryfirst=True)\ndef pytest_configure(config):\n\"\"\"\n    Register the plugin's custom markers and process command-line options.\n\n    Custom marker registration:\n    https://docs.pytest.org/en/7.1.x/how-to/writing_plugins.html#registering-custom-markers\n    \"\"\"\n    config.addinivalue_line(\n        \"markers\",\n        \"state_test: a test case that implement a single state transition test.\",\n    )\n    config.addinivalue_line(\n        \"markers\",\n        \"blockchain_test: a test case that implements a block transition test.\",\n    )\n    config.addinivalue_line(\n        \"markers\",\n        \"yul_test: a test case that compiles Yul code.\",\n    )\n    config.addinivalue_line(\n        \"markers\",\n        \"compile_yul_with(fork): Always compile Yul source using the corresponding evm version.\",\n    )\n    if config.option.collectonly:\n        return\n    # Instantiate the transition tool here to check that the binary path/trace option is valid.\n    # This ensures we only raise an error once, if appropriate, instead of for every test.\n    TransitionTool.from_binary_path(\n        binary_path=config.getoption(\"evm_bin\"), trace=config.getoption(\"evm_collect_traces\")\n    )\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.EIPSpecTestItem","title":"EIPSpecTestItem","text":"

Bases: Item

Custom pytest test item to test EIP spec versions.

Source code in src/pytest_plugins/spec_version_checker/spec_version_checker.py
class EIPSpecTestItem(Item):\n\"\"\"\n    Custom pytest test item to test EIP spec versions.\n    \"\"\"\n\n    def __init__(self, name, parent, module):\n        super().__init__(name, parent)\n        self.module = module\n\n    @classmethod\n    def from_parent(cls, parent, module):\n\"\"\"\n        Public constructor to define new tests.\n        https://docs.pytest.org/en/latest/reference/reference.html#pytest.nodes.Node.from_parent\n        \"\"\"\n        return super().from_parent(parent=parent, name=\"test_eip_spec_version\", module=module)\n\n    def runtest(self):\n\"\"\"\n        Define the test to execute for this item.\n        \"\"\"\n        test_eip_spec_version(self.module)\n\n    def reportinfo(self):\n\"\"\"\n        Get location information for this test item to use test reports.\n        \"\"\"\n        return \"spec_version_checker\", 0, f\"{self.name}\"\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.spec_version_checker.spec_version_checker.EIPSpecTestItem.from_parent","title":"from_parent(parent, module) classmethod","text":"

Public constructor to define new tests. https://docs.pytest.org/en/latest/reference/reference.html#pytest.nodes.Node.from_parent

Source code in src/pytest_plugins/spec_version_checker/spec_version_checker.py
@classmethod\ndef from_parent(cls, parent, module):\n\"\"\"\n    Public constructor to define new tests.\n    https://docs.pytest.org/en/latest/reference/reference.html#pytest.nodes.Node.from_parent\n    \"\"\"\n    return super().from_parent(parent=parent, name=\"test_eip_spec_version\", module=module)\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.spec_version_checker.spec_version_checker.EIPSpecTestItem.runtest","title":"runtest()","text":"

Define the test to execute for this item.

Source code in src/pytest_plugins/spec_version_checker/spec_version_checker.py
def runtest(self):\n\"\"\"\n    Define the test to execute for this item.\n    \"\"\"\n    test_eip_spec_version(self.module)\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.spec_version_checker.spec_version_checker.EIPSpecTestItem.reportinfo","title":"reportinfo()","text":"

Get location information for this test item to use test reports.

Source code in src/pytest_plugins/spec_version_checker/spec_version_checker.py
def reportinfo(self):\n\"\"\"\n    Get location information for this test item to use test reports.\n    \"\"\"\n    return \"spec_version_checker\", 0, f\"{self.name}\"\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.pytest_report_header","title":"pytest_report_header(config, start_path)","text":"

Add lines to pytest's console output header

Source code in src/pytest_plugins/test_filler/test_filler.py
@pytest.hookimpl(trylast=True)\ndef pytest_report_header(config, start_path):\n\"\"\"Add lines to pytest's console output header\"\"\"\n    if config.option.collectonly:\n        return\n    binary_path = config.getoption(\"evm_bin\")\n    t8n = TransitionTool.from_binary_path(binary_path=binary_path)\n    solc_version_string = Yul(\"\", binary=config.getoption(\"solc_bin\")).version()\n    return [f\"{t8n.version()}, solc version {solc_version_string}\"]\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.evm_bin","title":"evm_bin(request)","text":"

Returns the configured evm tool binary path.

Source code in src/pytest_plugins/test_filler/test_filler.py
@pytest.fixture(autouse=True, scope=\"session\")\ndef evm_bin(request) -> Path:\n\"\"\"\n    Returns the configured evm tool binary path.\n    \"\"\"\n    return request.config.getoption(\"evm_bin\")\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.solc_bin","title":"solc_bin(request)","text":"

Returns the configured solc binary path.

Source code in src/pytest_plugins/test_filler/test_filler.py
@pytest.fixture(autouse=True, scope=\"session\")\ndef solc_bin(request):\n\"\"\"\n    Returns the configured solc binary path.\n    \"\"\"\n    return request.config.getoption(\"solc_bin\")\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.t8n","title":"t8n(request, evm_bin)","text":"

Returns the configured transition tool.

Source code in src/pytest_plugins/test_filler/test_filler.py
@pytest.fixture(autouse=True, scope=\"session\")\ndef t8n(request, evm_bin: Path) -> TransitionTool:\n\"\"\"\n    Returns the configured transition tool.\n    \"\"\"\n    return TransitionTool.from_binary_path(\n        binary_path=evm_bin, trace=request.config.getoption(\"evm_collect_traces\")\n    )\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.strip_test_prefix","title":"strip_test_prefix(name)","text":"

Removes the test prefix from a test case name.

Source code in src/pytest_plugins/test_filler/test_filler.py
def strip_test_prefix(name: str) -> str:\n\"\"\"\n    Removes the test prefix from a test case name.\n    \"\"\"\n    TEST_PREFIX = \"test_\"\n    if name.startswith(TEST_PREFIX):\n        return name[len(TEST_PREFIX) :]\n    return name\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.FixtureCollector","title":"FixtureCollector","text":"

Collects all fixtures generated by the test cases.

Source code in src/pytest_plugins/test_filler/test_filler.py
class FixtureCollector:\n\"\"\"\n    Collects all fixtures generated by the test cases.\n    \"\"\"\n\n    all_fixtures: Dict[str, List[Tuple[str, Any]]]\n    output_dir: str\n    flat_output: bool\n\n    def __init__(self, output_dir: str, flat_output: bool) -> None:\n        self.all_fixtures = {}\n        self.output_dir = output_dir\n        self.flat_output = flat_output\n\n    def add_fixture(self, item, fixture: Fixture) -> None:\n\"\"\"\n        Adds a fixture to the list of fixtures of a given test case.\n        \"\"\"\n\n        def get_module_dir(item) -> str:\n\"\"\"\n            Returns the directory of the test case module.\n            \"\"\"\n            dirname = os.path.dirname(item.path)\n            basename, _ = os.path.splitext(item.path)\n            basename = strip_test_prefix(os.path.basename(basename))\n            module_path_no_ext = os.path.join(dirname, basename)\n            module_dir = os.path.relpath(\n                module_path_no_ext,\n                item.funcargs[\"filler_path\"],\n            )\n            return module_dir\n\n        module_dir = (\n            strip_test_prefix(item.originalname)\n            if self.flat_output\n            else os.path.join(\n                get_module_dir(item),\n                strip_test_prefix(item.originalname),\n            )\n        )\n        if module_dir not in self.all_fixtures:\n            self.all_fixtures[module_dir] = []\n        m = re.match(r\".*?\\[(.*)\\]\", item.name)\n        if not m:\n            raise Exception(\"Could not parse test name: \" + item.name)\n        name = m.group(1)\n        if fixture.name:\n            name += \"-\" + fixture.name\n        jsonFixture = json.loads(json.dumps(fixture, cls=JSONEncoder))\n        self.all_fixtures[module_dir].append((name, jsonFixture))\n\n    def dump_fixtures(self) -> None:\n\"\"\"\n        Dumps all collected fixtures to their respective files.\n        \"\"\"\n        os.makedirs(self.output_dir, exist_ok=True)\n        for module_file, fixtures in self.all_fixtures.items():\n            output_json = {}\n            for index, name_fixture in enumerate(fixtures):\n                name, fixture = name_fixture\n                name = str(index).zfill(3) + \"-\" + name\n                output_json[name] = fixture\n            file_path = os.path.join(self.output_dir, module_file + \".json\")\n            if not self.flat_output:\n                os.makedirs(os.path.dirname(file_path), exist_ok=True)\n            with open(file_path, \"w\") as f:\n                json.dump(output_json, f, indent=4)\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.FixtureCollector.add_fixture","title":"add_fixture(item, fixture)","text":"

Adds a fixture to the list of fixtures of a given test case.

Source code in src/pytest_plugins/test_filler/test_filler.py
def add_fixture(self, item, fixture: Fixture) -> None:\n\"\"\"\n    Adds a fixture to the list of fixtures of a given test case.\n    \"\"\"\n\n    def get_module_dir(item) -> str:\n\"\"\"\n        Returns the directory of the test case module.\n        \"\"\"\n        dirname = os.path.dirname(item.path)\n        basename, _ = os.path.splitext(item.path)\n        basename = strip_test_prefix(os.path.basename(basename))\n        module_path_no_ext = os.path.join(dirname, basename)\n        module_dir = os.path.relpath(\n            module_path_no_ext,\n            item.funcargs[\"filler_path\"],\n        )\n        return module_dir\n\n    module_dir = (\n        strip_test_prefix(item.originalname)\n        if self.flat_output\n        else os.path.join(\n            get_module_dir(item),\n            strip_test_prefix(item.originalname),\n        )\n    )\n    if module_dir not in self.all_fixtures:\n        self.all_fixtures[module_dir] = []\n    m = re.match(r\".*?\\[(.*)\\]\", item.name)\n    if not m:\n        raise Exception(\"Could not parse test name: \" + item.name)\n    name = m.group(1)\n    if fixture.name:\n        name += \"-\" + fixture.name\n    jsonFixture = json.loads(json.dumps(fixture, cls=JSONEncoder))\n    self.all_fixtures[module_dir].append((name, jsonFixture))\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.FixtureCollector.dump_fixtures","title":"dump_fixtures()","text":"

Dumps all collected fixtures to their respective files.

Source code in src/pytest_plugins/test_filler/test_filler.py
def dump_fixtures(self) -> None:\n\"\"\"\n    Dumps all collected fixtures to their respective files.\n    \"\"\"\n    os.makedirs(self.output_dir, exist_ok=True)\n    for module_file, fixtures in self.all_fixtures.items():\n        output_json = {}\n        for index, name_fixture in enumerate(fixtures):\n            name, fixture = name_fixture\n            name = str(index).zfill(3) + \"-\" + name\n            output_json[name] = fixture\n        file_path = os.path.join(self.output_dir, module_file + \".json\")\n        if not self.flat_output:\n            os.makedirs(os.path.dirname(file_path), exist_ok=True)\n        with open(file_path, \"w\") as f:\n            json.dump(output_json, f, indent=4)\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.fixture_collector","title":"fixture_collector(request)","text":"

Returns the configured fixture collector instance used for all tests in one test module.

Source code in src/pytest_plugins/test_filler/test_filler.py
@pytest.fixture(scope=\"module\")\ndef fixture_collector(request):\n\"\"\"\n    Returns the configured fixture collector instance used for all tests\n    in one test module.\n    \"\"\"\n    fixture_collector = FixtureCollector(\n        output_dir=request.config.getoption(\"output\"),\n        flat_output=request.config.getoption(\"flat_output\"),\n    )\n    yield fixture_collector\n    fixture_collector.dump_fixtures()\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.engine","title":"engine()","text":"

Returns the sealEngine used in the generated test fixtures.

Source code in src/pytest_plugins/test_filler/test_filler.py
@pytest.fixture(autouse=True, scope=\"session\")\ndef engine():\n\"\"\"\n    Returns the sealEngine used in the generated test fixtures.\n    \"\"\"\n    return \"NoProof\"\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.filler_path","title":"filler_path(request)","text":"

Returns the directory containing the tests to execute.

Source code in src/pytest_plugins/test_filler/test_filler.py
@pytest.fixture(autouse=True, scope=\"session\")\ndef filler_path(request):\n\"\"\"\n    Returns the directory containing the tests to execute.\n    \"\"\"\n    return request.config.getoption(\"filler_path\")\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.eips","title":"eips()","text":"

A fixture specifying that, by default, no EIPs should be activated for tests.

This fixture (function) may be redefined in test filler modules in order to overwrite this default and return a list of integers specifying which EIPs should be activated for the tests in scope.

Source code in src/pytest_plugins/test_filler/test_filler.py
@pytest.fixture(autouse=True)\ndef eips():\n\"\"\"\n    A fixture specifying that, by default, no EIPs should be activated for\n    tests.\n\n    This fixture (function) may be redefined in test filler modules in order\n    to overwrite this default and return a list of integers specifying which\n    EIPs should be activated for the tests in scope.\n    \"\"\"\n    return []\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.yul","title":"yul(fork, request)","text":"

A fixture that allows contract code to be defined with Yul code.

This fixture defines a class that wraps the ::ethereum_test_tools.Yul class so that upon instantiation within the test case, it provides the test case's current fork parameter. The forks is then available for use in solc's arguments for the Yul code compilation.

Test cases can override the default value by specifying a fixed version with the @pytest.mark.compile_yul_with(FORK) marker.

Source code in src/pytest_plugins/test_filler/test_filler.py
@pytest.fixture\ndef yul(fork: Fork, request):\n\"\"\"\n    A fixture that allows contract code to be defined with Yul code.\n\n    This fixture defines a class that wraps the ::ethereum_test_tools.Yul\n    class so that upon instantiation within the test case, it provides the\n    test case's current fork parameter. The forks is then available for use\n    in solc's arguments for the Yul code compilation.\n\n    Test cases can override the default value by specifying a fixed version\n    with the @pytest.mark.compile_yul_with(FORK) marker.\n    \"\"\"\n    marker = request.node.get_closest_marker(\"compile_yul_with\")\n    if marker:\n        if not marker.args[0]:\n            pytest.fail(\n                f\"{request.node.name}: Expected one argument in 'compile_yul_with' marker.\"\n            )\n        fork = request.config.fork_map[marker.args[0]]\n\n    class YulWrapper(Yul):\n        def __init__(self, *args, **kwargs):\n            super(YulWrapper, self).__init__(*args, **kwargs, fork=fork)\n\n    return YulWrapper\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.state_test","title":"state_test(request, t8n, fork, engine, reference_spec, eips, fixture_collector)","text":"

Fixture used to instantiate an auto-fillable StateTest object from within a test function.

Every test that defines a StateTest filler must explicitly specify this fixture in its function arguments and set the StateTestWrapper's spec property.

Implementation detail: It must be scoped on test function level to avoid leakage between tests.

Source code in src/pytest_plugins/test_filler/test_filler.py
@pytest.fixture(scope=\"function\")\ndef state_test(\n    request, t8n, fork, engine, reference_spec, eips, fixture_collector\n) -> StateTestFiller:\n\"\"\"\n    Fixture used to instantiate an auto-fillable StateTest object from within\n    a test function.\n\n    Every test that defines a StateTest filler must explicitly specify this\n    fixture in its function arguments and set the StateTestWrapper's spec\n    property.\n\n    Implementation detail: It must be scoped on test function level to avoid\n    leakage between tests.\n    \"\"\"\n\n    class StateTestWrapper(StateTest):\n        def __init__(self, *args, **kwargs):\n            super(StateTestWrapper, self).__init__(*args, **kwargs)\n            fixture_collector.add_fixture(\n                request.node,\n                fill_test(\n                    t8n,\n                    self,\n                    fork,\n                    engine,\n                    reference_spec,\n                    eips=eips,\n                ),\n            )\n\n    return StateTestWrapper\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.blockchain_test","title":"blockchain_test(request, t8n, fork, engine, reference_spec, eips, fixture_collector)","text":"

Fixture used to define an auto-fillable BlockchainTest analogous to the state_test fixture for StateTests. See the state_test fixture docstring for details.

Source code in src/pytest_plugins/test_filler/test_filler.py
@pytest.fixture(scope=\"function\")\ndef blockchain_test(\n    request, t8n, fork, engine, reference_spec, eips, fixture_collector\n) -> BlockchainTestFiller:\n\"\"\"\n    Fixture used to define an auto-fillable BlockchainTest analogous to the\n    state_test fixture for StateTests.\n    See the state_test fixture docstring for details.\n    \"\"\"\n\n    class BlockchainTestWrapper(BlockchainTest):\n        def __init__(self, *args, **kwargs):\n            super(BlockchainTestWrapper, self).__init__(*args, **kwargs)\n            fixture_collector.add_fixture(\n                request.node,\n                fill_test(\n                    t8n,\n                    self,\n                    fork,\n                    engine,\n                    reference_spec,\n                    eips=eips,\n                ),\n            )\n\n    return BlockchainTestWrapper\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.pytest_collection_modifyitems","title":"pytest_collection_modifyitems(items, config)","text":"

A pytest hook called during collection, after all items have been collected.

Here we dynamically apply \"state_test\" or \"blockchain_test\" markers to a test if the test function uses the corresponding fixture.

Source code in src/pytest_plugins/test_filler/test_filler.py
def pytest_collection_modifyitems(items, config):\n\"\"\"\n    A pytest hook called during collection, after all items have been\n    collected.\n\n    Here we dynamically apply \"state_test\" or \"blockchain_test\" markers\n    to a test if the test function uses the corresponding fixture.\n    \"\"\"\n    for item in items:\n        if isinstance(item, EIPSpecTestItem):\n            continue\n        if \"state_test\" in item.fixturenames:\n            marker = pytest.mark.state_test()\n            item.add_marker(marker)\n        elif \"blockchain_test\" in item.fixturenames:\n            marker = pytest.mark.blockchain_test()\n            item.add_marker(marker)\n        if \"yul\" in item.fixturenames:\n            marker = pytest.mark.yul_test()\n            item.add_marker(marker)\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.pytest_make_parametrize_id","title":"pytest_make_parametrize_id(config, val, argname)","text":"

Pytest hook called when generating test ids. We use this to generate more readable test ids for the generated tests.

Source code in src/pytest_plugins/test_filler/test_filler.py
def pytest_make_parametrize_id(config, val, argname):\n\"\"\"\n    Pytest hook called when generating test ids. We use this to generate\n    more readable test ids for the generated tests.\n    \"\"\"\n    return f\"{argname}={val}\"\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.pytest_runtest_call","title":"pytest_runtest_call(item)","text":"

Pytest hook called in the context of test execution.

Source code in src/pytest_plugins/test_filler/test_filler.py
def pytest_runtest_call(item):\n\"\"\"\n    Pytest hook called in the context of test execution.\n    \"\"\"\n    if isinstance(item, EIPSpecTestItem):\n        return\n\n    class InvalidFiller(Exception):\n        def __init__(self, message):\n            super().__init__(message)\n\n    if \"state_test\" in item.fixturenames and \"blockchain_test\" in item.fixturenames:\n        raise InvalidFiller(\n            \"A filler should only implement either a state test or \" \"a blockchain test; not both.\"\n        )\n\n    # Check that the test defines either test type as parameter.\n    if not any([i for i in item.funcargs if i in SPEC_TYPES_PARAMETERS]):\n        pytest.fail(\n            \"Test must define either one of the following parameters to \"\n            + \"properly generate a test: \"\n            + \", \".join(SPEC_TYPES_PARAMETERS)\n        )\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.Fixture","title":"Fixture dataclass","text":"

Cross-client compatible Ethereum test fixture.

Source code in src/ethereum_test_tools/common/types.py
@dataclass(kw_only=True)\nclass Fixture:\n\"\"\"\n    Cross-client compatible Ethereum test fixture.\n    \"\"\"\n\n    blocks: List[FixtureBlock]\n    genesis: FixtureHeader\n    genesis_rlp: bytes\n    head: bytes\n    fork: str\n    pre_state: Mapping[str, Account]\n    post_state: Optional[Mapping[str, Account]]\n    seal_engine: str\n    info: Dict[str, str] = field(default_factory=dict)\n    name: str = \"\"\n\n    _json: Dict[str, Any] | None = None\n\n    def __post_init__(self):\n\"\"\"\n        Post init hook to convert to JSON after instantiation.\n        \"\"\"\n        self._json = to_json(self)\n\n    def fill_info(\n        self,\n        t8n: TransitionTool,\n        ref_spec: ReferenceSpec | None,\n    ):\n\"\"\"\n        Fill the info field for this fixture\n        \"\"\"\n        self.info[\"filling-transition-tool\"] = t8n.version()\n        if ref_spec is not None:\n            ref_spec.write_info(self.info)\n
"},{"location":"library/pytest_plugins/test_filler/#ethereum_test_tools.common.types.Fixture.__post_init__","title":"__post_init__()","text":"

Post init hook to convert to JSON after instantiation.

Source code in src/ethereum_test_tools/common/types.py
def __post_init__(self):\n\"\"\"\n    Post init hook to convert to JSON after instantiation.\n    \"\"\"\n    self._json = to_json(self)\n
"},{"location":"library/pytest_plugins/test_filler/#ethereum_test_tools.common.types.Fixture.fill_info","title":"fill_info(t8n, ref_spec)","text":"

Fill the info field for this fixture

Source code in src/ethereum_test_tools/common/types.py
def fill_info(\n    self,\n    t8n: TransitionTool,\n    ref_spec: ReferenceSpec | None,\n):\n\"\"\"\n    Fill the info field for this fixture\n    \"\"\"\n    self.info[\"filling-transition-tool\"] = t8n.version()\n    if ref_spec is not None:\n        ref_spec.write_info(self.info)\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.JSONEncoder","title":"JSONEncoder","text":"

Bases: json.JSONEncoder

Custom JSON encoder for ethereum_test types.

Source code in src/ethereum_test_tools/common/types.py
class JSONEncoder(json.JSONEncoder):\n\"\"\"\n    Custom JSON encoder for `ethereum_test` types.\n    \"\"\"\n\n    def default(self, obj: JSONEncoderSupportedType) -> Any:\n\"\"\"\n        Enocdes types defined in this module using basic python facilities.\n        \"\"\"\n        if isinstance(obj, Storage):\n            return obj.to_dict()\n        elif isinstance(obj, Account):\n            account = {\n                \"nonce\": hex_or_none(obj.nonce, hex(0)),\n                \"balance\": hex_or_none(obj.balance, hex(0)),\n                \"code\": code_or_none(obj.code, \"0x\"),\n                \"storage\": to_json_or_none(obj.storage, {}),\n            }\n            return even_padding(account, excluded=[\"storage\"])\n        elif isinstance(obj, AccessList):\n            access_list: Dict[str, Any] = {\n                \"address\": address_or_none(obj.address, \"0x\" + ZeroAddress.hex())\n            }\n            if obj.storage_keys is not None:\n                access_list[\"storageKeys\"] = [hex_or_none(k) for k in obj.storage_keys]\n            return access_list\n        elif isinstance(obj, Transaction):\n            assert obj.ty is not None, \"Transaction type must be set\"\n            tx: Dict[str, Any] = {\n                \"type\": hex(obj.ty),\n                \"chainId\": hex(obj.chain_id),\n                \"nonce\": hex(obj.nonce),\n                \"gasPrice\": hex_or_none(obj.gas_price),\n                \"maxPriorityFeePerGas\": hex_or_none(obj.max_priority_fee_per_gas),\n                \"maxFeePerGas\": hex_or_none(obj.max_fee_per_gas),\n                \"gas\": hex(obj.gas_limit),\n                \"value\": hex(obj.value),\n                \"input\": code_to_hex(obj.data),\n                \"to\": address_or_none(obj.to),\n                \"accessList\": obj.access_list,\n                \"secretKey\": obj.secret_key,\n                \"maxFeePerDataGas\": hex_or_none(obj.max_fee_per_data_gas),\n                \"sender\": address_or_none(obj.sender),\n            }\n\n            if obj.blob_versioned_hashes is not None:\n                tx[\"blobVersionedHashes\"] = [hash_string(h) for h in obj.blob_versioned_hashes]\n\n            if obj.secret_key is None:\n                assert obj.signature is not None\n                assert len(obj.signature) == 3\n                tx[\"v\"] = hex(obj.signature[0])\n                tx[\"r\"] = hex(obj.signature[1])\n                tx[\"s\"] = hex(obj.signature[2])\n            else:\n                tx[\"v\"] = \"\"\n                tx[\"r\"] = \"\"\n                tx[\"s\"] = \"\"\n\n            return {k: v for (k, v) in tx.items() if v is not None}\n        elif isinstance(obj, Withdrawal):\n            withdrawal = {\n                \"index\": hex(obj.index),\n                \"validatorIndex\": hex(obj.validator),\n                \"address\": obj.address,\n                \"amount\": hex(obj.amount),\n            }\n            return withdrawal\n        elif isinstance(obj, Environment):\n            env: Dict[str, Any] = {\n                \"currentCoinbase\": address_or_none(obj.coinbase, \"0x\" + ZeroAddress.hex()),\n                \"currentGasLimit\": str_or_none(obj.gas_limit),\n                \"currentNumber\": str_or_none(obj.number),\n                \"currentTimestamp\": str_or_none(obj.timestamp),\n                \"currentRandom\": str_or_none(obj.prev_randao),\n                \"currentDifficulty\": str_or_none(obj.difficulty),\n                \"parentDifficulty\": str_or_none(obj.parent_difficulty),\n                \"parentBaseFee\": str_or_none(obj.parent_base_fee),\n                \"parentGasUsed\": str_or_none(obj.parent_gas_used),\n                \"parentGasLimit\": str_or_none(obj.parent_gas_limit),\n                \"parentTimestamp\": str_or_none(obj.parent_timestamp),\n                \"blockHashes\": {str(k): hex_or_none(v) for (k, v) in obj.block_hashes.items()},\n                \"ommers\": [],\n                \"withdrawals\": to_json_or_none(obj.withdrawals),\n                \"parentUncleHash\": hash_string(obj.parent_ommers_hash),\n                \"currentBaseFee\": str_or_none(obj.base_fee),\n                \"parentDataGasUsed\": str_or_none(obj.parent_data_gas_used),\n                \"parentExcessDataGas\": str_or_none(obj.parent_excess_data_gas),\n                \"currentExcessDataGas\": str_or_none(obj.excess_data_gas),\n                \"currentDataGasUsed\": str_or_none(obj.data_gas_used),\n            }\n\n            return {k: v for (k, v) in env.items() if v is not None}\n        elif isinstance(obj, FixtureHeader):\n            header = {\n                \"parentHash\": hex_or_none(obj.parent_hash),\n                \"uncleHash\": hex_or_none(obj.ommers_hash),\n                \"coinbase\": hex_or_none(obj.coinbase),\n                \"stateRoot\": hex_or_none(obj.state_root),\n                \"transactionsTrie\": hex_or_none(obj.transactions_root),\n                \"receiptTrie\": hex_or_none(obj.receipt_root),\n                \"bloom\": hex_or_none(obj.bloom),\n                \"difficulty\": hex(obj.difficulty),\n                \"number\": hex(obj.number),\n                \"gasLimit\": hex(obj.gas_limit),\n                \"gasUsed\": hex(obj.gas_used),\n                \"timestamp\": hex(obj.timestamp),\n                \"extraData\": hex_or_none(obj.extra_data),\n                \"mixHash\": hex_or_none(obj.mix_digest),\n                \"nonce\": hex_or_none(obj.nonce),\n            }\n            if obj.base_fee is not None:\n                header[\"baseFeePerGas\"] = hex(obj.base_fee)\n            if obj.hash is not None:\n                header[\"hash\"] = \"0x\" + obj.hash.hex()\n            if obj.withdrawals_root is not None:\n                header[\"withdrawalsRoot\"] = hex_or_none(obj.withdrawals_root)\n            if obj.data_gas_used is not None:\n                header[\"dataGasUsed\"] = hex(obj.data_gas_used)\n            if obj.excess_data_gas is not None:\n                header[\"excessDataGas\"] = hex(obj.excess_data_gas)\n            return even_padding(\n                header,\n                excluded=[\n                    \"parentHash\",\n                    \"uncleHash\",\n                    \"stateRoot\",\n                    \"coinbase\",\n                    \"transactionsTrie\",\n                    \"receiptTrie\",\n                    \"bloom\",\n                    \"nonce\",\n                    \"mixHash\",\n                    \"hash\",\n                    \"withdrawalsRoot\",\n                    \"extraData\",\n                ],\n            )\n        elif isinstance(obj, FixtureTransaction):\n            json_tx = to_json(obj.tx)\n            if json_tx[\"v\"] == \"\":\n                del json_tx[\"v\"]\n                del json_tx[\"r\"]\n                del json_tx[\"s\"]\n            if \"input\" in json_tx:\n                json_tx[\"data\"] = json_tx[\"input\"]\n                del json_tx[\"input\"]\n            if \"gas\" in json_tx:\n                json_tx[\"gasLimit\"] = json_tx[\"gas\"]\n                del json_tx[\"gas\"]\n            if \"to\" not in json_tx:\n                json_tx[\"to\"] = \"\"\n            return even_padding(\n                json_tx,\n                excluded=[\"data\", \"to\", \"accessList\"],\n            )\n        elif isinstance(obj, FixtureExecutionPayload):\n            payload: Dict[str, Any] = {\n                \"parentHash\": hex_or_none(obj.header.parent_hash),\n                \"feeRecipient\": hex_or_none(obj.header.coinbase),\n                \"stateRoot\": hex_or_none(obj.header.state_root),\n                \"receiptsRoot\": hex_or_none(obj.header.receipt_root),\n                \"logsBloom\": hex_or_none(obj.header.bloom),\n                \"prevRandao\": hex_or_none(obj.header.mix_digest),\n                \"blockNumber\": hex(obj.header.number),\n                \"gasLimit\": hex(obj.header.gas_limit),\n                \"gasUsed\": hex(obj.header.gas_used),\n                \"timestamp\": hex(obj.header.timestamp),\n                \"extraData\": hex_or_none(obj.header.extra_data),\n            }\n            if obj.header.base_fee is not None:\n                payload[\"baseFeePerGas\"] = hex(obj.header.base_fee)\n            if obj.header.hash is not None:\n                payload[\"blockHash\"] = \"0x\" + obj.header.hash.hex()\n\n            if obj.transactions is not None:\n                payload[\"transactions\"] = [\n                    hex_or_none(tx.serialized_bytes()) for tx in obj.transactions\n                ]\n            if obj.withdrawals is not None:\n                payload[\"withdrawals\"] = obj.withdrawals\n\n            if obj.header.data_gas_used is not None:\n                payload[\"dataGasUsed\"] = hex(obj.header.data_gas_used)\n            if obj.header.excess_data_gas is not None:\n                payload[\"excessDataGas\"] = hex(obj.header.excess_data_gas)\n\n            return payload\n        elif isinstance(obj, FixtureEngineNewPayload):\n            new_payload: Dict[str, Any] = {\n                \"payload\": to_json(obj.payload),\n                \"version\": str_or_none(obj.version),\n            }\n            if obj.blob_versioned_hashes is not None:\n                new_payload[\"blobVersionedHashes\"] = [\n                    \"0x\" + hash_to_bytes(h).hex() for h in obj.blob_versioned_hashes\n                ]\n            if obj.error_code is not None:\n                new_payload[\"errorCode\"] = str(int(obj.error_code))\n            return new_payload\n\n        elif isinstance(obj, FixtureBlock):\n            b: Dict[str, Any] = {\"rlp\": hex_or_none(obj.rlp)}\n            if obj.block_header is not None:\n                b[\"blockHeader\"] = json.loads(json.dumps(obj.block_header, cls=JSONEncoder))\n            if obj.new_payload is not None:\n                b[\"engineNewPayload\"] = to_json_or_none(obj.new_payload)\n            if obj.expected_exception is not None:\n                b[\"expectException\"] = obj.expected_exception\n            if obj.block_number is not None:\n                b[\"blocknumber\"] = str(obj.block_number)\n            if obj.txs is not None:\n                b[\"transactions\"] = [FixtureTransaction(tx=tx) for tx in obj.txs]\n            if obj.ommers is not None:\n                b[\"uncleHeaders\"] = obj.ommers\n            if obj.withdrawals is not None:\n                b[\"withdrawals\"] = [\n                    even_padding(to_json(wd), excluded=[\"address\"]) for wd in obj.withdrawals\n                ]\n            return b\n\n        elif isinstance(obj, Fixture):\n            if obj._json is not None:\n                obj._json[\"_info\"] = obj.info\n                return obj._json\n\n            f = {\n                \"_info\": obj.info,\n                \"blocks\": [json.loads(json.dumps(b, cls=JSONEncoder)) for b in obj.blocks],\n                \"genesisBlockHeader\": self.default(obj.genesis),\n                \"genesisRLP\": hex_or_none(obj.genesis_rlp),\n                \"lastblockhash\": hex_or_none(obj.head),\n                \"network\": obj.fork,\n                \"pre\": json.loads(json.dumps(obj.pre_state, cls=JSONEncoder)),\n                \"postState\": json.loads(json.dumps(obj.post_state, cls=JSONEncoder)),\n                \"sealEngine\": obj.seal_engine,\n            }\n            if f[\"postState\"] is None:\n                del f[\"postState\"]\n            return f\n        else:\n            return super().default(obj)\n
"},{"location":"library/pytest_plugins/test_filler/#ethereum_test_tools.common.types.JSONEncoder.default","title":"default(obj)","text":"

Enocdes types defined in this module using basic python facilities.

Source code in src/ethereum_test_tools/common/types.py
def default(self, obj: JSONEncoderSupportedType) -> Any:\n\"\"\"\n    Enocdes types defined in this module using basic python facilities.\n    \"\"\"\n    if isinstance(obj, Storage):\n        return obj.to_dict()\n    elif isinstance(obj, Account):\n        account = {\n            \"nonce\": hex_or_none(obj.nonce, hex(0)),\n            \"balance\": hex_or_none(obj.balance, hex(0)),\n            \"code\": code_or_none(obj.code, \"0x\"),\n            \"storage\": to_json_or_none(obj.storage, {}),\n        }\n        return even_padding(account, excluded=[\"storage\"])\n    elif isinstance(obj, AccessList):\n        access_list: Dict[str, Any] = {\n            \"address\": address_or_none(obj.address, \"0x\" + ZeroAddress.hex())\n        }\n        if obj.storage_keys is not None:\n            access_list[\"storageKeys\"] = [hex_or_none(k) for k in obj.storage_keys]\n        return access_list\n    elif isinstance(obj, Transaction):\n        assert obj.ty is not None, \"Transaction type must be set\"\n        tx: Dict[str, Any] = {\n            \"type\": hex(obj.ty),\n            \"chainId\": hex(obj.chain_id),\n            \"nonce\": hex(obj.nonce),\n            \"gasPrice\": hex_or_none(obj.gas_price),\n            \"maxPriorityFeePerGas\": hex_or_none(obj.max_priority_fee_per_gas),\n            \"maxFeePerGas\": hex_or_none(obj.max_fee_per_gas),\n            \"gas\": hex(obj.gas_limit),\n            \"value\": hex(obj.value),\n            \"input\": code_to_hex(obj.data),\n            \"to\": address_or_none(obj.to),\n            \"accessList\": obj.access_list,\n            \"secretKey\": obj.secret_key,\n            \"maxFeePerDataGas\": hex_or_none(obj.max_fee_per_data_gas),\n            \"sender\": address_or_none(obj.sender),\n        }\n\n        if obj.blob_versioned_hashes is not None:\n            tx[\"blobVersionedHashes\"] = [hash_string(h) for h in obj.blob_versioned_hashes]\n\n        if obj.secret_key is None:\n            assert obj.signature is not None\n            assert len(obj.signature) == 3\n            tx[\"v\"] = hex(obj.signature[0])\n            tx[\"r\"] = hex(obj.signature[1])\n            tx[\"s\"] = hex(obj.signature[2])\n        else:\n            tx[\"v\"] = \"\"\n            tx[\"r\"] = \"\"\n            tx[\"s\"] = \"\"\n\n        return {k: v for (k, v) in tx.items() if v is not None}\n    elif isinstance(obj, Withdrawal):\n        withdrawal = {\n            \"index\": hex(obj.index),\n            \"validatorIndex\": hex(obj.validator),\n            \"address\": obj.address,\n            \"amount\": hex(obj.amount),\n        }\n        return withdrawal\n    elif isinstance(obj, Environment):\n        env: Dict[str, Any] = {\n            \"currentCoinbase\": address_or_none(obj.coinbase, \"0x\" + ZeroAddress.hex()),\n            \"currentGasLimit\": str_or_none(obj.gas_limit),\n            \"currentNumber\": str_or_none(obj.number),\n            \"currentTimestamp\": str_or_none(obj.timestamp),\n            \"currentRandom\": str_or_none(obj.prev_randao),\n            \"currentDifficulty\": str_or_none(obj.difficulty),\n            \"parentDifficulty\": str_or_none(obj.parent_difficulty),\n            \"parentBaseFee\": str_or_none(obj.parent_base_fee),\n            \"parentGasUsed\": str_or_none(obj.parent_gas_used),\n            \"parentGasLimit\": str_or_none(obj.parent_gas_limit),\n            \"parentTimestamp\": str_or_none(obj.parent_timestamp),\n            \"blockHashes\": {str(k): hex_or_none(v) for (k, v) in obj.block_hashes.items()},\n            \"ommers\": [],\n            \"withdrawals\": to_json_or_none(obj.withdrawals),\n            \"parentUncleHash\": hash_string(obj.parent_ommers_hash),\n            \"currentBaseFee\": str_or_none(obj.base_fee),\n            \"parentDataGasUsed\": str_or_none(obj.parent_data_gas_used),\n            \"parentExcessDataGas\": str_or_none(obj.parent_excess_data_gas),\n            \"currentExcessDataGas\": str_or_none(obj.excess_data_gas),\n            \"currentDataGasUsed\": str_or_none(obj.data_gas_used),\n        }\n\n        return {k: v for (k, v) in env.items() if v is not None}\n    elif isinstance(obj, FixtureHeader):\n        header = {\n            \"parentHash\": hex_or_none(obj.parent_hash),\n            \"uncleHash\": hex_or_none(obj.ommers_hash),\n            \"coinbase\": hex_or_none(obj.coinbase),\n            \"stateRoot\": hex_or_none(obj.state_root),\n            \"transactionsTrie\": hex_or_none(obj.transactions_root),\n            \"receiptTrie\": hex_or_none(obj.receipt_root),\n            \"bloom\": hex_or_none(obj.bloom),\n            \"difficulty\": hex(obj.difficulty),\n            \"number\": hex(obj.number),\n            \"gasLimit\": hex(obj.gas_limit),\n            \"gasUsed\": hex(obj.gas_used),\n            \"timestamp\": hex(obj.timestamp),\n            \"extraData\": hex_or_none(obj.extra_data),\n            \"mixHash\": hex_or_none(obj.mix_digest),\n            \"nonce\": hex_or_none(obj.nonce),\n        }\n        if obj.base_fee is not None:\n            header[\"baseFeePerGas\"] = hex(obj.base_fee)\n        if obj.hash is not None:\n            header[\"hash\"] = \"0x\" + obj.hash.hex()\n        if obj.withdrawals_root is not None:\n            header[\"withdrawalsRoot\"] = hex_or_none(obj.withdrawals_root)\n        if obj.data_gas_used is not None:\n            header[\"dataGasUsed\"] = hex(obj.data_gas_used)\n        if obj.excess_data_gas is not None:\n            header[\"excessDataGas\"] = hex(obj.excess_data_gas)\n        return even_padding(\n            header,\n            excluded=[\n                \"parentHash\",\n                \"uncleHash\",\n                \"stateRoot\",\n                \"coinbase\",\n                \"transactionsTrie\",\n                \"receiptTrie\",\n                \"bloom\",\n                \"nonce\",\n                \"mixHash\",\n                \"hash\",\n                \"withdrawalsRoot\",\n                \"extraData\",\n            ],\n        )\n    elif isinstance(obj, FixtureTransaction):\n        json_tx = to_json(obj.tx)\n        if json_tx[\"v\"] == \"\":\n            del json_tx[\"v\"]\n            del json_tx[\"r\"]\n            del json_tx[\"s\"]\n        if \"input\" in json_tx:\n            json_tx[\"data\"] = json_tx[\"input\"]\n            del json_tx[\"input\"]\n        if \"gas\" in json_tx:\n            json_tx[\"gasLimit\"] = json_tx[\"gas\"]\n            del json_tx[\"gas\"]\n        if \"to\" not in json_tx:\n            json_tx[\"to\"] = \"\"\n        return even_padding(\n            json_tx,\n            excluded=[\"data\", \"to\", \"accessList\"],\n        )\n    elif isinstance(obj, FixtureExecutionPayload):\n        payload: Dict[str, Any] = {\n            \"parentHash\": hex_or_none(obj.header.parent_hash),\n            \"feeRecipient\": hex_or_none(obj.header.coinbase),\n            \"stateRoot\": hex_or_none(obj.header.state_root),\n            \"receiptsRoot\": hex_or_none(obj.header.receipt_root),\n            \"logsBloom\": hex_or_none(obj.header.bloom),\n            \"prevRandao\": hex_or_none(obj.header.mix_digest),\n            \"blockNumber\": hex(obj.header.number),\n            \"gasLimit\": hex(obj.header.gas_limit),\n            \"gasUsed\": hex(obj.header.gas_used),\n            \"timestamp\": hex(obj.header.timestamp),\n            \"extraData\": hex_or_none(obj.header.extra_data),\n        }\n        if obj.header.base_fee is not None:\n            payload[\"baseFeePerGas\"] = hex(obj.header.base_fee)\n        if obj.header.hash is not None:\n            payload[\"blockHash\"] = \"0x\" + obj.header.hash.hex()\n\n        if obj.transactions is not None:\n            payload[\"transactions\"] = [\n                hex_or_none(tx.serialized_bytes()) for tx in obj.transactions\n            ]\n        if obj.withdrawals is not None:\n            payload[\"withdrawals\"] = obj.withdrawals\n\n        if obj.header.data_gas_used is not None:\n            payload[\"dataGasUsed\"] = hex(obj.header.data_gas_used)\n        if obj.header.excess_data_gas is not None:\n            payload[\"excessDataGas\"] = hex(obj.header.excess_data_gas)\n\n        return payload\n    elif isinstance(obj, FixtureEngineNewPayload):\n        new_payload: Dict[str, Any] = {\n            \"payload\": to_json(obj.payload),\n            \"version\": str_or_none(obj.version),\n        }\n        if obj.blob_versioned_hashes is not None:\n            new_payload[\"blobVersionedHashes\"] = [\n                \"0x\" + hash_to_bytes(h).hex() for h in obj.blob_versioned_hashes\n            ]\n        if obj.error_code is not None:\n            new_payload[\"errorCode\"] = str(int(obj.error_code))\n        return new_payload\n\n    elif isinstance(obj, FixtureBlock):\n        b: Dict[str, Any] = {\"rlp\": hex_or_none(obj.rlp)}\n        if obj.block_header is not None:\n            b[\"blockHeader\"] = json.loads(json.dumps(obj.block_header, cls=JSONEncoder))\n        if obj.new_payload is not None:\n            b[\"engineNewPayload\"] = to_json_or_none(obj.new_payload)\n        if obj.expected_exception is not None:\n            b[\"expectException\"] = obj.expected_exception\n        if obj.block_number is not None:\n            b[\"blocknumber\"] = str(obj.block_number)\n        if obj.txs is not None:\n            b[\"transactions\"] = [FixtureTransaction(tx=tx) for tx in obj.txs]\n        if obj.ommers is not None:\n            b[\"uncleHeaders\"] = obj.ommers\n        if obj.withdrawals is not None:\n            b[\"withdrawals\"] = [\n                even_padding(to_json(wd), excluded=[\"address\"]) for wd in obj.withdrawals\n            ]\n        return b\n\n    elif isinstance(obj, Fixture):\n        if obj._json is not None:\n            obj._json[\"_info\"] = obj.info\n            return obj._json\n\n        f = {\n            \"_info\": obj.info,\n            \"blocks\": [json.loads(json.dumps(b, cls=JSONEncoder)) for b in obj.blocks],\n            \"genesisBlockHeader\": self.default(obj.genesis),\n            \"genesisRLP\": hex_or_none(obj.genesis_rlp),\n            \"lastblockhash\": hex_or_none(obj.head),\n            \"network\": obj.fork,\n            \"pre\": json.loads(json.dumps(obj.pre_state, cls=JSONEncoder)),\n            \"postState\": json.loads(json.dumps(obj.post_state, cls=JSONEncoder)),\n            \"sealEngine\": obj.seal_engine,\n        }\n        if f[\"postState\"] is None:\n            del f[\"postState\"]\n        return f\n    else:\n        return super().default(obj)\n
"},{"location":"tests/","title":"Test case reference","text":"

Documentation for tests.

Generate fixtures for these test cases for all forks deployed to mainnet with:

fill -v tests\n

Generate fixtures for these test cases for Cancun with:

Cancun only:

fill -v tests --fork=Cancun --evm-bin=/path/to/evm-tool-dev-version\n
For all forks up to and including Cancun:
fill -v tests --until=Cancun --evm-bin=/path/to/evm-tool-dev-version\n

Cross-client test cases organized by fork. Each directory underneath tests/ contains test cases corresponding to the fork in which the functionality-under-test was introduced.

"},{"location":"tests/berlin/","title":"Berlin","text":"

Documentation for tests/berlin.

Generate fixtures for these test cases with:

fill -v tests/berlin\n

Test cases for EVM functionality introduced in Berlin.

"},{"location":"tests/berlin/eip2930_access_list/","title":"EIP-2930 Access List","text":"

Documentation for tests/berlin/eip2930_access_list.

Generate fixtures for these test cases with:

fill -v tests/berlin/eip2930_access_list\n
Tests EIP-2930: Optional access lists

Test cases for EIP-2930: Optional access lists.

"},{"location":"tests/berlin/eip2930_access_list/test_acl/","title":"Test ACL","text":"

Documentation for tests/berlin/eip2930_access_list/test_acl.py.

Generate fixtures for these test cases with:

fill -v tests/berlin/eip2930_access_list/test_acl.py\n

Test ACL Transaction Source Code Examples

"},{"location":"tests/berlin/eip2930_access_list/test_acl/#tests.berlin.eip2930_access_list.test_acl.test_access_list","title":"test_access_list(state_test, fork)","text":"

Test type 1 transaction.

Source code in tests/berlin/eip2930_access_list/test_acl.py
@pytest.mark.valid_from(\"Berlin\")\n@pytest.mark.valid_until(\"London\")\ndef test_access_list(state_test: StateTestFiller, fork: Fork):\n\"\"\"\n    Test type 1 transaction.\n    \"\"\"\n    env = Environment()\n\n    pre = {\n        \"0x000000000000000000000000000000000000aaaa\": Account(\n            balance=0x03,\n            code=Op.PC + Op.SLOAD + Op.POP + Op.PC + Op.SLOAD,\n            nonce=1,\n        ),\n        \"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b\": Account(\n            balance=0x300000,\n            nonce=0,\n        ),\n    }\n\n    tx = Transaction(\n        ty=1,\n        chain_id=0x01,\n        nonce=0,\n        to=\"0x000000000000000000000000000000000000aaaa\",\n        value=1,\n        gas_limit=323328,\n        gas_price=7,\n        access_list=[\n            AccessList(\n                address=\"0x0000000000000000000000000000000000000000\",\n                storage_keys=[\n                    \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n                ],\n            )\n        ],\n        secret_key=\"0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8\",\n        protected=True,\n    )\n\n    post = {\n        \"0x000000000000000000000000000000000000aaaa\": Account(\n            code=\"0x5854505854\",\n            balance=4,\n            nonce=1,\n        ),\n        \"0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba\": Account(\n            balance=0x1BC16D674EC80000 if is_fork(fork, London) else 0x1BC16D674ECB26CE,\n        ),\n        \"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b\": Account(\n            balance=0x2CD931,\n            nonce=1,\n        ),\n    }\n    state_test(env=env, pre=pre, post=post, txs=[tx])\n
"},{"location":"tests/berlin/eip2930_access_list/test_acl/index/test_cases/","title":"Test ACL - Test Cases","text":"

Test cases generated from tests/berlin/eip2930_access_list/test_acl.py

Parametrized test cases generated from the test module tests/berlin/eip2930_access_list/test_acl.py:

test_access_list[fork=Berlin]\ntest_access_list[fork=London]\n

This output was extracted from the result of:

fill --collect-only -q --until Cancun tests/berlin/eip2930_access_list/test_acl.py\n
"},{"location":"tests/cancun/","title":"Cancun","text":"

Documentation for tests/cancun.

Generate fixtures for these test cases for Cancun with:

Cancun only:

fill -v tests/cancun --fork=Cancun --evm-bin=/path/to/evm-tool-dev-version\n
For all forks up to and including Cancun:
fill -v tests/cancun --until=Cancun --evm-bin=/path/to/evm-tool-dev-version\n

Test cases for EVM functionality introduced in Cancun.

"},{"location":"tests/cancun/eip4844_blobs/","title":"EIP-4844 Blobs","text":"

Documentation for tests/cancun/eip4844_blobs.

Generate fixtures for these test cases for Cancun with:

Cancun only:

fill -v tests/cancun/eip4844_blobs --fork=Cancun --evm-bin=/path/to/evm-tool-dev-version\n
For all forks up to and including Cancun:
fill -v tests/cancun/eip4844_blobs --until=Cancun --evm-bin=/path/to/evm-tool-dev-version\n

Cross-client EIP-4844 Tests

"},{"location":"tests/cancun/eip4844_blobs/point_evaluation_vectors/README_./","title":"KZG Point Evaluation Test Vectors","text":"

This directory contains test vectors for the KZG point evaluation algorithm, compiled from different sources.

Each file must contain a JSON list of objects, each with the following fields: - name: a string describing the test case - input: object containing commitment, proof, z and y - output: expected output of the evaluation, true, false or null.

The files are loaded and used throughout different test tests.

Current files and their sources: - go_kzg_4844_verify_kzg_proof.json: test vectors from the go-kzg-4844 repository.

"},{"location":"tests/cancun/eip4844_blobs/spec/","title":"Spec","text":"

Documentation for tests/cancun/eip4844_blobs/spec.py.

Defines EIP-4844 spec constants and functions.

"},{"location":"tests/cancun/eip4844_blobs/spec/#tests.cancun.eip4844_blobs.spec.Spec","title":"Spec dataclass","text":"

Bases: IntEnum

Parameters from the EIP-4844 specifications as defined at https://eips.ethereum.org/EIPS/eip-4844#parameters

If the parameter is not currently used within the tests, it is commented out.

Source code in tests/cancun/eip4844_blobs/spec.py
@dataclass(frozen=True)\nclass Spec(IntEnum):\n\"\"\"\n    Parameters from the EIP-4844 specifications as defined at\n    https://eips.ethereum.org/EIPS/eip-4844#parameters\n\n    If the parameter is not currently used within the tests, it is commented\n    out.\n    \"\"\"\n\n    BLOB_TX_TYPE = 0x03\n    FIELD_ELEMENTS_PER_BLOB = 4096\n    BLS_MODULUS = 0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001\n    BLOB_COMMITMENT_VERSION_KZG = 1\n    POINT_EVALUATION_PRECOMPILE_ADDRESS = 20\n    POINT_EVALUATION_PRECOMPILE_GAS = 50_000\n    MAX_DATA_GAS_PER_BLOCK = 786432\n    TARGET_DATA_GAS_PER_BLOCK = 393216\n    MIN_DATA_GASPRICE = 1\n    DATA_GASPRICE_UPDATE_FRACTION = 3338477\n    # MAX_VERSIONED_HASHES_LIST_SIZE = 2**24\n    # MAX_CALLDATA_SIZE = 2**24\n    # MAX_ACCESS_LIST_SIZE = 2**24\n    # MAX_ACCESS_LIST_STORAGE_KEYS = 2**24\n    # MAX_TX_WRAP_COMMITMENTS = 2**12\n    # LIMIT_BLOBS_PER_TX = 2**12\n    DATA_GAS_PER_BLOB = 2**17\n    HASH_OPCODE_BYTE = 0x49\n    HASH_GAS_COST = 3\n\n    @classmethod\n    def kzg_to_versioned_hash(\n        cls,\n        kzg_commitment: bytes | int,  # 48 bytes\n        blob_commitment_version_kzg: Optional[bytes | int] = None,\n    ) -> bytes:\n\"\"\"\n        Calculates the versioned hash for a given KZG commitment.\n        \"\"\"\n        if blob_commitment_version_kzg is None:\n            blob_commitment_version_kzg = cls.BLOB_COMMITMENT_VERSION_KZG\n        if isinstance(kzg_commitment, int):\n            kzg_commitment = kzg_commitment.to_bytes(48, \"big\")\n        if isinstance(blob_commitment_version_kzg, int):\n            blob_commitment_version_kzg = blob_commitment_version_kzg.to_bytes(1, \"big\")\n        return blob_commitment_version_kzg + sha256(kzg_commitment).digest()[1:]\n\n    @classmethod\n    def fake_exponential(cls, factor: int, numerator: int, denominator: int) -> int:\n\"\"\"\n        Used to calculate the data gas cost.\n        \"\"\"\n        i = 1\n        output = 0\n        numerator_accumulator = factor * denominator\n        while numerator_accumulator > 0:\n            output += numerator_accumulator\n            numerator_accumulator = (numerator_accumulator * numerator) // (denominator * i)\n            i += 1\n        return output // denominator\n\n    @classmethod\n    def calc_excess_data_gas(cls, parent: BlockHeaderDataGasFields) -> int:\n\"\"\"\n        Calculate the excess data gas for a block given the parent excess data gas\n        and the number of blobs in the block.\n        \"\"\"\n        if parent.excess_data_gas + parent.data_gas_used < cls.TARGET_DATA_GAS_PER_BLOCK:\n            return 0\n        else:\n            return parent.excess_data_gas + parent.data_gas_used - cls.TARGET_DATA_GAS_PER_BLOCK\n\n    # Note: Currently unused.\n    # @classmethod\n    # def get_total_data_gas(cls, tx: Transaction) -> int:\n    #     \"\"\"\n    #     Calculate the total data gas for a transaction.\n    #     \"\"\"\n    #     if tx.blob_versioned_hashes is None:\n    #         return 0\n    #     return cls.DATA_GAS_PER_BLOB.value * len(tx.blob_versioned_hashes)\n\n    @classmethod\n    def get_data_gasprice(cls, *, excess_data_gas: int) -> int:\n\"\"\"\n        Calculate the data gas price from the excess.\n        \"\"\"\n        return cls.fake_exponential(\n            cls.MIN_DATA_GASPRICE.value,\n            excess_data_gas,\n            cls.DATA_GASPRICE_UPDATE_FRACTION.value,\n        )\n
"},{"location":"tests/cancun/eip4844_blobs/spec/#tests.cancun.eip4844_blobs.spec.SpecHelpers","title":"SpecHelpers dataclass","text":"

Bases: Enum

Define parameters and helper functions that are tightly coupled to the 4844 spec but not strictly part of it.

Source code in tests/cancun/eip4844_blobs/spec.py
@dataclass(frozen=True)\nclass SpecHelpers(Enum):\n\"\"\"\n    Define parameters and helper functions that are tightly coupled to the 4844\n    spec but not strictly part of it.\n    \"\"\"\n\n    BYTES_PER_FIELD_ELEMENT = 32\n\n    @classmethod\n    def max_blobs_per_block(cls) -> int:  # MAX_BLOBS_PER_BLOCK =\n\"\"\"\n        Returns the maximum number of blobs per block.\n        \"\"\"\n        return Spec.MAX_DATA_GAS_PER_BLOCK.value // Spec.DATA_GAS_PER_BLOB.value\n\n    @classmethod\n    def target_blobs_per_block(cls) -> int:\n\"\"\"\n        Returns the target number of blobs per block.\n        \"\"\"\n        return Spec.TARGET_DATA_GAS_PER_BLOCK.value // Spec.DATA_GAS_PER_BLOB.value\n\n    @classmethod\n    def calc_excess_data_gas_from_blob_count(\n        cls, parent_excess_data_gas: int, parent_blob_count: int\n    ) -> int:\n\"\"\"\n        Calculate the excess data gas for a block given the parent excess data gas\n        and the number of blobs in the block.\n        \"\"\"\n        parent_consumed_data_gas = parent_blob_count * Spec.DATA_GAS_PER_BLOB.value\n        return Spec.calc_excess_data_gas(\n            BlockHeaderDataGasFields(parent_excess_data_gas, parent_consumed_data_gas)\n        )\n\n    @classmethod\n    def get_min_excess_data_gas_for_data_gas_price(cls, data_gas_price: int) -> int:\n\"\"\"\n        Gets the minimum required excess data gas value to get a given data gas cost in a block\n        \"\"\"\n        current_excess_data_gas = 0\n        current_data_gas_price = 1\n        while current_data_gas_price < data_gas_price:\n            current_excess_data_gas += Spec.DATA_GAS_PER_BLOB.value\n            current_data_gas_price = Spec.get_data_gasprice(\n                excess_data_gas=current_excess_data_gas\n            )\n        return current_excess_data_gas\n\n    @classmethod\n    def get_min_excess_data_blobs_for_data_gas_price(cls, data_gas_price: int) -> int:\n\"\"\"\n        Gets the minimum required excess data blobs to get a given data gas cost in a block\n        \"\"\"\n        return (\n            cls.get_min_excess_data_gas_for_data_gas_price(data_gas_price)\n            // Spec.DATA_GAS_PER_BLOB.value\n        )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs/","title":"Test Blob Txs","text":"

Documentation for tests/cancun/eip4844_blobs/test_blob_txs.py.

Generate fixtures for these test cases for Cancun with:

Cancun only:

fill -v tests/cancun/eip4844_blobs/test_blob_txs.py --fork=Cancun --evm-bin=/path/to/evm-tool-dev-version\n
For all forks up to and including Cancun:
fill -v tests/cancun/eip4844_blobs/test_blob_txs.py --until=Cancun --evm-bin=/path/to/evm-tool-dev-version\n

Tests blob type transactions for EIP-4844: Shard Blob Transactions

Test blob type transactions for EIP-4844: Shard Blob Transactions.

Adding a new test

Add a function that is named test_<test_name> and takes at least the following arguments:

  • blockchain_test
  • pre
  • env
  • blocks

All other pytest.fixture fixtures can be parametrized to generate new combinations and test cases.

"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs/#tests.cancun.eip4844_blobs.test_blob_txs.Spec","title":"Spec dataclass","text":"

Bases: IntEnum

Parameters from the EIP-4844 specifications as defined at https://eips.ethereum.org/EIPS/eip-4844#parameters

If the parameter is not currently used within the tests, it is commented out.

Source code in tests/cancun/eip4844_blobs/spec.py
@dataclass(frozen=True)\nclass Spec(IntEnum):\n\"\"\"\n    Parameters from the EIP-4844 specifications as defined at\n    https://eips.ethereum.org/EIPS/eip-4844#parameters\n\n    If the parameter is not currently used within the tests, it is commented\n    out.\n    \"\"\"\n\n    BLOB_TX_TYPE = 0x03\n    FIELD_ELEMENTS_PER_BLOB = 4096\n    BLS_MODULUS = 0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001\n    BLOB_COMMITMENT_VERSION_KZG = 1\n    POINT_EVALUATION_PRECOMPILE_ADDRESS = 20\n    POINT_EVALUATION_PRECOMPILE_GAS = 50_000\n    MAX_DATA_GAS_PER_BLOCK = 786432\n    TARGET_DATA_GAS_PER_BLOCK = 393216\n    MIN_DATA_GASPRICE = 1\n    DATA_GASPRICE_UPDATE_FRACTION = 3338477\n    # MAX_VERSIONED_HASHES_LIST_SIZE = 2**24\n    # MAX_CALLDATA_SIZE = 2**24\n    # MAX_ACCESS_LIST_SIZE = 2**24\n    # MAX_ACCESS_LIST_STORAGE_KEYS = 2**24\n    # MAX_TX_WRAP_COMMITMENTS = 2**12\n    # LIMIT_BLOBS_PER_TX = 2**12\n    DATA_GAS_PER_BLOB = 2**17\n    HASH_OPCODE_BYTE = 0x49\n    HASH_GAS_COST = 3\n\n    @classmethod\n    def kzg_to_versioned_hash(\n        cls,\n        kzg_commitment: bytes | int,  # 48 bytes\n        blob_commitment_version_kzg: Optional[bytes | int] = None,\n    ) -> bytes:\n\"\"\"\n        Calculates the versioned hash for a given KZG commitment.\n        \"\"\"\n        if blob_commitment_version_kzg is None:\n            blob_commitment_version_kzg = cls.BLOB_COMMITMENT_VERSION_KZG\n        if isinstance(kzg_commitment, int):\n            kzg_commitment = kzg_commitment.to_bytes(48, \"big\")\n        if isinstance(blob_commitment_version_kzg, int):\n            blob_commitment_version_kzg = blob_commitment_version_kzg.to_bytes(1, \"big\")\n        return blob_commitment_version_kzg + sha256(kzg_commitment).digest()[1:]\n\n    @classmethod\n    def fake_exponential(cls, factor: int, numerator: int, denominator: int) -> int:\n\"\"\"\n        Used to calculate the data gas cost.\n        \"\"\"\n        i = 1\n        output = 0\n        numerator_accumulator = factor * denominator\n        while numerator_accumulator > 0:\n            output += numerator_accumulator\n            numerator_accumulator = (numerator_accumulator * numerator) // (denominator * i)\n            i += 1\n        return output // denominator\n\n    @classmethod\n    def calc_excess_data_gas(cls, parent: BlockHeaderDataGasFields) -> int:\n\"\"\"\n        Calculate the excess data gas for a block given the parent excess data gas\n        and the number of blobs in the block.\n        \"\"\"\n        if parent.excess_data_gas + parent.data_gas_used < cls.TARGET_DATA_GAS_PER_BLOCK:\n            return 0\n        else:\n            return parent.excess_data_gas + parent.data_gas_used - cls.TARGET_DATA_GAS_PER_BLOCK\n\n    # Note: Currently unused.\n    # @classmethod\n    # def get_total_data_gas(cls, tx: Transaction) -> int:\n    #     \"\"\"\n    #     Calculate the total data gas for a transaction.\n    #     \"\"\"\n    #     if tx.blob_versioned_hashes is None:\n    #         return 0\n    #     return cls.DATA_GAS_PER_BLOB.value * len(tx.blob_versioned_hashes)\n\n    @classmethod\n    def get_data_gasprice(cls, *, excess_data_gas: int) -> int:\n\"\"\"\n        Calculate the data gas price from the excess.\n        \"\"\"\n        return cls.fake_exponential(\n            cls.MIN_DATA_GASPRICE.value,\n            excess_data_gas,\n            cls.DATA_GASPRICE_UPDATE_FRACTION.value,\n        )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs/#tests.cancun.eip4844_blobs.test_blob_txs.SpecHelpers","title":"SpecHelpers dataclass","text":"

Bases: Enum

Define parameters and helper functions that are tightly coupled to the 4844 spec but not strictly part of it.

Source code in tests/cancun/eip4844_blobs/spec.py
@dataclass(frozen=True)\nclass SpecHelpers(Enum):\n\"\"\"\n    Define parameters and helper functions that are tightly coupled to the 4844\n    spec but not strictly part of it.\n    \"\"\"\n\n    BYTES_PER_FIELD_ELEMENT = 32\n\n    @classmethod\n    def max_blobs_per_block(cls) -> int:  # MAX_BLOBS_PER_BLOCK =\n\"\"\"\n        Returns the maximum number of blobs per block.\n        \"\"\"\n        return Spec.MAX_DATA_GAS_PER_BLOCK.value // Spec.DATA_GAS_PER_BLOB.value\n\n    @classmethod\n    def target_blobs_per_block(cls) -> int:\n\"\"\"\n        Returns the target number of blobs per block.\n        \"\"\"\n        return Spec.TARGET_DATA_GAS_PER_BLOCK.value // Spec.DATA_GAS_PER_BLOB.value\n\n    @classmethod\n    def calc_excess_data_gas_from_blob_count(\n        cls, parent_excess_data_gas: int, parent_blob_count: int\n    ) -> int:\n\"\"\"\n        Calculate the excess data gas for a block given the parent excess data gas\n        and the number of blobs in the block.\n        \"\"\"\n        parent_consumed_data_gas = parent_blob_count * Spec.DATA_GAS_PER_BLOB.value\n        return Spec.calc_excess_data_gas(\n            BlockHeaderDataGasFields(parent_excess_data_gas, parent_consumed_data_gas)\n        )\n\n    @classmethod\n    def get_min_excess_data_gas_for_data_gas_price(cls, data_gas_price: int) -> int:\n\"\"\"\n        Gets the minimum required excess data gas value to get a given data gas cost in a block\n        \"\"\"\n        current_excess_data_gas = 0\n        current_data_gas_price = 1\n        while current_data_gas_price < data_gas_price:\n            current_excess_data_gas += Spec.DATA_GAS_PER_BLOB.value\n            current_data_gas_price = Spec.get_data_gasprice(\n                excess_data_gas=current_excess_data_gas\n            )\n        return current_excess_data_gas\n\n    @classmethod\n    def get_min_excess_data_blobs_for_data_gas_price(cls, data_gas_price: int) -> int:\n\"\"\"\n        Gets the minimum required excess data blobs to get a given data gas cost in a block\n        \"\"\"\n        return (\n            cls.get_min_excess_data_gas_for_data_gas_price(data_gas_price)\n            // Spec.DATA_GAS_PER_BLOB.value\n        )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs/#tests.cancun.eip4844_blobs.test_blob_txs.test_valid_blob_tx_combinations","title":"test_valid_blob_tx_combinations(blockchain_test, pre, env, blocks)","text":"

Test all valid blob combinations in a single block, assuming a given value of MAX_BLOBS_PER_BLOCK.

This assumes a block can include from 1 and up to MAX_BLOBS_PER_BLOCK transactions where all transactions contain at least 1 blob, and the sum of all blobs in a block is at most MAX_BLOBS_PER_BLOCK.

This test is parametrized with all valid blob transaction combinations for a given block, and therefore if value of MAX_BLOBS_PER_BLOCK changes, this test is automatically updated.

Source code in tests/cancun/eip4844_blobs/test_blob_txs.py
@pytest.mark.parametrize(\n    \"blobs_per_tx\",\n    all_valid_blob_combinations(),\n)\n@pytest.mark.valid_from(\"Cancun\")\ndef test_valid_blob_tx_combinations(\n    blockchain_test: BlockchainTestFiller,\n    pre: Dict,\n    env: Environment,\n    blocks: List[Block],\n):\n\"\"\"\n    Test all valid blob combinations in a single block, assuming a given value of\n    `MAX_BLOBS_PER_BLOCK`.\n\n    This assumes a block can include from 1 and up to `MAX_BLOBS_PER_BLOCK` transactions where all\n    transactions contain at least 1 blob, and the sum of all blobs in a block is at\n    most `MAX_BLOBS_PER_BLOCK`.\n\n    This test is parametrized with all valid blob transaction combinations for a given block, and\n    therefore if value of `MAX_BLOBS_PER_BLOCK` changes, this test is automatically updated.\n    \"\"\"\n    blockchain_test(\n        pre=pre,\n        post={},\n        blocks=blocks,\n        genesis_environment=env,\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs/#tests.cancun.eip4844_blobs.test_blob_txs.test_invalid_tx_max_fee_per_data_gas","title":"test_invalid_tx_max_fee_per_data_gas(blockchain_test, pre, env, blocks, parent_blobs, block_intermediate)","text":"

Reject blocks with invalid blob txs due to:

  • tx max_fee_per_data_gas is barely not enough
  • tx max_fee_per_data_gas is zero
Source code in tests/cancun/eip4844_blobs/test_blob_txs.py
@pytest.mark.parametrize(\n    \"parent_excess_blobs,parent_blobs,tx_max_fee_per_data_gas,tx_error\",\n    [\n        # tx max_data_gas_cost of the transaction is not enough\n        (\n            SpecHelpers.get_min_excess_data_blobs_for_data_gas_price(2) - 1,  # data gas price is 1\n            SpecHelpers.target_blobs_per_block() + 1,  # data gas cost increases to 2\n            1,  # tx max_data_gas_cost is 1\n            \"insufficient max fee per data gas\",\n        ),\n        # tx max_data_gas_cost of the transaction is zero, which is invalid\n        (\n            0,  # data gas price is 1\n            0,  # data gas cost stays put at 1\n            0,  # tx max_data_gas_cost is 0\n            \"invalid max fee per data gas\",\n        ),\n    ],\n    ids=[\"insufficient_max_fee_per_data_gas\", \"invalid_max_fee_per_data_gas\"],\n)\n@pytest.mark.valid_from(\"Cancun\")\ndef test_invalid_tx_max_fee_per_data_gas(\n    blockchain_test: BlockchainTestFiller,\n    pre: Dict,\n    env: Environment,\n    blocks: List[Block],\n    parent_blobs: int,\n    block_intermediate: Block,\n):\n\"\"\"\n    Reject blocks with invalid blob txs due to:\n\n    - tx max_fee_per_data_gas is barely not enough\n    - tx max_fee_per_data_gas is zero\n    \"\"\"\n    if parent_blobs:\n        pre[TestAddress2] = Account(balance=10**9)\n        blocks.insert(0, block_intermediate)\n        if env.excess_data_gas is not None:\n            env.excess_data_gas += Spec.TARGET_DATA_GAS_PER_BLOCK\n    blockchain_test(\n        pre=pre,\n        post={},\n        blocks=blocks,\n        genesis_environment=env,\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs/#tests.cancun.eip4844_blobs.test_blob_txs.test_invalid_normal_gas","title":"test_invalid_normal_gas(blockchain_test, pre, env, blocks)","text":"

Reject blocks with invalid blob txs due to:

  • Sufficient max fee per data gas, but insufficient max fee per gas
Source code in tests/cancun/eip4844_blobs/test_blob_txs.py
@pytest.mark.parametrize(\n    \"tx_max_fee_per_gas,tx_error\",\n    [\n        # max data gas is ok, but max fee per gas is less than base fee per gas\n        (\n            6,\n            \"insufficient max fee per gas\",\n        ),\n    ],\n    ids=[\"insufficient_max_fee_per_gas\"],\n)\n@pytest.mark.valid_from(\"Cancun\")\ndef test_invalid_normal_gas(\n    blockchain_test: BlockchainTestFiller,\n    pre: Dict,\n    env: Environment,\n    blocks: List[Block],\n):\n\"\"\"\n    Reject blocks with invalid blob txs due to:\n\n    - Sufficient max fee per data gas, but insufficient max fee per gas\n    \"\"\"\n    blockchain_test(\n        pre=pre,\n        post={},\n        blocks=blocks,\n        genesis_environment=env,\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs/#tests.cancun.eip4844_blobs.test_blob_txs.test_invalid_block_blob_count","title":"test_invalid_block_blob_count(blockchain_test, pre, env, blocks)","text":"

Test all invalid blob combinations in a single block, where the sum of all blobs in a block is at MAX_BLOBS_PER_BLOCK + 1.

This test is parametrized with all blob transaction combinations exceeding MAX_BLOBS_PER_BLOCK by one for a given block, and therefore if value of MAX_BLOBS_PER_BLOCK changes, this test is automatically updated.

Source code in tests/cancun/eip4844_blobs/test_blob_txs.py
@pytest.mark.parametrize(\n    \"blobs_per_tx\",\n    invalid_blob_combinations(),\n)\n@pytest.mark.parametrize(\"tx_error\", [\"invalid_blob_count\"])\n@pytest.mark.valid_from(\"Cancun\")\ndef test_invalid_block_blob_count(\n    blockchain_test: BlockchainTestFiller,\n    pre: Dict,\n    env: Environment,\n    blocks: List[Block],\n):\n\"\"\"\n    Test all invalid blob combinations in a single block, where the sum of all blobs in a block is\n    at `MAX_BLOBS_PER_BLOCK + 1`.\n\n    This test is parametrized with all blob transaction combinations exceeding\n    `MAX_BLOBS_PER_BLOCK` by one for a given block, and\n    therefore if value of `MAX_BLOBS_PER_BLOCK` changes, this test is automatically updated.\n    \"\"\"\n    blockchain_test(\n        pre=pre,\n        post={},\n        blocks=blocks,\n        genesis_environment=env,\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs/#tests.cancun.eip4844_blobs.test_blob_txs.test_insufficient_balance_blob_tx","title":"test_insufficient_balance_blob_tx(blockchain_test, pre, env, blocks)","text":"

Reject blocks where user cannot afford the data gas specified (but max_fee_per_gas would be enough for current block), including:

  • Transactions with and without priority fee
  • Transactions with and without value
  • Transactions with and without calldata
  • Transactions with max fee per data gas lower or higher than the priority fee
Source code in tests/cancun/eip4844_blobs/test_blob_txs.py
@pytest.mark.parametrize(\"tx_max_priority_fee_per_gas\", [0, 8])\n@pytest.mark.parametrize(\"tx_value\", [0, 1])\n@pytest.mark.parametrize(\n    \"tx_calldata\",\n    [b\"\", b\"\\x00\", b\"\\x01\"],\n    ids=[\"no_calldata\", \"single_zero_calldata\", \"single_one_calldata\"],\n)\n@pytest.mark.parametrize(\"tx_max_fee_per_data_gas\", [1, 100, 10000])\n@pytest.mark.parametrize(\"account_balance_modifier\", [-1], ids=[\"exact_balance_minus_1\"])\n@pytest.mark.parametrize(\"tx_error\", [\"insufficient_account_balance\"], ids=[\"\"])\n@pytest.mark.valid_from(\"Cancun\")\ndef test_insufficient_balance_blob_tx(\n    blockchain_test: BlockchainTestFiller,\n    pre: Dict,\n    env: Environment,\n    blocks: List[Block],\n):\n\"\"\"\n    Reject blocks where user cannot afford the data gas specified (but\n    max_fee_per_gas would be enough for current block), including:\n\n    - Transactions with and without priority fee\n    - Transactions with and without value\n    - Transactions with and without calldata\n    - Transactions with max fee per data gas lower or higher than the priority fee\n    \"\"\"\n    blockchain_test(\n        pre=pre,\n        post={},\n        blocks=blocks,\n        genesis_environment=env,\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs/#tests.cancun.eip4844_blobs.test_blob_txs.test_insufficient_balance_blob_tx_combinations","title":"test_insufficient_balance_blob_tx_combinations(blockchain_test, pre, env, blocks)","text":"

Reject all valid blob transaction combinations in a block, but block is invalid due to:

  • The amount of blobs is correct but the user cannot afford the transaction total cost
Source code in tests/cancun/eip4844_blobs/test_blob_txs.py
@pytest.mark.parametrize(\n    \"blobs_per_tx\",\n    all_valid_blob_combinations(),\n)\n@pytest.mark.parametrize(\"account_balance_modifier\", [-1], ids=[\"exact_balance_minus_1\"])\n@pytest.mark.parametrize(\"tx_error\", [\"insufficient_account_balance\"], ids=[\"\"])\n@pytest.mark.valid_from(\"Cancun\")\ndef test_insufficient_balance_blob_tx_combinations(\n    blockchain_test: BlockchainTestFiller,\n    pre: Dict,\n    env: Environment,\n    blocks: List[Block],\n):\n\"\"\"\n    Reject all valid blob transaction combinations in a block, but block is invalid due to:\n\n    - The amount of blobs is correct but the user cannot afford the\n            transaction total cost\n    \"\"\"\n    blockchain_test(\n        pre=pre,\n        post={},\n        blocks=blocks,\n        genesis_environment=env,\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs/#tests.cancun.eip4844_blobs.test_blob_txs.test_invalid_tx_blob_count","title":"test_invalid_tx_blob_count(blockchain_test, pre, env, blocks)","text":"

Reject blocks that include blob transactions with invalid blob counts:

  • blob count == 0 in type 3 transaction
  • blob count > MAX_BLOBS_PER_BLOCK in type 3 transaction
Source code in tests/cancun/eip4844_blobs/test_blob_txs.py
@pytest.mark.parametrize(\n    \"blobs_per_tx,tx_error\",\n    [\n        ([0], \"zero_blob_tx\"),\n        ([SpecHelpers.max_blobs_per_block() + 1], \"too_many_blobs_tx\"),\n    ],\n    ids=[\"too_few_blobs\", \"too_many_blobs\"],\n)\n@pytest.mark.valid_from(\"Cancun\")\ndef test_invalid_tx_blob_count(\n    blockchain_test: BlockchainTestFiller,\n    pre: Dict,\n    env: Environment,\n    blocks: List[Block],\n):\n\"\"\"\n    Reject blocks that include blob transactions with invalid blob counts:\n\n    - `blob count == 0` in type 3 transaction\n    - `blob count > MAX_BLOBS_PER_BLOCK` in type 3 transaction\n    \"\"\"\n    blockchain_test(\n        pre=pre,\n        post={},\n        blocks=blocks,\n        genesis_environment=env,\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs/#tests.cancun.eip4844_blobs.test_blob_txs.test_invalid_blob_hash_versioning","title":"test_invalid_blob_hash_versioning(blockchain_test, pre, env, blocks)","text":"

Reject blocks that include blob transactions with invalid blob hash version, including:

  • Single blob transaction with single blob with invalid version
  • Single blob transaction with multiple blobs all with invalid version
  • Single blob transaction with multiple blobs either with invalid version
  • Multiple blob transactions with single blob all with invalid version
  • Multiple blob transactions with multiple blobs all with invalid version
  • Multiple blob transactions with multiple blobs only one with invalid version
Source code in tests/cancun/eip4844_blobs/test_blob_txs.py
@pytest.mark.parametrize(\n    \"blob_hashes_per_tx\",\n    [\n        [[to_hash_bytes(1)]],\n        [[to_hash_bytes(x) for x in range(2)]],\n        [\n            add_kzg_version([to_hash_bytes(1)], Spec.BLOB_COMMITMENT_VERSION_KZG)\n            + [to_hash_bytes(2)]\n        ],\n        [\n            [to_hash_bytes(1)]\n            + add_kzg_version([to_hash_bytes(2)], Spec.BLOB_COMMITMENT_VERSION_KZG)\n        ],\n        [\n            add_kzg_version([to_hash_bytes(1)], Spec.BLOB_COMMITMENT_VERSION_KZG),\n            [to_hash_bytes(2)],\n        ],\n        [\n            add_kzg_version([to_hash_bytes(1)], Spec.BLOB_COMMITMENT_VERSION_KZG),\n            [to_hash_bytes(x) for x in range(1, 3)],\n        ],\n        [\n            add_kzg_version([to_hash_bytes(1)], Spec.BLOB_COMMITMENT_VERSION_KZG),\n            [to_hash_bytes(2)]\n            + add_kzg_version([to_hash_bytes(3)], Spec.BLOB_COMMITMENT_VERSION_KZG),\n        ],\n        [\n            add_kzg_version([to_hash_bytes(1)], Spec.BLOB_COMMITMENT_VERSION_KZG),\n            add_kzg_version([to_hash_bytes(2)], Spec.BLOB_COMMITMENT_VERSION_KZG),\n            [to_hash_bytes(3)],\n        ],\n    ],\n    ids=[\n        \"single_tx_single_blob\",\n        \"single_tx_multiple_blobs\",\n        \"single_tx_multiple_blobs_single_bad_hash_1\",\n        \"single_tx_multiple_blobs_single_bad_hash_2\",\n        \"multiple_txs_single_blob\",\n        \"multiple_txs_multiple_blobs\",\n        \"multiple_txs_multiple_blobs_single_bad_hash_1\",\n        \"multiple_txs_multiple_blobs_single_bad_hash_2\",\n    ],\n)\n@pytest.mark.parametrize(\"tx_error\", [\"invalid_versioned_hash\"], ids=[\"\"])\n@pytest.mark.valid_from(\"Cancun\")\ndef test_invalid_blob_hash_versioning(\n    blockchain_test: BlockchainTestFiller,\n    pre: Dict,\n    env: Environment,\n    blocks: List[Block],\n):\n\"\"\"\n    Reject blocks that include blob transactions with invalid blob hash\n    version, including:\n\n    - Single blob transaction with single blob with invalid version\n    - Single blob transaction with multiple blobs all with invalid version\n    - Single blob transaction with multiple blobs either with invalid version\n    - Multiple blob transactions with single blob all with invalid version\n    - Multiple blob transactions with multiple blobs all with invalid version\n    - Multiple blob transactions with multiple blobs only one with invalid version\n    \"\"\"\n    blockchain_test(\n        pre=pre,\n        post={},\n        blocks=blocks,\n        genesis_environment=env,\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs/#tests.cancun.eip4844_blobs.test_blob_txs.test_invalid_blob_tx_contract_creation","title":"test_invalid_blob_tx_contract_creation(blockchain_test, pre, env, blocks)","text":"

Reject blocks that include blob transactions that have nil to value (contract creating).

Source code in tests/cancun/eip4844_blobs/test_blob_txs.py
@pytest.mark.parametrize(\n    \"destination_account,tx_error\", [(None, \"no_contract_creating_blob_txs\")], ids=[\"\"]\n)\n@pytest.mark.valid_from(\"Cancun\")\ndef test_invalid_blob_tx_contract_creation(\n    blockchain_test: BlockchainTestFiller,\n    pre: Dict,\n    env: Environment,\n    blocks: List[Block],\n):\n\"\"\"\n    Reject blocks that include blob transactions that have nil to value (contract creating).\n    \"\"\"\n    blockchain_test(\n        pre=pre,\n        post={},\n        blocks=blocks,\n        genesis_environment=env,\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs/#tests.cancun.eip4844_blobs.test_blob_txs.test_blob_tx_attribute_opcodes","title":"test_blob_tx_attribute_opcodes(blockchain_test, pre, opcode, env, blocks, destination_account)","text":"

Test opcodes that read transaction attributes work properly for blob type transactions:

  • ORIGIN
  • CALLER
Source code in tests/cancun/eip4844_blobs/test_blob_txs.py
@pytest.mark.parametrize(\n    \"opcode\",\n    [Op.ORIGIN, Op.CALLER],\n    indirect=[\"opcode\"],\n)\n@pytest.mark.parametrize(\"tx_gas\", [500_000])\n@pytest.mark.valid_from(\"Cancun\")\ndef test_blob_tx_attribute_opcodes(\n    blockchain_test: BlockchainTestFiller,\n    pre: Dict,\n    opcode: Tuple[bytes, Storage.StorageDictType],\n    env: Environment,\n    blocks: List[Block],\n    destination_account: str,\n):\n\"\"\"\n    Test opcodes that read transaction attributes work properly for blob type transactions:\n\n    - ORIGIN\n    - CALLER\n    \"\"\"\n    code, storage = opcode\n    pre[destination_account] = Account(code=code)\n    post = {\n        destination_account: Account(\n            storage=storage,\n        )\n    }\n    blockchain_test(\n        pre=pre,\n        post=post,\n        blocks=blocks,\n        genesis_environment=env,\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs/#tests.cancun.eip4844_blobs.test_blob_txs.test_blob_tx_attribute_value_opcode","title":"test_blob_tx_attribute_value_opcode(blockchain_test, pre, opcode, env, blocks, tx_value, destination_account)","text":"

Test the VALUE opcode with different blob type transaction value amounts.

Source code in tests/cancun/eip4844_blobs/test_blob_txs.py
@pytest.mark.parametrize(\"opcode\", [Op.CALLVALUE], indirect=[\"opcode\"])\n@pytest.mark.parametrize(\"tx_value\", [0, 1, int(1e18)])\n@pytest.mark.parametrize(\"tx_gas\", [500_000])\n@pytest.mark.valid_from(\"Cancun\")\ndef test_blob_tx_attribute_value_opcode(\n    blockchain_test: BlockchainTestFiller,\n    pre: Dict,\n    opcode: Tuple[bytes, Storage.StorageDictType],\n    env: Environment,\n    blocks: List[Block],\n    tx_value: int,\n    destination_account: str,\n):\n\"\"\"\n    Test the VALUE opcode with different blob type transaction value amounts.\n    \"\"\"\n    code, storage = opcode\n    pre[destination_account] = Account(code=code)\n    post = {\n        destination_account: Account(\n            storage=storage,\n            balance=tx_value,\n        )\n    }\n    blockchain_test(\n        pre=pre,\n        post=post,\n        blocks=blocks,\n        genesis_environment=env,\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs/#tests.cancun.eip4844_blobs.test_blob_txs.test_blob_tx_attribute_calldata_opcodes","title":"test_blob_tx_attribute_calldata_opcodes(blockchain_test, pre, opcode, env, blocks, destination_account)","text":"

Test calldata related opcodes to verify their behavior is not affected by blobs:

  • CALLDATALOAD
  • CALLDATASIZE
  • CALLDATACOPY
Source code in tests/cancun/eip4844_blobs/test_blob_txs.py
@pytest.mark.parametrize(\n    \"opcode\",\n    [\n        Op.CALLDATALOAD,\n        Op.CALLDATASIZE,\n        Op.CALLDATACOPY,\n    ],\n    indirect=True,\n)\n@pytest.mark.parametrize(\n    \"tx_calldata\",\n    [\n        b\"\",\n        b\"\\x01\",\n        b\"\\x00\\x01\" * 16,\n    ],\n    ids=[\"empty\", \"single_byte\", \"word\"],\n)\n@pytest.mark.parametrize(\"tx_gas\", [500_000])\n@pytest.mark.valid_from(\"Cancun\")\ndef test_blob_tx_attribute_calldata_opcodes(\n    blockchain_test: BlockchainTestFiller,\n    pre: Dict,\n    opcode: Tuple[bytes, Storage.StorageDictType],\n    env: Environment,\n    blocks: List[Block],\n    destination_account: str,\n):\n\"\"\"\n    Test calldata related opcodes to verify their behavior is not affected by blobs:\n\n    - CALLDATALOAD\n    - CALLDATASIZE\n    - CALLDATACOPY\n    \"\"\"\n    code, storage = opcode\n    pre[destination_account] = Account(code=code)\n    post = {\n        destination_account: Account(\n            storage=storage,\n        )\n    }\n    blockchain_test(\n        pre=pre,\n        post=post,\n        blocks=blocks,\n        genesis_environment=env,\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs/#tests.cancun.eip4844_blobs.test_blob_txs.test_blob_tx_attribute_gasprice_opcode","title":"test_blob_tx_attribute_gasprice_opcode(blockchain_test, pre, opcode, env, blocks, destination_account)","text":"

Test GASPRICE opcode to sanity check that the data fee per gas does not affect its calculation:

  • No priority fee
  • Priority fee below data fee
  • Priority fee above data fee
Source code in tests/cancun/eip4844_blobs/test_blob_txs.py
@pytest.mark.parametrize(\"tx_max_priority_fee_per_gas\", [0, 2])  # always below data fee\n@pytest.mark.parametrize(\"tx_max_fee_per_data_gas\", [1, 3])  # normal and above priority fee\n@pytest.mark.parametrize(\"tx_max_fee_per_gas\", [100])  # always above priority fee\n@pytest.mark.parametrize(\"opcode\", [Op.GASPRICE], indirect=True)\n@pytest.mark.parametrize(\"tx_gas\", [500_000])\n@pytest.mark.valid_from(\"Cancun\")\ndef test_blob_tx_attribute_gasprice_opcode(\n    blockchain_test: BlockchainTestFiller,\n    pre: Dict,\n    opcode: Tuple[bytes, Storage.StorageDictType],\n    env: Environment,\n    blocks: List[Block],\n    destination_account: str,\n):\n\"\"\"\n    Test GASPRICE opcode to sanity check that the data fee per gas does not affect\n    its calculation:\n\n    - No priority fee\n    - Priority fee below data fee\n    - Priority fee above data fee\n    \"\"\"\n    code, storage = opcode\n    pre[destination_account] = Account(code=code)\n    post = {\n        destination_account: Account(\n            storage=storage,\n        )\n    }\n    blockchain_test(\n        pre=pre,\n        post=post,\n        blocks=blocks,\n        genesis_environment=env,\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs/#tests.cancun.eip4844_blobs.test_blob_txs.test_blob_type_tx_pre_fork","title":"test_blob_type_tx_pre_fork(blockchain_test, pre, blocks)","text":"

Reject blocks with blob type transactions before Cancun fork

Source code in tests/cancun/eip4844_blobs/test_blob_txs.py
@pytest.mark.parametrize(\n    [\n        \"blobs_per_tx\",\n        \"parent_excess_blobs\",\n        \"tx_max_fee_per_data_gas\",\n        \"tx_error\",\n    ],\n    [\n        ([0], None, 1, \"tx_type_3_not_allowed_yet\"),\n        ([1], None, 1, \"tx_type_3_not_allowed_yet\"),\n    ],\n    ids=[\"no_blob_tx\", \"one_blob_tx\"],\n)\n@pytest.mark.valid_at_transition_to(\"Cancun\")\ndef test_blob_type_tx_pre_fork(\n    blockchain_test: BlockchainTestFiller,\n    pre: Dict,\n    blocks: List[Block],\n):\n\"\"\"\n    Reject blocks with blob type transactions before Cancun fork\n    \"\"\"\n    blockchain_test(\n        pre=pre,\n        post={},\n        blocks=blocks,\n        genesis_environment=Environment(),  # `env` fixture has blob fields\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs/index/test_cases/","title":"Test Blob Txs - Test Cases","text":"

Test cases generated from tests/cancun/eip4844_blobs/test_blob_txs.py

Parametrized test cases generated from the test module tests/cancun/eip4844_blobs/test_blob_txs.py:

test_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(1, 1, 1, 1, 1, 1)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(1, 1, 1, 1, 1)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(1, 1, 1, 1, 2)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(1, 1, 1, 1)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(1, 1, 1, 2)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(1, 1, 1, 3)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(1, 1, 2, 2)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(1, 1, 1)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(1, 1, 2)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(1, 1, 3)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(1, 1, 4)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(1, 2, 2)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(1, 2, 3)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(2, 2, 2)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(1, 1)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(1, 2)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(1, 3)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(1, 4)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(1, 5)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(2, 2)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(2, 3)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(2, 4)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(3, 3)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(1,)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(2,)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(3,)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(4,)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(5,)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(6,)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(2, 1, 1, 1, 1)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(2, 1, 1, 1)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(3, 1, 1, 1)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(2, 2, 1, 1)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(2, 1, 1)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(3, 1, 1)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(4, 1, 1)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(2, 2, 1)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(3, 2, 1)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(2, 1)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(3, 1)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(4, 1)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(5, 1)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(3, 2)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(4, 2)]\ntest_invalid_tx_max_fee_per_data_gas[fork=Cancun-insufficient_max_fee_per_data_gas]\ntest_invalid_tx_max_fee_per_data_gas[fork=Cancun-invalid_max_fee_per_data_gas]\ntest_invalid_normal_gas[fork=Cancun-insufficient_max_fee_per_gas]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(1, 1, 1, 1, 1, 1, 1)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(1, 1, 1, 1, 1, 2)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(1, 1, 1, 1, 3)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(1, 1, 1, 2, 2)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(1, 1, 1, 4)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(1, 1, 2, 3)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(1, 2, 2, 2)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(1, 1, 5)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(1, 2, 4)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(1, 3, 3)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(2, 2, 3)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(1, 6)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(2, 5)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(3, 4)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(7,)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(2, 1, 1, 1, 1, 1)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(3, 1, 1, 1, 1)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(2, 2, 1, 1, 1)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(4, 1, 1, 1)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(3, 2, 1, 1)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(2, 2, 2, 1)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(5, 1, 1)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(4, 2, 1)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(3, 3, 1)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(3, 2, 2)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(6, 1)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(5, 2)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(4, 3)]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=1-no_calldata-tx_value=0-tx_max_priority_fee_per_gas=0]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=1-no_calldata-tx_value=0-tx_max_priority_fee_per_gas=8]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=1-no_calldata-tx_value=1-tx_max_priority_fee_per_gas=0]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=1-no_calldata-tx_value=1-tx_max_priority_fee_per_gas=8]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=1-single_zero_calldata-tx_value=0-tx_max_priority_fee_per_gas=0]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=1-single_zero_calldata-tx_value=0-tx_max_priority_fee_per_gas=8]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=1-single_zero_calldata-tx_value=1-tx_max_priority_fee_per_gas=0]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=1-single_zero_calldata-tx_value=1-tx_max_priority_fee_per_gas=8]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=1-single_one_calldata-tx_value=0-tx_max_priority_fee_per_gas=0]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=1-single_one_calldata-tx_value=0-tx_max_priority_fee_per_gas=8]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=1-single_one_calldata-tx_value=1-tx_max_priority_fee_per_gas=0]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=1-single_one_calldata-tx_value=1-tx_max_priority_fee_per_gas=8]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=100-no_calldata-tx_value=0-tx_max_priority_fee_per_gas=0]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=100-no_calldata-tx_value=0-tx_max_priority_fee_per_gas=8]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=100-no_calldata-tx_value=1-tx_max_priority_fee_per_gas=0]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=100-no_calldata-tx_value=1-tx_max_priority_fee_per_gas=8]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=100-single_zero_calldata-tx_value=0-tx_max_priority_fee_per_gas=0]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=100-single_zero_calldata-tx_value=0-tx_max_priority_fee_per_gas=8]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=100-single_zero_calldata-tx_value=1-tx_max_priority_fee_per_gas=0]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=100-single_zero_calldata-tx_value=1-tx_max_priority_fee_per_gas=8]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=100-single_one_calldata-tx_value=0-tx_max_priority_fee_per_gas=0]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=100-single_one_calldata-tx_value=0-tx_max_priority_fee_per_gas=8]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=100-single_one_calldata-tx_value=1-tx_max_priority_fee_per_gas=0]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=100-single_one_calldata-tx_value=1-tx_max_priority_fee_per_gas=8]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=10000-no_calldata-tx_value=0-tx_max_priority_fee_per_gas=0]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=10000-no_calldata-tx_value=0-tx_max_priority_fee_per_gas=8]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=10000-no_calldata-tx_value=1-tx_max_priority_fee_per_gas=0]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=10000-no_calldata-tx_value=1-tx_max_priority_fee_per_gas=8]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=10000-single_zero_calldata-tx_value=0-tx_max_priority_fee_per_gas=0]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=10000-single_zero_calldata-tx_value=0-tx_max_priority_fee_per_gas=8]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=10000-single_zero_calldata-tx_value=1-tx_max_priority_fee_per_gas=0]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=10000-single_zero_calldata-tx_value=1-tx_max_priority_fee_per_gas=8]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=10000-single_one_calldata-tx_value=0-tx_max_priority_fee_per_gas=0]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=10000-single_one_calldata-tx_value=0-tx_max_priority_fee_per_gas=8]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=10000-single_one_calldata-tx_value=1-tx_max_priority_fee_per_gas=0]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=10000-single_one_calldata-tx_value=1-tx_max_priority_fee_per_gas=8]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(1, 1, 1, 1, 1, 1)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(1, 1, 1, 1, 1)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(1, 1, 1, 1, 2)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(1, 1, 1, 1)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(1, 1, 1, 2)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(1, 1, 1, 3)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(1, 1, 2, 2)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(1, 1, 1)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(1, 1, 2)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(1, 1, 3)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(1, 1, 4)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(1, 2, 2)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(1, 2, 3)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(2, 2, 2)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(1, 1)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(1, 2)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(1, 3)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(1, 4)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(1, 5)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(2, 2)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(2, 3)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(2, 4)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(3, 3)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(1,)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(2,)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(3,)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(4,)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(5,)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(6,)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(2, 1, 1, 1, 1)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(2, 1, 1, 1)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(3, 1, 1, 1)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(2, 2, 1, 1)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(2, 1, 1)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(3, 1, 1)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(4, 1, 1)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(2, 2, 1)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(3, 2, 1)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(2, 1)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(3, 1)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(4, 1)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(5, 1)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(3, 2)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(4, 2)]\ntest_invalid_tx_blob_count[fork=Cancun-too_few_blobs]\ntest_invalid_tx_blob_count[fork=Cancun-too_many_blobs]\ntest_invalid_blob_hash_versioning[fork=Cancun--single_tx_single_blob]\ntest_invalid_blob_hash_versioning[fork=Cancun--single_tx_multiple_blobs]\ntest_invalid_blob_hash_versioning[fork=Cancun--single_tx_multiple_blobs_single_bad_hash_1]\ntest_invalid_blob_hash_versioning[fork=Cancun--single_tx_multiple_blobs_single_bad_hash_2]\ntest_invalid_blob_hash_versioning[fork=Cancun--multiple_txs_single_blob]\ntest_invalid_blob_hash_versioning[fork=Cancun--multiple_txs_multiple_blobs]\ntest_invalid_blob_hash_versioning[fork=Cancun--multiple_txs_multiple_blobs_single_bad_hash_1]\ntest_invalid_blob_hash_versioning[fork=Cancun--multiple_txs_multiple_blobs_single_bad_hash_2]\ntest_invalid_blob_tx_contract_creation[fork=Cancun-]\ntest_blob_tx_attribute_opcodes[fork=Cancun-tx_gas=500000-opcode=ORIGIN]\ntest_blob_tx_attribute_opcodes[fork=Cancun-tx_gas=500000-opcode=CALLER]\ntest_blob_tx_attribute_value_opcode[fork=Cancun-tx_gas=500000-tx_value=0-opcode=CALLVALUE]\ntest_blob_tx_attribute_value_opcode[fork=Cancun-tx_gas=500000-tx_value=1-opcode=CALLVALUE]\ntest_blob_tx_attribute_value_opcode[fork=Cancun-tx_gas=500000-tx_value=1000000000000000000-opcode=CALLVALUE]\ntest_blob_tx_attribute_calldata_opcodes[fork=Cancun-tx_gas=500000-empty-opcode=CALLDATALOAD]\ntest_blob_tx_attribute_calldata_opcodes[fork=Cancun-tx_gas=500000-empty-opcode=CALLDATASIZE]\ntest_blob_tx_attribute_calldata_opcodes[fork=Cancun-tx_gas=500000-empty-opcode=CALLDATACOPY]\ntest_blob_tx_attribute_calldata_opcodes[fork=Cancun-tx_gas=500000-single_byte-opcode=CALLDATALOAD]\ntest_blob_tx_attribute_calldata_opcodes[fork=Cancun-tx_gas=500000-single_byte-opcode=CALLDATASIZE]\ntest_blob_tx_attribute_calldata_opcodes[fork=Cancun-tx_gas=500000-single_byte-opcode=CALLDATACOPY]\ntest_blob_tx_attribute_calldata_opcodes[fork=Cancun-tx_gas=500000-word-opcode=CALLDATALOAD]\ntest_blob_tx_attribute_calldata_opcodes[fork=Cancun-tx_gas=500000-word-opcode=CALLDATASIZE]\ntest_blob_tx_attribute_calldata_opcodes[fork=Cancun-tx_gas=500000-word-opcode=CALLDATACOPY]\ntest_blob_tx_attribute_gasprice_opcode[fork=Cancun-tx_gas=500000-opcode=GASPRICE-tx_max_fee_per_gas=100-tx_max_fee_per_data_gas=1-tx_max_priority_fee_per_gas=0]\ntest_blob_tx_attribute_gasprice_opcode[fork=Cancun-tx_gas=500000-opcode=GASPRICE-tx_max_fee_per_gas=100-tx_max_fee_per_data_gas=1-tx_max_priority_fee_per_gas=2]\ntest_blob_tx_attribute_gasprice_opcode[fork=Cancun-tx_gas=500000-opcode=GASPRICE-tx_max_fee_per_gas=100-tx_max_fee_per_data_gas=3-tx_max_priority_fee_per_gas=0]\ntest_blob_tx_attribute_gasprice_opcode[fork=Cancun-tx_gas=500000-opcode=GASPRICE-tx_max_fee_per_gas=100-tx_max_fee_per_data_gas=3-tx_max_priority_fee_per_gas=2]\ntest_blob_type_tx_pre_fork[fork=ShanghaiToCancunAtTime15k-no_blob_tx]\ntest_blob_type_tx_pre_fork[fork=ShanghaiToCancunAtTime15k-one_blob_tx]\n

This output was extracted from the result of:

fill --collect-only -q --until Cancun tests/cancun/eip4844_blobs/test_blob_txs.py\n
"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs_full/","title":"Test Blob Txs Full","text":"

Documentation for tests/cancun/eip4844_blobs/test_blob_txs_full.py.

Generate fixtures for these test cases for Cancun with:

Cancun only:

fill -v tests/cancun/eip4844_blobs/test_blob_txs_full.py --fork=Cancun --evm-bin=/path/to/evm-tool-dev-version\n
For all forks up to and including Cancun:
fill -v tests/cancun/eip4844_blobs/test_blob_txs_full.py --until=Cancun --evm-bin=/path/to/evm-tool-dev-version\n

Tests full blob type transactions for EIP-4844: Shard Blob Transactions

Test full blob type transactions for EIP-4844: Shard Blob Transactions.

"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs_full/#tests.cancun.eip4844_blobs.test_blob_txs_full.Spec","title":"Spec dataclass","text":"

Bases: IntEnum

Parameters from the EIP-4844 specifications as defined at https://eips.ethereum.org/EIPS/eip-4844#parameters

If the parameter is not currently used within the tests, it is commented out.

Source code in tests/cancun/eip4844_blobs/spec.py
@dataclass(frozen=True)\nclass Spec(IntEnum):\n\"\"\"\n    Parameters from the EIP-4844 specifications as defined at\n    https://eips.ethereum.org/EIPS/eip-4844#parameters\n\n    If the parameter is not currently used within the tests, it is commented\n    out.\n    \"\"\"\n\n    BLOB_TX_TYPE = 0x03\n    FIELD_ELEMENTS_PER_BLOB = 4096\n    BLS_MODULUS = 0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001\n    BLOB_COMMITMENT_VERSION_KZG = 1\n    POINT_EVALUATION_PRECOMPILE_ADDRESS = 20\n    POINT_EVALUATION_PRECOMPILE_GAS = 50_000\n    MAX_DATA_GAS_PER_BLOCK = 786432\n    TARGET_DATA_GAS_PER_BLOCK = 393216\n    MIN_DATA_GASPRICE = 1\n    DATA_GASPRICE_UPDATE_FRACTION = 3338477\n    # MAX_VERSIONED_HASHES_LIST_SIZE = 2**24\n    # MAX_CALLDATA_SIZE = 2**24\n    # MAX_ACCESS_LIST_SIZE = 2**24\n    # MAX_ACCESS_LIST_STORAGE_KEYS = 2**24\n    # MAX_TX_WRAP_COMMITMENTS = 2**12\n    # LIMIT_BLOBS_PER_TX = 2**12\n    DATA_GAS_PER_BLOB = 2**17\n    HASH_OPCODE_BYTE = 0x49\n    HASH_GAS_COST = 3\n\n    @classmethod\n    def kzg_to_versioned_hash(\n        cls,\n        kzg_commitment: bytes | int,  # 48 bytes\n        blob_commitment_version_kzg: Optional[bytes | int] = None,\n    ) -> bytes:\n\"\"\"\n        Calculates the versioned hash for a given KZG commitment.\n        \"\"\"\n        if blob_commitment_version_kzg is None:\n            blob_commitment_version_kzg = cls.BLOB_COMMITMENT_VERSION_KZG\n        if isinstance(kzg_commitment, int):\n            kzg_commitment = kzg_commitment.to_bytes(48, \"big\")\n        if isinstance(blob_commitment_version_kzg, int):\n            blob_commitment_version_kzg = blob_commitment_version_kzg.to_bytes(1, \"big\")\n        return blob_commitment_version_kzg + sha256(kzg_commitment).digest()[1:]\n\n    @classmethod\n    def fake_exponential(cls, factor: int, numerator: int, denominator: int) -> int:\n\"\"\"\n        Used to calculate the data gas cost.\n        \"\"\"\n        i = 1\n        output = 0\n        numerator_accumulator = factor * denominator\n        while numerator_accumulator > 0:\n            output += numerator_accumulator\n            numerator_accumulator = (numerator_accumulator * numerator) // (denominator * i)\n            i += 1\n        return output // denominator\n\n    @classmethod\n    def calc_excess_data_gas(cls, parent: BlockHeaderDataGasFields) -> int:\n\"\"\"\n        Calculate the excess data gas for a block given the parent excess data gas\n        and the number of blobs in the block.\n        \"\"\"\n        if parent.excess_data_gas + parent.data_gas_used < cls.TARGET_DATA_GAS_PER_BLOCK:\n            return 0\n        else:\n            return parent.excess_data_gas + parent.data_gas_used - cls.TARGET_DATA_GAS_PER_BLOCK\n\n    # Note: Currently unused.\n    # @classmethod\n    # def get_total_data_gas(cls, tx: Transaction) -> int:\n    #     \"\"\"\n    #     Calculate the total data gas for a transaction.\n    #     \"\"\"\n    #     if tx.blob_versioned_hashes is None:\n    #         return 0\n    #     return cls.DATA_GAS_PER_BLOB.value * len(tx.blob_versioned_hashes)\n\n    @classmethod\n    def get_data_gasprice(cls, *, excess_data_gas: int) -> int:\n\"\"\"\n        Calculate the data gas price from the excess.\n        \"\"\"\n        return cls.fake_exponential(\n            cls.MIN_DATA_GASPRICE.value,\n            excess_data_gas,\n            cls.DATA_GASPRICE_UPDATE_FRACTION.value,\n        )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs_full/#tests.cancun.eip4844_blobs.test_blob_txs_full.SpecHelpers","title":"SpecHelpers dataclass","text":"

Bases: Enum

Define parameters and helper functions that are tightly coupled to the 4844 spec but not strictly part of it.

Source code in tests/cancun/eip4844_blobs/spec.py
@dataclass(frozen=True)\nclass SpecHelpers(Enum):\n\"\"\"\n    Define parameters and helper functions that are tightly coupled to the 4844\n    spec but not strictly part of it.\n    \"\"\"\n\n    BYTES_PER_FIELD_ELEMENT = 32\n\n    @classmethod\n    def max_blobs_per_block(cls) -> int:  # MAX_BLOBS_PER_BLOCK =\n\"\"\"\n        Returns the maximum number of blobs per block.\n        \"\"\"\n        return Spec.MAX_DATA_GAS_PER_BLOCK.value // Spec.DATA_GAS_PER_BLOB.value\n\n    @classmethod\n    def target_blobs_per_block(cls) -> int:\n\"\"\"\n        Returns the target number of blobs per block.\n        \"\"\"\n        return Spec.TARGET_DATA_GAS_PER_BLOCK.value // Spec.DATA_GAS_PER_BLOB.value\n\n    @classmethod\n    def calc_excess_data_gas_from_blob_count(\n        cls, parent_excess_data_gas: int, parent_blob_count: int\n    ) -> int:\n\"\"\"\n        Calculate the excess data gas for a block given the parent excess data gas\n        and the number of blobs in the block.\n        \"\"\"\n        parent_consumed_data_gas = parent_blob_count * Spec.DATA_GAS_PER_BLOB.value\n        return Spec.calc_excess_data_gas(\n            BlockHeaderDataGasFields(parent_excess_data_gas, parent_consumed_data_gas)\n        )\n\n    @classmethod\n    def get_min_excess_data_gas_for_data_gas_price(cls, data_gas_price: int) -> int:\n\"\"\"\n        Gets the minimum required excess data gas value to get a given data gas cost in a block\n        \"\"\"\n        current_excess_data_gas = 0\n        current_data_gas_price = 1\n        while current_data_gas_price < data_gas_price:\n            current_excess_data_gas += Spec.DATA_GAS_PER_BLOB.value\n            current_data_gas_price = Spec.get_data_gasprice(\n                excess_data_gas=current_excess_data_gas\n            )\n        return current_excess_data_gas\n\n    @classmethod\n    def get_min_excess_data_blobs_for_data_gas_price(cls, data_gas_price: int) -> int:\n\"\"\"\n        Gets the minimum required excess data blobs to get a given data gas cost in a block\n        \"\"\"\n        return (\n            cls.get_min_excess_data_gas_for_data_gas_price(data_gas_price)\n            // Spec.DATA_GAS_PER_BLOB.value\n        )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs_full/#tests.cancun.eip4844_blobs.test_blob_txs_full.test_reject_valid_full_blob_in_block_rlp","title":"test_reject_valid_full_blob_in_block_rlp(blockchain_test, pre, env, blocks)","text":"

Test valid blob combinations where one or more txs in the block serialized version contain a full blob (network version) tx.

Source code in tests/cancun/eip4844_blobs/test_blob_txs_full.py
@pytest.mark.parametrize(\n    \"txs_blobs,txs_wrapped_blobs\",\n    [\n        (\n            [  # Txs\n                [  # Blobs per transaction\n                    Blob(\n                        blob=bytes(\n                            Spec.FIELD_ELEMENTS_PER_BLOB.value\n                            * SpecHelpers.BYTES_PER_FIELD_ELEMENT.value\n                        ),\n                        kzg_commitment=INF_POINT,\n                        kzg_proof=INF_POINT,\n                    ),\n                ]\n            ],\n            [True],\n        ),\n        (\n            [  # Txs\n                [  # Blobs per transaction\n                    Blob(\n                        blob=bytes(\n                            Spec.FIELD_ELEMENTS_PER_BLOB.value\n                            * SpecHelpers.BYTES_PER_FIELD_ELEMENT.value\n                        ),\n                        kzg_commitment=INF_POINT,\n                        kzg_proof=INF_POINT,\n                    )\n                ]\n                for _ in range(SpecHelpers.max_blobs_per_block())\n            ],\n            [True] + ([False] * (SpecHelpers.max_blobs_per_block() - 1)),\n        ),\n        (\n            [  # Txs\n                [  # Blobs per transaction\n                    Blob(\n                        blob=bytes(\n                            Spec.FIELD_ELEMENTS_PER_BLOB.value\n                            * SpecHelpers.BYTES_PER_FIELD_ELEMENT.value\n                        ),\n                        kzg_commitment=INF_POINT,\n                        kzg_proof=INF_POINT,\n                    )\n                ]\n                for _ in range(SpecHelpers.max_blobs_per_block())\n            ],\n            ([False] * (SpecHelpers.max_blobs_per_block() - 1)) + [True],\n        ),\n    ],\n    ids=[\n        \"one_full_blob_one_tx\",\n        \"one_full_blob_max_txs\",\n        \"one_full_blob_at_the_end_max_txs\",\n    ],\n)\n@pytest.mark.valid_from(\"Cancun\")\ndef test_reject_valid_full_blob_in_block_rlp(\n    blockchain_test: BlockchainTestFiller,\n    pre: Dict,\n    env: Environment,\n    blocks: List[Block],\n):\n\"\"\"\n    Test valid blob combinations where one or more txs in the block\n    serialized version contain a full blob (network version) tx.\n    \"\"\"\n    blockchain_test(\n        pre=pre,\n        post={},\n        blocks=blocks,\n        genesis_environment=env,\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs_full/index/test_cases/","title":"Test Blob Txs Full - Test Cases","text":"

Test cases generated from tests/cancun/eip4844_blobs/test_blob_txs_full.py

Parametrized test cases generated from the test module tests/cancun/eip4844_blobs/test_blob_txs_full.py:

test_reject_valid_full_blob_in_block_rlp[fork=Cancun-one_full_blob_one_tx]\ntest_reject_valid_full_blob_in_block_rlp[fork=Cancun-one_full_blob_max_txs]\ntest_reject_valid_full_blob_in_block_rlp[fork=Cancun-one_full_blob_at_the_end_max_txs]\n

This output was extracted from the result of:

fill --collect-only -q --until Cancun tests/cancun/eip4844_blobs/test_blob_txs_full.py\n
"},{"location":"tests/cancun/eip4844_blobs/test_blobhash_opcode/","title":"Test Blobhash Opcode","text":"

Documentation for tests/cancun/eip4844_blobs/test_blobhash_opcode.py.

Generate fixtures for these test cases for Cancun with:

Cancun only:

fill -v tests/cancun/eip4844_blobs/test_blobhash_opcode.py --fork=Cancun --evm-bin=/path/to/evm-tool-dev-version\n
For all forks up to and including Cancun:
fill -v tests/cancun/eip4844_blobs/test_blobhash_opcode.py --until=Cancun --evm-bin=/path/to/evm-tool-dev-version\n

Tests BLOBHASH opcode in EIP-4844: Shard Blob Transactions

Test cases for the BLOBHASH opcode in EIP-4844: Shard Blob Transactions.

Adding a new test

Add a function that is named test_<test_name> and takes at least the following arguments:

  • blockchain_test
  • pre
  • tx
  • post

Additional custom pytest.fixture fixtures can be added and parametrized for new test cases.

There is no specific structure to follow within this test module.

"},{"location":"tests/cancun/eip4844_blobs/test_blobhash_opcode/#tests.cancun.eip4844_blobs.test_blobhash_opcode.Spec","title":"Spec dataclass","text":"

Bases: IntEnum

Parameters from the EIP-4844 specifications as defined at https://eips.ethereum.org/EIPS/eip-4844#parameters

If the parameter is not currently used within the tests, it is commented out.

Source code in tests/cancun/eip4844_blobs/spec.py
@dataclass(frozen=True)\nclass Spec(IntEnum):\n\"\"\"\n    Parameters from the EIP-4844 specifications as defined at\n    https://eips.ethereum.org/EIPS/eip-4844#parameters\n\n    If the parameter is not currently used within the tests, it is commented\n    out.\n    \"\"\"\n\n    BLOB_TX_TYPE = 0x03\n    FIELD_ELEMENTS_PER_BLOB = 4096\n    BLS_MODULUS = 0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001\n    BLOB_COMMITMENT_VERSION_KZG = 1\n    POINT_EVALUATION_PRECOMPILE_ADDRESS = 20\n    POINT_EVALUATION_PRECOMPILE_GAS = 50_000\n    MAX_DATA_GAS_PER_BLOCK = 786432\n    TARGET_DATA_GAS_PER_BLOCK = 393216\n    MIN_DATA_GASPRICE = 1\n    DATA_GASPRICE_UPDATE_FRACTION = 3338477\n    # MAX_VERSIONED_HASHES_LIST_SIZE = 2**24\n    # MAX_CALLDATA_SIZE = 2**24\n    # MAX_ACCESS_LIST_SIZE = 2**24\n    # MAX_ACCESS_LIST_STORAGE_KEYS = 2**24\n    # MAX_TX_WRAP_COMMITMENTS = 2**12\n    # LIMIT_BLOBS_PER_TX = 2**12\n    DATA_GAS_PER_BLOB = 2**17\n    HASH_OPCODE_BYTE = 0x49\n    HASH_GAS_COST = 3\n\n    @classmethod\n    def kzg_to_versioned_hash(\n        cls,\n        kzg_commitment: bytes | int,  # 48 bytes\n        blob_commitment_version_kzg: Optional[bytes | int] = None,\n    ) -> bytes:\n\"\"\"\n        Calculates the versioned hash for a given KZG commitment.\n        \"\"\"\n        if blob_commitment_version_kzg is None:\n            blob_commitment_version_kzg = cls.BLOB_COMMITMENT_VERSION_KZG\n        if isinstance(kzg_commitment, int):\n            kzg_commitment = kzg_commitment.to_bytes(48, \"big\")\n        if isinstance(blob_commitment_version_kzg, int):\n            blob_commitment_version_kzg = blob_commitment_version_kzg.to_bytes(1, \"big\")\n        return blob_commitment_version_kzg + sha256(kzg_commitment).digest()[1:]\n\n    @classmethod\n    def fake_exponential(cls, factor: int, numerator: int, denominator: int) -> int:\n\"\"\"\n        Used to calculate the data gas cost.\n        \"\"\"\n        i = 1\n        output = 0\n        numerator_accumulator = factor * denominator\n        while numerator_accumulator > 0:\n            output += numerator_accumulator\n            numerator_accumulator = (numerator_accumulator * numerator) // (denominator * i)\n            i += 1\n        return output // denominator\n\n    @classmethod\n    def calc_excess_data_gas(cls, parent: BlockHeaderDataGasFields) -> int:\n\"\"\"\n        Calculate the excess data gas for a block given the parent excess data gas\n        and the number of blobs in the block.\n        \"\"\"\n        if parent.excess_data_gas + parent.data_gas_used < cls.TARGET_DATA_GAS_PER_BLOCK:\n            return 0\n        else:\n            return parent.excess_data_gas + parent.data_gas_used - cls.TARGET_DATA_GAS_PER_BLOCK\n\n    # Note: Currently unused.\n    # @classmethod\n    # def get_total_data_gas(cls, tx: Transaction) -> int:\n    #     \"\"\"\n    #     Calculate the total data gas for a transaction.\n    #     \"\"\"\n    #     if tx.blob_versioned_hashes is None:\n    #         return 0\n    #     return cls.DATA_GAS_PER_BLOB.value * len(tx.blob_versioned_hashes)\n\n    @classmethod\n    def get_data_gasprice(cls, *, excess_data_gas: int) -> int:\n\"\"\"\n        Calculate the data gas price from the excess.\n        \"\"\"\n        return cls.fake_exponential(\n            cls.MIN_DATA_GASPRICE.value,\n            excess_data_gas,\n            cls.DATA_GASPRICE_UPDATE_FRACTION.value,\n        )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blobhash_opcode/#tests.cancun.eip4844_blobs.test_blobhash_opcode.test_blobhash_gas_cost","title":"test_blobhash_gas_cost(pre, template_tx, blocks, post, tx_type, blockchain_test)","text":"

Tests BLOBHASH opcode gas cost using a variety of indexes.

Asserts that the gas consumption of the BLOBHASH opcode is correct by ensuring it matches HASH_OPCODE_GAS = 3. Includes both valid and invalid random index sizes from the range [0, 2**256-1], for tx types 2 and 3.

Source code in tests/cancun/eip4844_blobs/test_blobhash_opcode.py
@pytest.mark.parametrize(\"tx_type\", [0, 1, 2, 3])\ndef test_blobhash_gas_cost(\n    pre,\n    template_tx,\n    blocks,\n    post,\n    tx_type,\n    blockchain_test: BlockchainTestFiller,\n):\n\"\"\"\n    Tests `BLOBHASH` opcode gas cost using a variety of indexes.\n\n    Asserts that the gas consumption of the `BLOBHASH` opcode is correct by ensuring\n    it matches `HASH_OPCODE_GAS = 3`. Includes both valid and invalid random\n    index sizes from the range `[0, 2**256-1]`, for tx types 2 and 3.\n    \"\"\"\n    assert (\n        Op.BLOBHASH.int() == Spec.HASH_OPCODE_BYTE\n    ), \"Opcodes blobhash byte doesn't match that defined in the spec\"\n    gas_measures_code = [\n        CodeGasMeasure(\n            code=Op.BLOBHASH(i),\n            overhead_cost=3,\n            extra_stack_items=1,\n        )\n        for i in blobhash_index_values\n    ]\n    for i, gas_code in enumerate(gas_measures_code):\n        address = to_address(0x100 + i * 0x100)\n        pre[address] = Account(code=gas_code)\n        blocks.append(\n            Block(\n                txs=[\n                    template_tx.with_fields(\n                        ty=tx_type,\n                        nonce=i,\n                        to=address,\n                        gas_price=10 if tx_type < 2 else None,\n                        access_list=[] if tx_type >= 2 else None,\n                        max_priority_fee_per_gas=10 if tx_type >= 2 else None,\n                        blob_versioned_hashes=random_blob_hashes[\n                            0 : SpecHelpers.target_blobs_per_block()\n                        ]\n                        if tx_type >= 3\n                        else None,\n                    )\n                ]\n            )\n        )\n        post[address] = Account(storage={0: Spec.HASH_GAS_COST.value})\n    blockchain_test(\n        pre=pre,\n        blocks=blocks,\n        post=post,\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blobhash_opcode/#tests.cancun.eip4844_blobs.test_blobhash_opcode.SpecHelpers","title":"SpecHelpers dataclass","text":"

Bases: Enum

Define parameters and helper functions that are tightly coupled to the 4844 spec but not strictly part of it.

Source code in tests/cancun/eip4844_blobs/spec.py
@dataclass(frozen=True)\nclass SpecHelpers(Enum):\n\"\"\"\n    Define parameters and helper functions that are tightly coupled to the 4844\n    spec but not strictly part of it.\n    \"\"\"\n\n    BYTES_PER_FIELD_ELEMENT = 32\n\n    @classmethod\n    def max_blobs_per_block(cls) -> int:  # MAX_BLOBS_PER_BLOCK =\n\"\"\"\n        Returns the maximum number of blobs per block.\n        \"\"\"\n        return Spec.MAX_DATA_GAS_PER_BLOCK.value // Spec.DATA_GAS_PER_BLOB.value\n\n    @classmethod\n    def target_blobs_per_block(cls) -> int:\n\"\"\"\n        Returns the target number of blobs per block.\n        \"\"\"\n        return Spec.TARGET_DATA_GAS_PER_BLOCK.value // Spec.DATA_GAS_PER_BLOB.value\n\n    @classmethod\n    def calc_excess_data_gas_from_blob_count(\n        cls, parent_excess_data_gas: int, parent_blob_count: int\n    ) -> int:\n\"\"\"\n        Calculate the excess data gas for a block given the parent excess data gas\n        and the number of blobs in the block.\n        \"\"\"\n        parent_consumed_data_gas = parent_blob_count * Spec.DATA_GAS_PER_BLOB.value\n        return Spec.calc_excess_data_gas(\n            BlockHeaderDataGasFields(parent_excess_data_gas, parent_consumed_data_gas)\n        )\n\n    @classmethod\n    def get_min_excess_data_gas_for_data_gas_price(cls, data_gas_price: int) -> int:\n\"\"\"\n        Gets the minimum required excess data gas value to get a given data gas cost in a block\n        \"\"\"\n        current_excess_data_gas = 0\n        current_data_gas_price = 1\n        while current_data_gas_price < data_gas_price:\n            current_excess_data_gas += Spec.DATA_GAS_PER_BLOB.value\n            current_data_gas_price = Spec.get_data_gasprice(\n                excess_data_gas=current_excess_data_gas\n            )\n        return current_excess_data_gas\n\n    @classmethod\n    def get_min_excess_data_blobs_for_data_gas_price(cls, data_gas_price: int) -> int:\n\"\"\"\n        Gets the minimum required excess data blobs to get a given data gas cost in a block\n        \"\"\"\n        return (\n            cls.get_min_excess_data_gas_for_data_gas_price(data_gas_price)\n            // Spec.DATA_GAS_PER_BLOB.value\n        )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blobhash_opcode/#tests.cancun.eip4844_blobs.test_blobhash_opcode.test_blobhash_scenarios","title":"test_blobhash_scenarios(pre, template_tx, blocks, post, scenario, blockchain_test)","text":"

Tests that the BLOBHASH opcode returns the correct versioned hash for various valid indexes.

Covers various scenarios with random blob_versioned_hash values within the valid range [0, 2**256-1].

Source code in tests/cancun/eip4844_blobs/test_blobhash_opcode.py
@pytest.mark.parametrize(\n    \"scenario\",\n    [\n        \"single_valid\",\n        \"repeated_valid\",\n        \"valid_invalid\",\n        \"varied_valid\",\n    ],\n)\ndef test_blobhash_scenarios(\n    pre,\n    template_tx,\n    blocks,\n    post,\n    scenario: str,\n    blockchain_test: BlockchainTestFiller,\n):\n\"\"\"\n    Tests that the `BLOBHASH` opcode returns the correct versioned hash for\n    various valid indexes.\n\n    Covers various scenarios with random `blob_versioned_hash` values within\n    the valid range `[0, 2**256-1]`.\n    \"\"\"\n    TOTAL_BLOCKS = 5\n    b_hashes_list = BlobhashScenario.create_blob_hashes_list(length=TOTAL_BLOCKS)\n    blobhash_calls = BlobhashScenario.generate_blobhash_bytecode(scenario)\n    for i in range(TOTAL_BLOCKS):\n        address = to_address(0x100 + i * 0x100)\n        pre[address] = Account(code=blobhash_calls)\n        blocks.append(\n            Block(\n                txs=[\n                    template_tx.with_fields(\n                        ty=Spec.BLOB_TX_TYPE.value,\n                        nonce=i,\n                        to=address,\n                        access_list=[],\n                        max_priority_fee_per_gas=10,\n                        blob_versioned_hashes=b_hashes_list[i],\n                    )\n                ]\n            )\n        )\n        post[address] = Account(\n            storage={\n                index: b_hashes_list[i][index]\n                for index in range(SpecHelpers.max_blobs_per_block())\n            }\n        )\n    blockchain_test(\n        pre=pre,\n        blocks=blocks,\n        post=post,\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blobhash_opcode/#tests.cancun.eip4844_blobs.test_blobhash_opcode.test_blobhash_invalid_blob_index","title":"test_blobhash_invalid_blob_index(pre, template_tx, blocks, post, blockchain_test, scenario)","text":"

Tests that the BLOBHASH opcode returns a zeroed bytes32 value for invalid indexes.

Includes cases where the index is negative (index < 0) or exceeds the maximum number of blob_versioned_hash values stored: (index >= len(tx.message.blob_versioned_hashes)).

It confirms that the returned value is a zeroed bytes32 for each case.

Source code in tests/cancun/eip4844_blobs/test_blobhash_opcode.py
@pytest.mark.parametrize(\n    \"scenario\",\n    [\n        \"invalid_calls\",\n    ],\n)\ndef test_blobhash_invalid_blob_index(\n    pre,\n    template_tx,\n    blocks,\n    post,\n    blockchain_test: BlockchainTestFiller,\n    scenario,\n):\n\"\"\"\n    Tests that the `BLOBHASH` opcode returns a zeroed `bytes32` value for invalid\n    indexes.\n\n    Includes cases where the index is negative (`index < 0`) or\n    exceeds the maximum number of `blob_versioned_hash` values stored:\n    (`index >= len(tx.message.blob_versioned_hashes)`).\n\n    It confirms that the returned value is a zeroed `bytes32` for each case.\n    \"\"\"\n    TOTAL_BLOCKS = 5\n    blobhash_calls = BlobhashScenario.generate_blobhash_bytecode(scenario)\n    for i in range(TOTAL_BLOCKS):\n        address = to_address(0x100 + i * 0x100)\n        pre[address] = Account(code=blobhash_calls)\n        blob_per_block = (i % SpecHelpers.max_blobs_per_block()) + 1\n        blobs = [random_blob_hashes[blob] for blob in range(blob_per_block)]\n        blocks.append(\n            Block(\n                txs=[\n                    template_tx.with_fields(\n                        ty=Spec.BLOB_TX_TYPE.value,\n                        nonce=i,\n                        to=address,\n                        access_list=[],\n                        max_priority_fee_per_gas=10,\n                        blob_versioned_hashes=blobs,\n                    )\n                ]\n            )\n        )\n        post[address] = Account(\n            storage={\n                index: (0 if index < 0 or index >= blob_per_block else blobs[index])\n                for index in range(\n                    -TOTAL_BLOCKS,\n                    blob_per_block + (TOTAL_BLOCKS - (i % SpecHelpers.max_blobs_per_block())),\n                )\n            }\n        )\n    blockchain_test(\n        pre=pre,\n        blocks=blocks,\n        post=post,\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blobhash_opcode/#tests.cancun.eip4844_blobs.test_blobhash_opcode.test_blobhash_multiple_txs_in_block","title":"test_blobhash_multiple_txs_in_block(pre, blob_tx, post, blockchain_test)","text":"

Tests that the BLOBHASH opcode returns the appropriate values when there is more than 1 blob tx type within a block (for tx types 2 and 3).

Scenarios involve tx type 3 followed by tx type 2 running the same code within a block, including the opposite.

Source code in tests/cancun/eip4844_blobs/test_blobhash_opcode.py
def test_blobhash_multiple_txs_in_block(\n    pre,\n    blob_tx,\n    post,\n    blockchain_test: BlockchainTestFiller,\n):\n\"\"\"\n    Tests that the `BLOBHASH` opcode returns the appropriate values when there\n    is more than 1 blob tx type within a block (for tx types 2 and 3).\n\n    Scenarios involve tx type 3 followed by tx type 2 running the same code\n    within a block, including the opposite.\n    \"\"\"\n    blobhash_bytecode = BlobhashScenario.generate_blobhash_bytecode(\"single_valid\")\n    pre = {\n        **pre,\n        **{\n            to_address(address): Account(code=blobhash_bytecode)\n            for address in range(0x100, 0x500, 0x100)\n        },\n    }\n    blocks = [\n        Block(\n            txs=[\n                blob_tx(address=to_address(0x100), type=3, nonce=0),\n                blob_tx(address=to_address(0x100), type=2, nonce=1),\n            ]\n        ),\n        Block(\n            txs=[\n                blob_tx(address=to_address(0x200), type=2, nonce=2),\n                blob_tx(address=to_address(0x200), type=3, nonce=3),\n            ]\n        ),\n        Block(\n            txs=[\n                blob_tx(address=to_address(0x300), type=2, nonce=4),\n                blob_tx(address=to_address(0x400), type=3, nonce=5),\n            ],\n        ),\n    ]\n    post = {\n        to_address(address): Account(\n            storage={i: random_blob_hashes[i] for i in range(SpecHelpers.max_blobs_per_block())}\n        )\n        if address in (0x200, 0x400)\n        else Account(storage={i: 0 for i in range(SpecHelpers.max_blobs_per_block())})\n        for address in range(0x100, 0x500, 0x100)\n    }\n    blockchain_test(\n        pre=pre,\n        blocks=blocks,\n        post=post,\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blobhash_opcode/index/test_cases/","title":"Test Blobhash Opcode - Test Cases","text":"

Test cases generated from tests/cancun/eip4844_blobs/test_blobhash_opcode.py

Parametrized test cases generated from the test module tests/cancun/eip4844_blobs/test_blobhash_opcode.py:

test_blobhash_gas_cost[fork=Cancun-tx_type=0]\ntest_blobhash_gas_cost[fork=Cancun-tx_type=1]\ntest_blobhash_gas_cost[fork=Cancun-tx_type=2]\ntest_blobhash_gas_cost[fork=Cancun-tx_type=3]\ntest_blobhash_scenarios[fork=Cancun-scenario=single_valid]\ntest_blobhash_scenarios[fork=Cancun-scenario=repeated_valid]\ntest_blobhash_scenarios[fork=Cancun-scenario=valid_invalid]\ntest_blobhash_scenarios[fork=Cancun-scenario=varied_valid]\ntest_blobhash_invalid_blob_index[fork=Cancun-scenario=invalid_calls]\ntest_blobhash_multiple_txs_in_block[fork=Cancun]\n

This output was extracted from the result of:

fill --collect-only -q --until Cancun tests/cancun/eip4844_blobs/test_blobhash_opcode.py\n
"},{"location":"tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts/","title":"Test Blobhash Opcode Contexts","text":"

Documentation for tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts.py.

Generate fixtures for these test cases for Cancun with:

Cancun only:

fill -v tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts.py --fork=Cancun --evm-bin=/path/to/evm-tool-dev-version\n
For all forks up to and including Cancun:
fill -v tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts.py --until=Cancun --evm-bin=/path/to/evm-tool-dev-version\n

Tests BLOBHASH opcode in EIP-4844: Shard Blob Transactions

Test case for BLOBHASH opcode calls across different contexts in EIP-4844: Shard Blob Transactions.

"},{"location":"tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts/#tests.cancun.eip4844_blobs.test_blobhash_opcode_contexts.Spec","title":"Spec dataclass","text":"

Bases: IntEnum

Parameters from the EIP-4844 specifications as defined at https://eips.ethereum.org/EIPS/eip-4844#parameters

If the parameter is not currently used within the tests, it is commented out.

Source code in tests/cancun/eip4844_blobs/spec.py
@dataclass(frozen=True)\nclass Spec(IntEnum):\n\"\"\"\n    Parameters from the EIP-4844 specifications as defined at\n    https://eips.ethereum.org/EIPS/eip-4844#parameters\n\n    If the parameter is not currently used within the tests, it is commented\n    out.\n    \"\"\"\n\n    BLOB_TX_TYPE = 0x03\n    FIELD_ELEMENTS_PER_BLOB = 4096\n    BLS_MODULUS = 0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001\n    BLOB_COMMITMENT_VERSION_KZG = 1\n    POINT_EVALUATION_PRECOMPILE_ADDRESS = 20\n    POINT_EVALUATION_PRECOMPILE_GAS = 50_000\n    MAX_DATA_GAS_PER_BLOCK = 786432\n    TARGET_DATA_GAS_PER_BLOCK = 393216\n    MIN_DATA_GASPRICE = 1\n    DATA_GASPRICE_UPDATE_FRACTION = 3338477\n    # MAX_VERSIONED_HASHES_LIST_SIZE = 2**24\n    # MAX_CALLDATA_SIZE = 2**24\n    # MAX_ACCESS_LIST_SIZE = 2**24\n    # MAX_ACCESS_LIST_STORAGE_KEYS = 2**24\n    # MAX_TX_WRAP_COMMITMENTS = 2**12\n    # LIMIT_BLOBS_PER_TX = 2**12\n    DATA_GAS_PER_BLOB = 2**17\n    HASH_OPCODE_BYTE = 0x49\n    HASH_GAS_COST = 3\n\n    @classmethod\n    def kzg_to_versioned_hash(\n        cls,\n        kzg_commitment: bytes | int,  # 48 bytes\n        blob_commitment_version_kzg: Optional[bytes | int] = None,\n    ) -> bytes:\n\"\"\"\n        Calculates the versioned hash for a given KZG commitment.\n        \"\"\"\n        if blob_commitment_version_kzg is None:\n            blob_commitment_version_kzg = cls.BLOB_COMMITMENT_VERSION_KZG\n        if isinstance(kzg_commitment, int):\n            kzg_commitment = kzg_commitment.to_bytes(48, \"big\")\n        if isinstance(blob_commitment_version_kzg, int):\n            blob_commitment_version_kzg = blob_commitment_version_kzg.to_bytes(1, \"big\")\n        return blob_commitment_version_kzg + sha256(kzg_commitment).digest()[1:]\n\n    @classmethod\n    def fake_exponential(cls, factor: int, numerator: int, denominator: int) -> int:\n\"\"\"\n        Used to calculate the data gas cost.\n        \"\"\"\n        i = 1\n        output = 0\n        numerator_accumulator = factor * denominator\n        while numerator_accumulator > 0:\n            output += numerator_accumulator\n            numerator_accumulator = (numerator_accumulator * numerator) // (denominator * i)\n            i += 1\n        return output // denominator\n\n    @classmethod\n    def calc_excess_data_gas(cls, parent: BlockHeaderDataGasFields) -> int:\n\"\"\"\n        Calculate the excess data gas for a block given the parent excess data gas\n        and the number of blobs in the block.\n        \"\"\"\n        if parent.excess_data_gas + parent.data_gas_used < cls.TARGET_DATA_GAS_PER_BLOCK:\n            return 0\n        else:\n            return parent.excess_data_gas + parent.data_gas_used - cls.TARGET_DATA_GAS_PER_BLOCK\n\n    # Note: Currently unused.\n    # @classmethod\n    # def get_total_data_gas(cls, tx: Transaction) -> int:\n    #     \"\"\"\n    #     Calculate the total data gas for a transaction.\n    #     \"\"\"\n    #     if tx.blob_versioned_hashes is None:\n    #         return 0\n    #     return cls.DATA_GAS_PER_BLOB.value * len(tx.blob_versioned_hashes)\n\n    @classmethod\n    def get_data_gasprice(cls, *, excess_data_gas: int) -> int:\n\"\"\"\n        Calculate the data gas price from the excess.\n        \"\"\"\n        return cls.fake_exponential(\n            cls.MIN_DATA_GASPRICE.value,\n            excess_data_gas,\n            cls.DATA_GASPRICE_UPDATE_FRACTION.value,\n        )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts/#tests.cancun.eip4844_blobs.test_blobhash_opcode_contexts.SpecHelpers","title":"SpecHelpers dataclass","text":"

Bases: Enum

Define parameters and helper functions that are tightly coupled to the 4844 spec but not strictly part of it.

Source code in tests/cancun/eip4844_blobs/spec.py
@dataclass(frozen=True)\nclass SpecHelpers(Enum):\n\"\"\"\n    Define parameters and helper functions that are tightly coupled to the 4844\n    spec but not strictly part of it.\n    \"\"\"\n\n    BYTES_PER_FIELD_ELEMENT = 32\n\n    @classmethod\n    def max_blobs_per_block(cls) -> int:  # MAX_BLOBS_PER_BLOCK =\n\"\"\"\n        Returns the maximum number of blobs per block.\n        \"\"\"\n        return Spec.MAX_DATA_GAS_PER_BLOCK.value // Spec.DATA_GAS_PER_BLOB.value\n\n    @classmethod\n    def target_blobs_per_block(cls) -> int:\n\"\"\"\n        Returns the target number of blobs per block.\n        \"\"\"\n        return Spec.TARGET_DATA_GAS_PER_BLOCK.value // Spec.DATA_GAS_PER_BLOB.value\n\n    @classmethod\n    def calc_excess_data_gas_from_blob_count(\n        cls, parent_excess_data_gas: int, parent_blob_count: int\n    ) -> int:\n\"\"\"\n        Calculate the excess data gas for a block given the parent excess data gas\n        and the number of blobs in the block.\n        \"\"\"\n        parent_consumed_data_gas = parent_blob_count * Spec.DATA_GAS_PER_BLOB.value\n        return Spec.calc_excess_data_gas(\n            BlockHeaderDataGasFields(parent_excess_data_gas, parent_consumed_data_gas)\n        )\n\n    @classmethod\n    def get_min_excess_data_gas_for_data_gas_price(cls, data_gas_price: int) -> int:\n\"\"\"\n        Gets the minimum required excess data gas value to get a given data gas cost in a block\n        \"\"\"\n        current_excess_data_gas = 0\n        current_data_gas_price = 1\n        while current_data_gas_price < data_gas_price:\n            current_excess_data_gas += Spec.DATA_GAS_PER_BLOB.value\n            current_data_gas_price = Spec.get_data_gasprice(\n                excess_data_gas=current_excess_data_gas\n            )\n        return current_excess_data_gas\n\n    @classmethod\n    def get_min_excess_data_blobs_for_data_gas_price(cls, data_gas_price: int) -> int:\n\"\"\"\n        Gets the minimum required excess data blobs to get a given data gas cost in a block\n        \"\"\"\n        return (\n            cls.get_min_excess_data_gas_for_data_gas_price(data_gas_price)\n            // Spec.DATA_GAS_PER_BLOB.value\n        )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts/#tests.cancun.eip4844_blobs.test_blobhash_opcode_contexts.test_blobhash_opcode_contexts","title":"test_blobhash_opcode_contexts(opcode_context, blockchain_test)","text":"

Tests that the BLOBHASH opcode functions correctly when called in different contexts including:

  • BLOBHASH opcode on the top level of the call stack.
  • BLOBHASH opcode on the max value.
  • BLOBHASH opcode on CALL, DELEGATECALL, STATICCALL, and CALLCODE.
  • BLOBHASH opcode on Initcode.
  • BLOBHASH opcode on CREATE and CREATE2.
  • BLOBHASH opcode on transaction types 0, 1 and 2.
Source code in tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts.py
@pytest.mark.compile_yul_with(\"Shanghai\")\ndef test_blobhash_opcode_contexts(opcode_context, blockchain_test: BlockchainTestFiller):\n\"\"\"\n    Tests that the `BLOBHASH` opcode functions correctly when called in different\n    contexts including:\n\n    - `BLOBHASH` opcode on the top level of the call stack.\n    - `BLOBHASH` opcode on the max value.\n    - `BLOBHASH` opcode on `CALL`, `DELEGATECALL`, `STATICCALL`, and `CALLCODE`.\n    - `BLOBHASH` opcode on Initcode.\n    - `BLOBHASH` opcode on `CREATE` and `CREATE2`.\n    - `BLOBHASH` opcode on transaction types 0, 1 and 2.\n    \"\"\"\n    blockchain_test(\n        pre=opcode_context.get(\"pre\"),\n        blocks=[Block(txs=[opcode_context.get(\"tx\")])],\n        post=opcode_context.get(\"post\"),\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts/index/test_cases/","title":"Test Blobhash Opcode Contexts - Test Cases","text":"

Test cases generated from tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts.py

Parametrized test cases generated from the test module tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts.py:

test_blobhash_opcode_contexts[opcode_context=on_top_level_call_stack-fork=Cancun]\ntest_blobhash_opcode_contexts[opcode_context=on_max_value-fork=Cancun]\ntest_blobhash_opcode_contexts[opcode_context=on_CALL-fork=Cancun]\ntest_blobhash_opcode_contexts[opcode_context=on_DELEGATECALL-fork=Cancun]\ntest_blobhash_opcode_contexts[opcode_context=on_STATICCALL-fork=Cancun]\ntest_blobhash_opcode_contexts[opcode_context=on_CALLCODE-fork=Cancun]\ntest_blobhash_opcode_contexts[opcode_context=on_CREATE-fork=Cancun]\ntest_blobhash_opcode_contexts[opcode_context=on_CREATE2-fork=Cancun]\ntest_blobhash_opcode_contexts[opcode_context=on_type_2_tx-fork=Cancun]\ntest_blobhash_opcode_contexts[opcode_context=on_type_1_tx-fork=Cancun]\ntest_blobhash_opcode_contexts[opcode_context=on_type_0_tx-fork=Cancun]\n

This output was extracted from the result of:

fill --collect-only -q --until Cancun tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts.py\n
"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas/","title":"Test Excess Data Gas","text":"

Documentation for tests/cancun/eip4844_blobs/test_excess_data_gas.py.

Generate fixtures for these test cases for Cancun with:

Cancun only:

fill -v tests/cancun/eip4844_blobs/test_excess_data_gas.py --fork=Cancun --evm-bin=/path/to/evm-tool-dev-version\n
For all forks up to and including Cancun:
fill -v tests/cancun/eip4844_blobs/test_excess_data_gas.py --until=Cancun --evm-bin=/path/to/evm-tool-dev-version\n

Tests excessDataGas and dataGasUsed block fields for EIP-4844: Shard Blob Transactions

Test excessDataGas and dataGasUsed block fields for EIP-4844: Shard Blob Transactions.

Adding a new test

Add a function that is named test_<test_name> and takes at least the following arguments:

  • blockchain_test
  • env
  • pre
  • blocks
  • post
  • correct_excess_data_gas

The following arguments need to be parametrized or the test will not be generated:

  • new_blobs

All other pytest.fixture fixtures can be parametrized to generate new combinations and test cases.

"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas/#tests.cancun.eip4844_blobs.test_excess_data_gas.Spec","title":"Spec dataclass","text":"

Bases: IntEnum

Parameters from the EIP-4844 specifications as defined at https://eips.ethereum.org/EIPS/eip-4844#parameters

If the parameter is not currently used within the tests, it is commented out.

Source code in tests/cancun/eip4844_blobs/spec.py
@dataclass(frozen=True)\nclass Spec(IntEnum):\n\"\"\"\n    Parameters from the EIP-4844 specifications as defined at\n    https://eips.ethereum.org/EIPS/eip-4844#parameters\n\n    If the parameter is not currently used within the tests, it is commented\n    out.\n    \"\"\"\n\n    BLOB_TX_TYPE = 0x03\n    FIELD_ELEMENTS_PER_BLOB = 4096\n    BLS_MODULUS = 0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001\n    BLOB_COMMITMENT_VERSION_KZG = 1\n    POINT_EVALUATION_PRECOMPILE_ADDRESS = 20\n    POINT_EVALUATION_PRECOMPILE_GAS = 50_000\n    MAX_DATA_GAS_PER_BLOCK = 786432\n    TARGET_DATA_GAS_PER_BLOCK = 393216\n    MIN_DATA_GASPRICE = 1\n    DATA_GASPRICE_UPDATE_FRACTION = 3338477\n    # MAX_VERSIONED_HASHES_LIST_SIZE = 2**24\n    # MAX_CALLDATA_SIZE = 2**24\n    # MAX_ACCESS_LIST_SIZE = 2**24\n    # MAX_ACCESS_LIST_STORAGE_KEYS = 2**24\n    # MAX_TX_WRAP_COMMITMENTS = 2**12\n    # LIMIT_BLOBS_PER_TX = 2**12\n    DATA_GAS_PER_BLOB = 2**17\n    HASH_OPCODE_BYTE = 0x49\n    HASH_GAS_COST = 3\n\n    @classmethod\n    def kzg_to_versioned_hash(\n        cls,\n        kzg_commitment: bytes | int,  # 48 bytes\n        blob_commitment_version_kzg: Optional[bytes | int] = None,\n    ) -> bytes:\n\"\"\"\n        Calculates the versioned hash for a given KZG commitment.\n        \"\"\"\n        if blob_commitment_version_kzg is None:\n            blob_commitment_version_kzg = cls.BLOB_COMMITMENT_VERSION_KZG\n        if isinstance(kzg_commitment, int):\n            kzg_commitment = kzg_commitment.to_bytes(48, \"big\")\n        if isinstance(blob_commitment_version_kzg, int):\n            blob_commitment_version_kzg = blob_commitment_version_kzg.to_bytes(1, \"big\")\n        return blob_commitment_version_kzg + sha256(kzg_commitment).digest()[1:]\n\n    @classmethod\n    def fake_exponential(cls, factor: int, numerator: int, denominator: int) -> int:\n\"\"\"\n        Used to calculate the data gas cost.\n        \"\"\"\n        i = 1\n        output = 0\n        numerator_accumulator = factor * denominator\n        while numerator_accumulator > 0:\n            output += numerator_accumulator\n            numerator_accumulator = (numerator_accumulator * numerator) // (denominator * i)\n            i += 1\n        return output // denominator\n\n    @classmethod\n    def calc_excess_data_gas(cls, parent: BlockHeaderDataGasFields) -> int:\n\"\"\"\n        Calculate the excess data gas for a block given the parent excess data gas\n        and the number of blobs in the block.\n        \"\"\"\n        if parent.excess_data_gas + parent.data_gas_used < cls.TARGET_DATA_GAS_PER_BLOCK:\n            return 0\n        else:\n            return parent.excess_data_gas + parent.data_gas_used - cls.TARGET_DATA_GAS_PER_BLOCK\n\n    # Note: Currently unused.\n    # @classmethod\n    # def get_total_data_gas(cls, tx: Transaction) -> int:\n    #     \"\"\"\n    #     Calculate the total data gas for a transaction.\n    #     \"\"\"\n    #     if tx.blob_versioned_hashes is None:\n    #         return 0\n    #     return cls.DATA_GAS_PER_BLOB.value * len(tx.blob_versioned_hashes)\n\n    @classmethod\n    def get_data_gasprice(cls, *, excess_data_gas: int) -> int:\n\"\"\"\n        Calculate the data gas price from the excess.\n        \"\"\"\n        return cls.fake_exponential(\n            cls.MIN_DATA_GASPRICE.value,\n            excess_data_gas,\n            cls.DATA_GASPRICE_UPDATE_FRACTION.value,\n        )\n
"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas/#tests.cancun.eip4844_blobs.test_excess_data_gas.SpecHelpers","title":"SpecHelpers dataclass","text":"

Bases: Enum

Define parameters and helper functions that are tightly coupled to the 4844 spec but not strictly part of it.

Source code in tests/cancun/eip4844_blobs/spec.py
@dataclass(frozen=True)\nclass SpecHelpers(Enum):\n\"\"\"\n    Define parameters and helper functions that are tightly coupled to the 4844\n    spec but not strictly part of it.\n    \"\"\"\n\n    BYTES_PER_FIELD_ELEMENT = 32\n\n    @classmethod\n    def max_blobs_per_block(cls) -> int:  # MAX_BLOBS_PER_BLOCK =\n\"\"\"\n        Returns the maximum number of blobs per block.\n        \"\"\"\n        return Spec.MAX_DATA_GAS_PER_BLOCK.value // Spec.DATA_GAS_PER_BLOB.value\n\n    @classmethod\n    def target_blobs_per_block(cls) -> int:\n\"\"\"\n        Returns the target number of blobs per block.\n        \"\"\"\n        return Spec.TARGET_DATA_GAS_PER_BLOCK.value // Spec.DATA_GAS_PER_BLOB.value\n\n    @classmethod\n    def calc_excess_data_gas_from_blob_count(\n        cls, parent_excess_data_gas: int, parent_blob_count: int\n    ) -> int:\n\"\"\"\n        Calculate the excess data gas for a block given the parent excess data gas\n        and the number of blobs in the block.\n        \"\"\"\n        parent_consumed_data_gas = parent_blob_count * Spec.DATA_GAS_PER_BLOB.value\n        return Spec.calc_excess_data_gas(\n            BlockHeaderDataGasFields(parent_excess_data_gas, parent_consumed_data_gas)\n        )\n\n    @classmethod\n    def get_min_excess_data_gas_for_data_gas_price(cls, data_gas_price: int) -> int:\n\"\"\"\n        Gets the minimum required excess data gas value to get a given data gas cost in a block\n        \"\"\"\n        current_excess_data_gas = 0\n        current_data_gas_price = 1\n        while current_data_gas_price < data_gas_price:\n            current_excess_data_gas += Spec.DATA_GAS_PER_BLOB.value\n            current_data_gas_price = Spec.get_data_gasprice(\n                excess_data_gas=current_excess_data_gas\n            )\n        return current_excess_data_gas\n\n    @classmethod\n    def get_min_excess_data_blobs_for_data_gas_price(cls, data_gas_price: int) -> int:\n\"\"\"\n        Gets the minimum required excess data blobs to get a given data gas cost in a block\n        \"\"\"\n        return (\n            cls.get_min_excess_data_gas_for_data_gas_price(data_gas_price)\n            // Spec.DATA_GAS_PER_BLOB.value\n        )\n
"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas/#tests.cancun.eip4844_blobs.test_excess_data_gas.test_correct_excess_data_gas_calculation","title":"test_correct_excess_data_gas_calculation(blockchain_test, env, pre, blocks, post, correct_excess_data_gas)","text":"

Test calculation of the excessDataGas increase/decrease across multiple blocks with and without blobs:

  • With parent block containing [0, MAX_BLOBS_PER_BLOCK] blobs
  • With parent block containing [0, TARGET_BLOBS_PER_BLOCK] equivalent value of excess data gas
Source code in tests/cancun/eip4844_blobs/test_excess_data_gas.py
@pytest.mark.parametrize(\"parent_blobs\", range(0, SpecHelpers.max_blobs_per_block() + 1))\n@pytest.mark.parametrize(\"parent_excess_blobs\", range(0, SpecHelpers.target_blobs_per_block() + 1))\n@pytest.mark.parametrize(\"new_blobs\", [1])\ndef test_correct_excess_data_gas_calculation(\n    blockchain_test: BlockchainTestFiller,\n    env: Environment,\n    pre: Mapping[str, Account],\n    blocks: List[Block],\n    post: Mapping[str, Account],\n    correct_excess_data_gas: int,\n):\n\"\"\"\n    Test calculation of the `excessDataGas` increase/decrease across\n    multiple blocks with and without blobs:\n\n    - With parent block containing `[0, MAX_BLOBS_PER_BLOCK]` blobs\n    - With parent block containing `[0, TARGET_BLOBS_PER_BLOCK]` equivalent value of excess data gas\n    \"\"\"  # noqa: E501\n    blockchain_test(\n        pre=pre,\n        post=post,\n        blocks=blocks,\n        genesis_environment=env,\n        tag=f\"expected_excess_data_gas:{hex(correct_excess_data_gas)}\",\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas/#tests.cancun.eip4844_blobs.test_excess_data_gas.test_correct_increasing_data_gas_costs","title":"test_correct_increasing_data_gas_costs(blockchain_test, env, pre, blocks, post, correct_excess_data_gas)","text":"

Test calculation of the excessDataGas and data gas tx costs at value points where the cost increases to interesting amounts:

  • At the first data gas cost increase (1 to 2)
  • At total transaction data cost increase to > 2^32
  • At data gas wei cost increase to > 2^32
  • At total transaction data cost increase to > 2^64
  • At data gas wei cost increase to > 2^64
  • At data gas wei cost increase of around current total Ether supply
Source code in tests/cancun/eip4844_blobs/test_excess_data_gas.py
@pytest.mark.parametrize(\n    \"parent_excess_blobs\",\n    [g - 1 for g in DATA_GAS_COST_INCREASES],\n)\n@pytest.mark.parametrize(\"parent_blobs\", [SpecHelpers.target_blobs_per_block() + 1])\n@pytest.mark.parametrize(\"new_blobs\", [1])\ndef test_correct_increasing_data_gas_costs(\n    blockchain_test: BlockchainTestFiller,\n    env: Environment,\n    pre: Mapping[str, Account],\n    blocks: List[Block],\n    post: Mapping[str, Account],\n    correct_excess_data_gas: int,\n):\n\"\"\"\n    Test calculation of the `excessDataGas` and data gas tx costs at\n    value points where the cost increases to interesting amounts:\n\n    - At the first data gas cost increase (1 to 2)\n    - At total transaction data cost increase to `> 2^32`\n    - At data gas wei cost increase to `> 2^32`\n    - At total transaction data cost increase to `> 2^64`\n    - At data gas wei cost increase to `> 2^64`\n    - At data gas wei cost increase of around current total Ether supply\n    \"\"\"\n    blockchain_test(\n        pre=pre,\n        post=post,\n        blocks=blocks,\n        genesis_environment=env,\n        tag=f\"expected_excess_data_gas:{hex(correct_excess_data_gas)}\",\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas/#tests.cancun.eip4844_blobs.test_excess_data_gas.test_correct_decreasing_data_gas_costs","title":"test_correct_decreasing_data_gas_costs(blockchain_test, env, pre, blocks, post, correct_excess_data_gas)","text":"

Test calculation of the excessDataGas and data gas tx costs at value points where the cost decreases to interesting amounts.

See test_correct_increasing_data_gas_costs.

Source code in tests/cancun/eip4844_blobs/test_excess_data_gas.py
@pytest.mark.parametrize(\n    \"parent_excess_blobs\",\n    [g for g in DATA_GAS_COST_INCREASES],\n)\n@pytest.mark.parametrize(\"parent_blobs\", [SpecHelpers.target_blobs_per_block() - 1])\n@pytest.mark.parametrize(\"new_blobs\", [1])\ndef test_correct_decreasing_data_gas_costs(\n    blockchain_test: BlockchainTestFiller,\n    env: Environment,\n    pre: Mapping[str, Account],\n    blocks: List[Block],\n    post: Mapping[str, Account],\n    correct_excess_data_gas: int,\n):\n\"\"\"\n    Test calculation of the `excessDataGas` and data gas tx costs at\n    value points where the cost decreases to interesting amounts.\n\n    See test_correct_increasing_data_gas_costs.\n    \"\"\"\n    blockchain_test(\n        pre=pre,\n        post=post,\n        blocks=blocks,\n        genesis_environment=env,\n        tag=f\"expected_excess_data_gas:{hex(correct_excess_data_gas)}\",\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas/#tests.cancun.eip4844_blobs.test_excess_data_gas.test_invalid_zero_excess_data_gas_in_header","title":"test_invalid_zero_excess_data_gas_in_header(blockchain_test, env, pre, blocks, correct_excess_data_gas, header_excess_data_gas)","text":"

Test rejection of blocks where the excessDataGas in the header drops to zero in a block with or without data blobs, but the excess blobs in the parent are greater than target.

Source code in tests/cancun/eip4844_blobs/test_excess_data_gas.py
@pytest.mark.parametrize(\"header_excess_data_gas\", [0])\n@pytest.mark.parametrize(\"new_blobs\", [0, 1])\n@pytest.mark.parametrize(\"parent_blobs\", range(0, SpecHelpers.max_blobs_per_block() + 1))\ndef test_invalid_zero_excess_data_gas_in_header(\n    blockchain_test: BlockchainTestFiller,\n    env: Environment,\n    pre: Mapping[str, Account],\n    blocks: List[Block],\n    correct_excess_data_gas: int,\n    header_excess_data_gas: Optional[int],\n):\n\"\"\"\n    Test rejection of blocks where the `excessDataGas` in the header drops to\n    zero in a block with or without data blobs, but the excess blobs in the parent are\n    greater than target.\n    \"\"\"\n    if header_excess_data_gas is None:\n        raise Exception(\"test case is badly formatted\")\n\n    if header_excess_data_gas == correct_excess_data_gas:\n        raise Exception(\"invalid test case\")\n\n    blockchain_test(\n        pre=pre,\n        post={},\n        blocks=blocks,\n        genesis_environment=env,\n        tag=\"-\".join(\n            [\n                f\"correct:{hex(correct_excess_data_gas)}\",\n                f\"header:{hex(header_excess_data_gas)}\",\n            ]\n        ),\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas/#tests.cancun.eip4844_blobs.test_excess_data_gas.test_invalid_data_gas_used_in_header","title":"test_invalid_data_gas_used_in_header(blockchain_test, env, pre, blocks, new_blobs, header_data_gas_used)","text":"

Test rejection of blocks where the dataGasUsed in the header is invalid:

  • dataGasUsed is not equal to the number of data blobs in the block
  • dataGasUsed is the max uint64 value
Source code in tests/cancun/eip4844_blobs/test_excess_data_gas.py
@pytest.mark.parametrize(\n    \"new_blobs,header_data_gas_used\",\n    all_invalid_data_gas_used_combinations(),\n)\n@pytest.mark.parametrize(\"parent_blobs\", [0])\ndef test_invalid_data_gas_used_in_header(\n    blockchain_test: BlockchainTestFiller,\n    env: Environment,\n    pre: Mapping[str, Account],\n    blocks: List[Block],\n    new_blobs: int,\n    header_data_gas_used: Optional[int],\n):\n\"\"\"\n    Test rejection of blocks where the `dataGasUsed` in the header is invalid:\n\n    - `dataGasUsed` is not equal to the number of data blobs in the block\n    - `dataGasUsed` is the max uint64 value\n    \"\"\"\n    if header_data_gas_used is None:\n        raise Exception(\"test case is badly formatted\")\n    blockchain_test(\n        pre=pre,\n        post={},\n        blocks=blocks,\n        genesis_environment=env,\n        tag=\"-\".join(\n            [\n                f\"correct:{hex(new_blobs *Spec.DATA_GAS_PER_BLOB)}\",\n                f\"header:{hex(header_data_gas_used)}\",\n            ]\n        ),\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas/#tests.cancun.eip4844_blobs.test_excess_data_gas.test_invalid_excess_data_gas_above_target_change","title":"test_invalid_excess_data_gas_above_target_change(blockchain_test, env, pre, blocks, correct_excess_data_gas, header_excess_data_gas)","text":"

Test rejection of blocks where the excessDataGas

  • decreases more than TARGET_DATA_GAS_PER_BLOCK in a single block with zero blobs
  • increases more than TARGET_DATA_GAS_PER_BLOCK in a single block with max blobs
Source code in tests/cancun/eip4844_blobs/test_excess_data_gas.py
@pytest.mark.parametrize(\n    \"header_excess_blobs_delta,parent_blobs\",\n    [\n        (-1, 0),\n        (+1, SpecHelpers.max_blobs_per_block()),\n    ],\n    ids=[\"zero_blobs_decrease_more_than_expected\", \"max_blobs_increase_more_than_expected\"],\n)\n@pytest.mark.parametrize(\"new_blobs\", [1])\ndef test_invalid_excess_data_gas_above_target_change(\n    blockchain_test: BlockchainTestFiller,\n    env: Environment,\n    pre: Mapping[str, Account],\n    blocks: List[Block],\n    correct_excess_data_gas: int,\n    header_excess_data_gas: Optional[int],\n):\n\"\"\"\n    Test rejection of blocks where the `excessDataGas`\n\n    - decreases more than `TARGET_DATA_GAS_PER_BLOCK` in a single block with zero blobs\n    - increases more than `TARGET_DATA_GAS_PER_BLOCK` in a single block with max blobs\n    \"\"\"\n    if header_excess_data_gas is None:\n        raise Exception(\"test case is badly formatted\")\n\n    if header_excess_data_gas == correct_excess_data_gas:\n        raise Exception(\"invalid test case\")\n\n    blockchain_test(\n        pre=pre,\n        post={},\n        blocks=blocks,\n        genesis_environment=env,\n        tag=\"-\".join(\n            [\n                f\"correct:{hex(correct_excess_data_gas)}\",\n                f\"header:{hex(header_excess_data_gas)}\",\n            ]\n        ),\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas/#tests.cancun.eip4844_blobs.test_excess_data_gas.test_invalid_static_excess_data_gas","title":"test_invalid_static_excess_data_gas(blockchain_test, env, pre, blocks, correct_excess_data_gas, parent_excess_data_gas)","text":"

Test rejection of blocks where the excessDataGas remains unchanged but the parent blobs included are not TARGET_BLOBS_PER_BLOCK.

Test is parametrized to MAX_BLOBS_PER_BLOCK and TARGET_BLOBS_PER_BLOCK.

Source code in tests/cancun/eip4844_blobs/test_excess_data_gas.py
@pytest.mark.parametrize(\n    \"parent_blobs\",\n    [\n        b\n        for b in range(0, SpecHelpers.max_blobs_per_block() + 1)\n        if b != SpecHelpers.target_blobs_per_block()\n    ],\n)\n@pytest.mark.parametrize(\"parent_excess_blobs\", [1, SpecHelpers.target_blobs_per_block()])\n@pytest.mark.parametrize(\"new_blobs\", [1])\ndef test_invalid_static_excess_data_gas(\n    blockchain_test: BlockchainTestFiller,\n    env: Environment,\n    pre: Mapping[str, Account],\n    blocks: List[Block],\n    correct_excess_data_gas: int,\n    parent_excess_data_gas: int,\n):\n\"\"\"\n    Test rejection of blocks where the `excessDataGas` remains unchanged\n    but the parent blobs included are not `TARGET_BLOBS_PER_BLOCK`.\n\n    Test is parametrized to `MAX_BLOBS_PER_BLOCK` and `TARGET_BLOBS_PER_BLOCK`.\n    \"\"\"\n    blocks[-1].rlp_modifier = Header(excess_data_gas=parent_excess_data_gas)\n    blocks[-1].exception = \"invalid excessDataGas\"\n    blockchain_test(\n        pre=pre,\n        post={},\n        blocks=blocks,\n        genesis_environment=env,\n        tag=\"-\".join(\n            [\n                f\"correct:{hex(correct_excess_data_gas)}\",\n                f\"header:{hex(parent_excess_data_gas)}\",\n            ]\n        ),\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas/#tests.cancun.eip4844_blobs.test_excess_data_gas.test_invalid_excess_data_gas_target_blobs_increase_from_zero","title":"test_invalid_excess_data_gas_target_blobs_increase_from_zero(blockchain_test, env, pre, blocks, correct_excess_data_gas, header_excess_data_gas)","text":"

Test rejection of blocks where the excessDataGas increases from zero, even when the included blobs are on or below target.

Test is parametrized according to [0, TARGET_BLOBS_PER_BLOCK new blobs.

Source code in tests/cancun/eip4844_blobs/test_excess_data_gas.py
@pytest.mark.parametrize(\"header_excess_blobs_delta\", range(1, SpecHelpers.max_blobs_per_block()))\n@pytest.mark.parametrize(\"parent_blobs\", range(0, SpecHelpers.target_blobs_per_block() + 1))\n@pytest.mark.parametrize(\"parent_excess_blobs\", [0])  # Start at 0\n@pytest.mark.parametrize(\"new_blobs\", [1])\ndef test_invalid_excess_data_gas_target_blobs_increase_from_zero(\n    blockchain_test: BlockchainTestFiller,\n    env: Environment,\n    pre: Mapping[str, Account],\n    blocks: List[Block],\n    correct_excess_data_gas: int,\n    header_excess_data_gas: Optional[int],\n):\n\"\"\"\n    Test rejection of blocks where the `excessDataGas` increases from zero,\n    even when the included blobs are on or below target.\n\n    Test is parametrized according to `[0, TARGET_BLOBS_PER_BLOCK` new blobs.\n    \"\"\"\n    if header_excess_data_gas is None:\n        raise Exception(\"test case is badly formatted\")\n\n    if header_excess_data_gas == correct_excess_data_gas:\n        raise Exception(\"invalid test case\")\n\n    blockchain_test(\n        pre=pre,\n        post={},\n        blocks=blocks,\n        genesis_environment=env,\n        tag=\"-\".join(\n            [\n                f\"correct:{hex(correct_excess_data_gas)}\",\n                f\"header:{hex(header_excess_data_gas)}\",\n            ]\n        ),\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas/#tests.cancun.eip4844_blobs.test_excess_data_gas.test_invalid_static_excess_data_gas_from_zero_on_blobs_above_target","title":"test_invalid_static_excess_data_gas_from_zero_on_blobs_above_target(blockchain_test, env, pre, blocks, correct_excess_data_gas, header_excess_data_gas)","text":"

Test rejection of blocks where the excessDataGas does not increase from zero, even when the included blobs is above target.

Test is parametrized to [TARGET_BLOBS_PER_BLOCK+1, MAX_BLOBS_PER_BLOCK] new blobs.

Source code in tests/cancun/eip4844_blobs/test_excess_data_gas.py
@pytest.mark.parametrize(\"header_excess_data_gas\", [0])\n@pytest.mark.parametrize(\n    \"parent_blobs\",\n    range(SpecHelpers.target_blobs_per_block() + 1, SpecHelpers.max_blobs_per_block() + 1),\n)\n@pytest.mark.parametrize(\"parent_excess_blobs\", [0])  # Start at 0\n@pytest.mark.parametrize(\"new_blobs\", [1])\ndef test_invalid_static_excess_data_gas_from_zero_on_blobs_above_target(\n    blockchain_test: BlockchainTestFiller,\n    env: Environment,\n    pre: Mapping[str, Account],\n    blocks: List[Block],\n    correct_excess_data_gas: int,\n    header_excess_data_gas: Optional[int],\n):\n\"\"\"\n    Test rejection of blocks where the `excessDataGas` does not increase from\n    zero, even when the included blobs is above target.\n\n    Test is parametrized to `[TARGET_BLOBS_PER_BLOCK+1, MAX_BLOBS_PER_BLOCK]` new blobs.\n    \"\"\"\n    if header_excess_data_gas is None:\n        raise Exception(\"test case is badly formatted\")\n\n    if header_excess_data_gas == correct_excess_data_gas:\n        raise Exception(\"invalid test case\")\n\n    blockchain_test(\n        pre=pre,\n        post={},\n        blocks=blocks,\n        genesis_environment=env,\n        tag=\"-\".join(\n            [\n                f\"correct:{hex(correct_excess_data_gas)}\",\n                f\"header:{hex(header_excess_data_gas)}\",\n            ]\n        ),\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas/#tests.cancun.eip4844_blobs.test_excess_data_gas.test_invalid_excess_data_gas_change","title":"test_invalid_excess_data_gas_change(blockchain_test, env, pre, blocks, correct_excess_data_gas, header_excess_data_gas)","text":"

Test rejection of blocks where the excessDataGas changes to an invalid value.

Given a parent block containing [0, MAX_BLOBS_PER_BLOCK] blobs, test an invalid excessDataGas value by changing it by [-TARGET_BLOBS_PER_BLOCK, TARGET_BLOBS_PER_BLOCK] from the correct value.

Source code in tests/cancun/eip4844_blobs/test_excess_data_gas.py
@pytest.mark.parametrize(\n    \"parent_blobs,header_excess_blobs_delta\",\n    itertools.product(\n        # parent_blobs\n        range(0, SpecHelpers.max_blobs_per_block() + 1),\n        # header_excess_blobs_delta (from correct value)\n        [\n            x\n            for x in range(\n                -SpecHelpers.target_blobs_per_block(), SpecHelpers.target_blobs_per_block() + 1\n            )\n            if x != 0\n        ],\n    ),\n)\n@pytest.mark.parametrize(\"new_blobs\", [1])\ndef test_invalid_excess_data_gas_change(\n    blockchain_test: BlockchainTestFiller,\n    env: Environment,\n    pre: Mapping[str, Account],\n    blocks: List[Block],\n    correct_excess_data_gas: int,\n    header_excess_data_gas: Optional[int],\n):\n\"\"\"\n    Test rejection of blocks where the `excessDataGas` changes to an invalid\n    value.\n\n    Given a parent block containing `[0, MAX_BLOBS_PER_BLOCK]` blobs, test an invalid\n    `excessDataGas` value by changing it by `[-TARGET_BLOBS_PER_BLOCK, TARGET_BLOBS_PER_BLOCK]`\n    from the correct value.\n    \"\"\"\n    if header_excess_data_gas is None:\n        raise Exception(\"test case is badly formatted\")\n\n    if header_excess_data_gas == correct_excess_data_gas:\n        raise Exception(\"invalid test case\")\n\n    blockchain_test(\n        pre=pre,\n        post={},\n        blocks=blocks,\n        genesis_environment=env,\n        tag=\"-\".join(\n            [\n                f\"correct:{hex(correct_excess_data_gas)}\",\n                f\"header:{hex(header_excess_data_gas)}\",\n            ]\n        ),\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas/#tests.cancun.eip4844_blobs.test_excess_data_gas.test_invalid_negative_excess_data_gas","title":"test_invalid_negative_excess_data_gas(blockchain_test, env, pre, blocks, correct_excess_data_gas, header_excess_data_gas)","text":"

Test rejection of blocks where the excessDataGas changes to the two's complement equivalent of the negative value after subtracting target blobs.

Reasoning is that the excessDataGas is a uint64, so it cannot be negative, and we test for a potential underflow here.

Source code in tests/cancun/eip4844_blobs/test_excess_data_gas.py
@pytest.mark.parametrize(\n    \"header_excess_data_gas\",\n    [\n        (2**64 + (x * Spec.DATA_GAS_PER_BLOB))\n        for x in range(-SpecHelpers.target_blobs_per_block(), 0)\n    ],\n)\n@pytest.mark.parametrize(\"parent_blobs\", range(SpecHelpers.target_blobs_per_block()))\n@pytest.mark.parametrize(\"new_blobs\", [1])\n@pytest.mark.parametrize(\"parent_excess_blobs\", range(SpecHelpers.target_blobs_per_block()))\ndef test_invalid_negative_excess_data_gas(\n    blockchain_test: BlockchainTestFiller,\n    env: Environment,\n    pre: Mapping[str, Account],\n    blocks: List[Block],\n    correct_excess_data_gas: int,\n    header_excess_data_gas: Optional[int],\n):\n\"\"\"\n    Test rejection of blocks where the `excessDataGas` changes to the two's\n    complement equivalent of the negative value after subtracting target blobs.\n\n    Reasoning is that the `excessDataGas` is a `uint64`, so it cannot be negative, and\n    we test for a potential underflow here.\n    \"\"\"\n    if header_excess_data_gas is None:\n        raise Exception(\"test case is badly formatted\")\n\n    if header_excess_data_gas == correct_excess_data_gas:\n        raise Exception(\"invalid test case\")\n\n    blockchain_test(\n        pre=pre,\n        post={},\n        blocks=blocks,\n        genesis_environment=env,\n        tag=\"-\".join(\n            [\n                f\"correct:{hex(correct_excess_data_gas)}\",\n                f\"header:{hex(header_excess_data_gas)}\",\n            ]\n        ),\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas/#tests.cancun.eip4844_blobs.test_excess_data_gas.test_invalid_non_multiple_excess_data_gas","title":"test_invalid_non_multiple_excess_data_gas(blockchain_test, env, pre, blocks, correct_excess_data_gas, header_excess_data_gas)","text":"

Test rejection of blocks where the excessDataGas changes to a value that is not a multiple of Spec.DATA_GAS_PER_BLOB`:

  • Parent block contains TARGET_BLOBS_PER_BLOCK + 1 blobs, but excessDataGas is off by \u00b11
  • Parent block contains TARGET_BLOBS_PER_BLOCK - 1 blobs, but excessDataGas is off by \u00b11
Source code in tests/cancun/eip4844_blobs/test_excess_data_gas.py
@pytest.mark.parametrize(\n    \"parent_blobs,header_excess_data_gas_delta\",\n    [\n        (SpecHelpers.target_blobs_per_block() + 1, 1),\n        (SpecHelpers.target_blobs_per_block() + 1, Spec.DATA_GAS_PER_BLOB - 1),\n        (SpecHelpers.target_blobs_per_block() - 1, -1),\n        (SpecHelpers.target_blobs_per_block() - 1, -(Spec.DATA_GAS_PER_BLOB - 1)),\n    ],\n)\n@pytest.mark.parametrize(\"new_blobs\", [1])\n@pytest.mark.parametrize(\"parent_excess_blobs\", [SpecHelpers.target_blobs_per_block() + 1])\ndef test_invalid_non_multiple_excess_data_gas(\n    blockchain_test: BlockchainTestFiller,\n    env: Environment,\n    pre: Mapping[str, Account],\n    blocks: List[Block],\n    correct_excess_data_gas: int,\n    header_excess_data_gas: Optional[int],\n):\n\"\"\"\n    Test rejection of blocks where the `excessDataGas` changes to a value that\n    is not a multiple of Spec.DATA_GAS_PER_BLOB`:\n\n    - Parent block contains `TARGET_BLOBS_PER_BLOCK + 1` blobs, but `excessDataGas` is off by +/-1\n    - Parent block contains `TARGET_BLOBS_PER_BLOCK - 1` blobs, but `excessDataGas` is off by +/-1\n    \"\"\"\n    if header_excess_data_gas is None:\n        raise Exception(\"test case is badly formatted\")\n\n    if header_excess_data_gas == correct_excess_data_gas:\n        raise Exception(\"invalid test case\")\n\n    blockchain_test(\n        pre=pre,\n        post={},\n        blocks=blocks,\n        genesis_environment=env,\n        tag=\"-\".join(\n            [\n                f\"correct:{hex(correct_excess_data_gas)}\",\n                f\"header:{hex(header_excess_data_gas)}\",\n            ]\n        ),\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas/index/test_cases/","title":"Test Excess Data Gas - Test Cases","text":"

Test cases generated from tests/cancun/eip4844_blobs/test_excess_data_gas.py

Parametrized test cases generated from the test module tests/cancun/eip4844_blobs/test_excess_data_gas.py:

test_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=0]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=1]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=2]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=3]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=4]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=5]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=6]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=1-parent_blobs=0]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=1-parent_blobs=1]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=1-parent_blobs=2]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=1-parent_blobs=3]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=1-parent_blobs=4]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=1-parent_blobs=5]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=1-parent_blobs=6]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=2-parent_blobs=0]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=2-parent_blobs=1]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=2-parent_blobs=2]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=2-parent_blobs=3]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=2-parent_blobs=4]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=2-parent_blobs=5]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=2-parent_blobs=6]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=3-parent_blobs=0]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=3-parent_blobs=1]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=3-parent_blobs=2]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=3-parent_blobs=3]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=3-parent_blobs=4]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=3-parent_blobs=5]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=3-parent_blobs=6]\ntest_correct_increasing_data_gas_costs[fork=Cancun-new_blobs=1-parent_blobs=4-parent_excess_blobs=17]\ntest_correct_increasing_data_gas_costs[fork=Cancun-new_blobs=1-parent_blobs=4-parent_excess_blobs=264]\ntest_correct_increasing_data_gas_costs[fork=Cancun-new_blobs=1-parent_blobs=4-parent_excess_blobs=564]\ntest_correct_increasing_data_gas_costs[fork=Cancun-new_blobs=1-parent_blobs=4-parent_excess_blobs=829]\ntest_correct_increasing_data_gas_costs[fork=Cancun-new_blobs=1-parent_blobs=4-parent_excess_blobs=1129]\ntest_correct_increasing_data_gas_costs[fork=Cancun-new_blobs=1-parent_blobs=4-parent_excess_blobs=1229]\ntest_correct_decreasing_data_gas_costs[fork=Cancun-new_blobs=1-parent_blobs=2-parent_excess_blobs=18]\ntest_correct_decreasing_data_gas_costs[fork=Cancun-new_blobs=1-parent_blobs=2-parent_excess_blobs=265]\ntest_correct_decreasing_data_gas_costs[fork=Cancun-new_blobs=1-parent_blobs=2-parent_excess_blobs=565]\ntest_correct_decreasing_data_gas_costs[fork=Cancun-new_blobs=1-parent_blobs=2-parent_excess_blobs=830]\ntest_correct_decreasing_data_gas_costs[fork=Cancun-new_blobs=1-parent_blobs=2-parent_excess_blobs=1130]\ntest_correct_decreasing_data_gas_costs[fork=Cancun-new_blobs=1-parent_blobs=2-parent_excess_blobs=1230]\ntest_invalid_zero_excess_data_gas_in_header[fork=Cancun-parent_blobs=0-new_blobs=0-header_excess_data_gas=0]\ntest_invalid_zero_excess_data_gas_in_header[fork=Cancun-parent_blobs=0-new_blobs=1-header_excess_data_gas=0]\ntest_invalid_zero_excess_data_gas_in_header[fork=Cancun-parent_blobs=1-new_blobs=0-header_excess_data_gas=0]\ntest_invalid_zero_excess_data_gas_in_header[fork=Cancun-parent_blobs=1-new_blobs=1-header_excess_data_gas=0]\ntest_invalid_zero_excess_data_gas_in_header[fork=Cancun-parent_blobs=2-new_blobs=0-header_excess_data_gas=0]\ntest_invalid_zero_excess_data_gas_in_header[fork=Cancun-parent_blobs=2-new_blobs=1-header_excess_data_gas=0]\ntest_invalid_zero_excess_data_gas_in_header[fork=Cancun-parent_blobs=3-new_blobs=0-header_excess_data_gas=0]\ntest_invalid_zero_excess_data_gas_in_header[fork=Cancun-parent_blobs=3-new_blobs=1-header_excess_data_gas=0]\ntest_invalid_zero_excess_data_gas_in_header[fork=Cancun-parent_blobs=4-new_blobs=0-header_excess_data_gas=0]\ntest_invalid_zero_excess_data_gas_in_header[fork=Cancun-parent_blobs=4-new_blobs=1-header_excess_data_gas=0]\ntest_invalid_zero_excess_data_gas_in_header[fork=Cancun-parent_blobs=5-new_blobs=0-header_excess_data_gas=0]\ntest_invalid_zero_excess_data_gas_in_header[fork=Cancun-parent_blobs=5-new_blobs=1-header_excess_data_gas=0]\ntest_invalid_zero_excess_data_gas_in_header[fork=Cancun-parent_blobs=6-new_blobs=0-header_excess_data_gas=0]\ntest_invalid_zero_excess_data_gas_in_header[fork=Cancun-parent_blobs=6-new_blobs=1-header_excess_data_gas=0]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=0-header_data_gas_used=131072]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=0-header_data_gas_used=262144]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=0-header_data_gas_used=393216]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=0-header_data_gas_used=524288]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=0-header_data_gas_used=655360]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=0-header_data_gas_used=786432]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=0-header_data_gas_used=18446744073709551615]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=1-header_data_gas_used=0]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=1-header_data_gas_used=262144]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=1-header_data_gas_used=393216]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=1-header_data_gas_used=524288]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=1-header_data_gas_used=655360]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=1-header_data_gas_used=786432]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=1-header_data_gas_used=18446744073709551615]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=2-header_data_gas_used=0]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=2-header_data_gas_used=131072]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=2-header_data_gas_used=393216]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=2-header_data_gas_used=524288]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=2-header_data_gas_used=655360]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=2-header_data_gas_used=786432]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=2-header_data_gas_used=18446744073709551615]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=3-header_data_gas_used=0]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=3-header_data_gas_used=131072]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=3-header_data_gas_used=262144]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=3-header_data_gas_used=524288]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=3-header_data_gas_used=655360]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=3-header_data_gas_used=786432]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=3-header_data_gas_used=18446744073709551615]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=4-header_data_gas_used=0]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=4-header_data_gas_used=131072]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=4-header_data_gas_used=262144]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=4-header_data_gas_used=393216]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=4-header_data_gas_used=655360]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=4-header_data_gas_used=786432]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=4-header_data_gas_used=18446744073709551615]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=5-header_data_gas_used=0]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=5-header_data_gas_used=131072]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=5-header_data_gas_used=262144]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=5-header_data_gas_used=393216]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=5-header_data_gas_used=524288]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=5-header_data_gas_used=786432]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=5-header_data_gas_used=18446744073709551615]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=6-header_data_gas_used=0]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=6-header_data_gas_used=131072]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=6-header_data_gas_used=262144]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=6-header_data_gas_used=393216]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=6-header_data_gas_used=524288]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=6-header_data_gas_used=655360]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=6-header_data_gas_used=18446744073709551615]\ntest_invalid_excess_data_gas_above_target_change[fork=Cancun-new_blobs=1-zero_blobs_decrease_more_than_expected]\ntest_invalid_excess_data_gas_above_target_change[fork=Cancun-new_blobs=1-max_blobs_increase_more_than_expected]\ntest_invalid_static_excess_data_gas[fork=Cancun-new_blobs=1-parent_excess_blobs=1-parent_blobs=0]\ntest_invalid_static_excess_data_gas[fork=Cancun-new_blobs=1-parent_excess_blobs=1-parent_blobs=1]\ntest_invalid_static_excess_data_gas[fork=Cancun-new_blobs=1-parent_excess_blobs=1-parent_blobs=2]\ntest_invalid_static_excess_data_gas[fork=Cancun-new_blobs=1-parent_excess_blobs=1-parent_blobs=4]\ntest_invalid_static_excess_data_gas[fork=Cancun-new_blobs=1-parent_excess_blobs=1-parent_blobs=5]\ntest_invalid_static_excess_data_gas[fork=Cancun-new_blobs=1-parent_excess_blobs=1-parent_blobs=6]\ntest_invalid_static_excess_data_gas[fork=Cancun-new_blobs=1-parent_excess_blobs=3-parent_blobs=0]\ntest_invalid_static_excess_data_gas[fork=Cancun-new_blobs=1-parent_excess_blobs=3-parent_blobs=1]\ntest_invalid_static_excess_data_gas[fork=Cancun-new_blobs=1-parent_excess_blobs=3-parent_blobs=2]\ntest_invalid_static_excess_data_gas[fork=Cancun-new_blobs=1-parent_excess_blobs=3-parent_blobs=4]\ntest_invalid_static_excess_data_gas[fork=Cancun-new_blobs=1-parent_excess_blobs=3-parent_blobs=5]\ntest_invalid_static_excess_data_gas[fork=Cancun-new_blobs=1-parent_excess_blobs=3-parent_blobs=6]\ntest_invalid_excess_data_gas_target_blobs_increase_from_zero[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=0-header_excess_blobs_delta=1]\ntest_invalid_excess_data_gas_target_blobs_increase_from_zero[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=0-header_excess_blobs_delta=2]\ntest_invalid_excess_data_gas_target_blobs_increase_from_zero[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=0-header_excess_blobs_delta=3]\ntest_invalid_excess_data_gas_target_blobs_increase_from_zero[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=0-header_excess_blobs_delta=4]\ntest_invalid_excess_data_gas_target_blobs_increase_from_zero[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=0-header_excess_blobs_delta=5]\ntest_invalid_excess_data_gas_target_blobs_increase_from_zero[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=1-header_excess_blobs_delta=1]\ntest_invalid_excess_data_gas_target_blobs_increase_from_zero[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=1-header_excess_blobs_delta=2]\ntest_invalid_excess_data_gas_target_blobs_increase_from_zero[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=1-header_excess_blobs_delta=3]\ntest_invalid_excess_data_gas_target_blobs_increase_from_zero[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=1-header_excess_blobs_delta=4]\ntest_invalid_excess_data_gas_target_blobs_increase_from_zero[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=1-header_excess_blobs_delta=5]\ntest_invalid_excess_data_gas_target_blobs_increase_from_zero[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=2-header_excess_blobs_delta=1]\ntest_invalid_excess_data_gas_target_blobs_increase_from_zero[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=2-header_excess_blobs_delta=2]\ntest_invalid_excess_data_gas_target_blobs_increase_from_zero[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=2-header_excess_blobs_delta=3]\ntest_invalid_excess_data_gas_target_blobs_increase_from_zero[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=2-header_excess_blobs_delta=4]\ntest_invalid_excess_data_gas_target_blobs_increase_from_zero[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=2-header_excess_blobs_delta=5]\ntest_invalid_excess_data_gas_target_blobs_increase_from_zero[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=3-header_excess_blobs_delta=1]\ntest_invalid_excess_data_gas_target_blobs_increase_from_zero[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=3-header_excess_blobs_delta=2]\ntest_invalid_excess_data_gas_target_blobs_increase_from_zero[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=3-header_excess_blobs_delta=3]\ntest_invalid_excess_data_gas_target_blobs_increase_from_zero[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=3-header_excess_blobs_delta=4]\ntest_invalid_excess_data_gas_target_blobs_increase_from_zero[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=3-header_excess_blobs_delta=5]\ntest_invalid_static_excess_data_gas_from_zero_on_blobs_above_target[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=4-header_excess_data_gas=0]\ntest_invalid_static_excess_data_gas_from_zero_on_blobs_above_target[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=5-header_excess_data_gas=0]\ntest_invalid_static_excess_data_gas_from_zero_on_blobs_above_target[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=6-header_excess_data_gas=0]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=0-header_excess_blobs_delta=-3]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=0-header_excess_blobs_delta=-2]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=0-header_excess_blobs_delta=-1]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=0-header_excess_blobs_delta=1]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=0-header_excess_blobs_delta=2]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=0-header_excess_blobs_delta=3]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=1-header_excess_blobs_delta=-3]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=1-header_excess_blobs_delta=-2]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=1-header_excess_blobs_delta=-1]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=1-header_excess_blobs_delta=1]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=1-header_excess_blobs_delta=2]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=1-header_excess_blobs_delta=3]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=2-header_excess_blobs_delta=-3]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=2-header_excess_blobs_delta=-2]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=2-header_excess_blobs_delta=-1]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=2-header_excess_blobs_delta=1]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=2-header_excess_blobs_delta=2]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=2-header_excess_blobs_delta=3]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=3-header_excess_blobs_delta=-3]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=3-header_excess_blobs_delta=-2]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=3-header_excess_blobs_delta=-1]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=3-header_excess_blobs_delta=1]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=3-header_excess_blobs_delta=2]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=3-header_excess_blobs_delta=3]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=4-header_excess_blobs_delta=-3]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=4-header_excess_blobs_delta=-2]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=4-header_excess_blobs_delta=-1]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=4-header_excess_blobs_delta=1]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=4-header_excess_blobs_delta=2]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=4-header_excess_blobs_delta=3]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=5-header_excess_blobs_delta=-3]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=5-header_excess_blobs_delta=-2]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=5-header_excess_blobs_delta=-1]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=5-header_excess_blobs_delta=1]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=5-header_excess_blobs_delta=2]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=5-header_excess_blobs_delta=3]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=6-header_excess_blobs_delta=-3]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=6-header_excess_blobs_delta=-2]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=6-header_excess_blobs_delta=-1]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=6-header_excess_blobs_delta=1]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=6-header_excess_blobs_delta=2]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=6-header_excess_blobs_delta=3]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=0-new_blobs=1-parent_blobs=0-header_excess_data_gas=18446744073709158400]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=0-new_blobs=1-parent_blobs=0-header_excess_data_gas=18446744073709289472]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=0-new_blobs=1-parent_blobs=0-header_excess_data_gas=18446744073709420544]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=0-new_blobs=1-parent_blobs=1-header_excess_data_gas=18446744073709158400]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=0-new_blobs=1-parent_blobs=1-header_excess_data_gas=18446744073709289472]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=0-new_blobs=1-parent_blobs=1-header_excess_data_gas=18446744073709420544]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=0-new_blobs=1-parent_blobs=2-header_excess_data_gas=18446744073709158400]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=0-new_blobs=1-parent_blobs=2-header_excess_data_gas=18446744073709289472]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=0-new_blobs=1-parent_blobs=2-header_excess_data_gas=18446744073709420544]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=1-new_blobs=1-parent_blobs=0-header_excess_data_gas=18446744073709158400]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=1-new_blobs=1-parent_blobs=0-header_excess_data_gas=18446744073709289472]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=1-new_blobs=1-parent_blobs=0-header_excess_data_gas=18446744073709420544]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=1-new_blobs=1-parent_blobs=1-header_excess_data_gas=18446744073709158400]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=1-new_blobs=1-parent_blobs=1-header_excess_data_gas=18446744073709289472]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=1-new_blobs=1-parent_blobs=1-header_excess_data_gas=18446744073709420544]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=1-new_blobs=1-parent_blobs=2-header_excess_data_gas=18446744073709158400]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=1-new_blobs=1-parent_blobs=2-header_excess_data_gas=18446744073709289472]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=1-new_blobs=1-parent_blobs=2-header_excess_data_gas=18446744073709420544]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=2-new_blobs=1-parent_blobs=0-header_excess_data_gas=18446744073709158400]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=2-new_blobs=1-parent_blobs=0-header_excess_data_gas=18446744073709289472]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=2-new_blobs=1-parent_blobs=0-header_excess_data_gas=18446744073709420544]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=2-new_blobs=1-parent_blobs=1-header_excess_data_gas=18446744073709158400]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=2-new_blobs=1-parent_blobs=1-header_excess_data_gas=18446744073709289472]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=2-new_blobs=1-parent_blobs=1-header_excess_data_gas=18446744073709420544]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=2-new_blobs=1-parent_blobs=2-header_excess_data_gas=18446744073709158400]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=2-new_blobs=1-parent_blobs=2-header_excess_data_gas=18446744073709289472]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=2-new_blobs=1-parent_blobs=2-header_excess_data_gas=18446744073709420544]\ntest_invalid_non_multiple_excess_data_gas[fork=Cancun-parent_excess_blobs=4-new_blobs=1-parent_blobs=4-header_excess_data_gas_delta=1]\ntest_invalid_non_multiple_excess_data_gas[fork=Cancun-parent_excess_blobs=4-new_blobs=1-parent_blobs=4-header_excess_data_gas_delta=131071]\ntest_invalid_non_multiple_excess_data_gas[fork=Cancun-parent_excess_blobs=4-new_blobs=1-parent_blobs=2-header_excess_data_gas_delta=-1]\ntest_invalid_non_multiple_excess_data_gas[fork=Cancun-parent_excess_blobs=4-new_blobs=1-parent_blobs=2-header_excess_data_gas_delta=-131071]\n

This output was extracted from the result of:

fill --collect-only -q --until Cancun tests/cancun/eip4844_blobs/test_excess_data_gas.py\n
"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition/","title":"Test Excess Data Gas Fork Transition","text":"

Documentation for tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition.py.

Generate fixtures for these test cases for Cancun with:

Cancun only:

fill -v tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition.py --fork=Cancun --evm-bin=/path/to/evm-tool-dev-version\n
For all forks up to and including Cancun:
fill -v tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition.py --until=Cancun --evm-bin=/path/to/evm-tool-dev-version\n

Tests excessDataGas and dataGasUsed block fields for EIP-4844: Shard Blob Transactions at fork transition.

Test excessDataGas and dataGasUsed block fields for EIP-4844: Shard Blob Transactions at fork transition.

"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition/#tests.cancun.eip4844_blobs.test_excess_data_gas_fork_transition.Spec","title":"Spec dataclass","text":"

Bases: IntEnum

Parameters from the EIP-4844 specifications as defined at https://eips.ethereum.org/EIPS/eip-4844#parameters

If the parameter is not currently used within the tests, it is commented out.

Source code in tests/cancun/eip4844_blobs/spec.py
@dataclass(frozen=True)\nclass Spec(IntEnum):\n\"\"\"\n    Parameters from the EIP-4844 specifications as defined at\n    https://eips.ethereum.org/EIPS/eip-4844#parameters\n\n    If the parameter is not currently used within the tests, it is commented\n    out.\n    \"\"\"\n\n    BLOB_TX_TYPE = 0x03\n    FIELD_ELEMENTS_PER_BLOB = 4096\n    BLS_MODULUS = 0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001\n    BLOB_COMMITMENT_VERSION_KZG = 1\n    POINT_EVALUATION_PRECOMPILE_ADDRESS = 20\n    POINT_EVALUATION_PRECOMPILE_GAS = 50_000\n    MAX_DATA_GAS_PER_BLOCK = 786432\n    TARGET_DATA_GAS_PER_BLOCK = 393216\n    MIN_DATA_GASPRICE = 1\n    DATA_GASPRICE_UPDATE_FRACTION = 3338477\n    # MAX_VERSIONED_HASHES_LIST_SIZE = 2**24\n    # MAX_CALLDATA_SIZE = 2**24\n    # MAX_ACCESS_LIST_SIZE = 2**24\n    # MAX_ACCESS_LIST_STORAGE_KEYS = 2**24\n    # MAX_TX_WRAP_COMMITMENTS = 2**12\n    # LIMIT_BLOBS_PER_TX = 2**12\n    DATA_GAS_PER_BLOB = 2**17\n    HASH_OPCODE_BYTE = 0x49\n    HASH_GAS_COST = 3\n\n    @classmethod\n    def kzg_to_versioned_hash(\n        cls,\n        kzg_commitment: bytes | int,  # 48 bytes\n        blob_commitment_version_kzg: Optional[bytes | int] = None,\n    ) -> bytes:\n\"\"\"\n        Calculates the versioned hash for a given KZG commitment.\n        \"\"\"\n        if blob_commitment_version_kzg is None:\n            blob_commitment_version_kzg = cls.BLOB_COMMITMENT_VERSION_KZG\n        if isinstance(kzg_commitment, int):\n            kzg_commitment = kzg_commitment.to_bytes(48, \"big\")\n        if isinstance(blob_commitment_version_kzg, int):\n            blob_commitment_version_kzg = blob_commitment_version_kzg.to_bytes(1, \"big\")\n        return blob_commitment_version_kzg + sha256(kzg_commitment).digest()[1:]\n\n    @classmethod\n    def fake_exponential(cls, factor: int, numerator: int, denominator: int) -> int:\n\"\"\"\n        Used to calculate the data gas cost.\n        \"\"\"\n        i = 1\n        output = 0\n        numerator_accumulator = factor * denominator\n        while numerator_accumulator > 0:\n            output += numerator_accumulator\n            numerator_accumulator = (numerator_accumulator * numerator) // (denominator * i)\n            i += 1\n        return output // denominator\n\n    @classmethod\n    def calc_excess_data_gas(cls, parent: BlockHeaderDataGasFields) -> int:\n\"\"\"\n        Calculate the excess data gas for a block given the parent excess data gas\n        and the number of blobs in the block.\n        \"\"\"\n        if parent.excess_data_gas + parent.data_gas_used < cls.TARGET_DATA_GAS_PER_BLOCK:\n            return 0\n        else:\n            return parent.excess_data_gas + parent.data_gas_used - cls.TARGET_DATA_GAS_PER_BLOCK\n\n    # Note: Currently unused.\n    # @classmethod\n    # def get_total_data_gas(cls, tx: Transaction) -> int:\n    #     \"\"\"\n    #     Calculate the total data gas for a transaction.\n    #     \"\"\"\n    #     if tx.blob_versioned_hashes is None:\n    #         return 0\n    #     return cls.DATA_GAS_PER_BLOB.value * len(tx.blob_versioned_hashes)\n\n    @classmethod\n    def get_data_gasprice(cls, *, excess_data_gas: int) -> int:\n\"\"\"\n        Calculate the data gas price from the excess.\n        \"\"\"\n        return cls.fake_exponential(\n            cls.MIN_DATA_GASPRICE.value,\n            excess_data_gas,\n            cls.DATA_GASPRICE_UPDATE_FRACTION.value,\n        )\n
"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition/#tests.cancun.eip4844_blobs.test_excess_data_gas_fork_transition.SpecHelpers","title":"SpecHelpers dataclass","text":"

Bases: Enum

Define parameters and helper functions that are tightly coupled to the 4844 spec but not strictly part of it.

Source code in tests/cancun/eip4844_blobs/spec.py
@dataclass(frozen=True)\nclass SpecHelpers(Enum):\n\"\"\"\n    Define parameters and helper functions that are tightly coupled to the 4844\n    spec but not strictly part of it.\n    \"\"\"\n\n    BYTES_PER_FIELD_ELEMENT = 32\n\n    @classmethod\n    def max_blobs_per_block(cls) -> int:  # MAX_BLOBS_PER_BLOCK =\n\"\"\"\n        Returns the maximum number of blobs per block.\n        \"\"\"\n        return Spec.MAX_DATA_GAS_PER_BLOCK.value // Spec.DATA_GAS_PER_BLOB.value\n\n    @classmethod\n    def target_blobs_per_block(cls) -> int:\n\"\"\"\n        Returns the target number of blobs per block.\n        \"\"\"\n        return Spec.TARGET_DATA_GAS_PER_BLOCK.value // Spec.DATA_GAS_PER_BLOB.value\n\n    @classmethod\n    def calc_excess_data_gas_from_blob_count(\n        cls, parent_excess_data_gas: int, parent_blob_count: int\n    ) -> int:\n\"\"\"\n        Calculate the excess data gas for a block given the parent excess data gas\n        and the number of blobs in the block.\n        \"\"\"\n        parent_consumed_data_gas = parent_blob_count * Spec.DATA_GAS_PER_BLOB.value\n        return Spec.calc_excess_data_gas(\n            BlockHeaderDataGasFields(parent_excess_data_gas, parent_consumed_data_gas)\n        )\n\n    @classmethod\n    def get_min_excess_data_gas_for_data_gas_price(cls, data_gas_price: int) -> int:\n\"\"\"\n        Gets the minimum required excess data gas value to get a given data gas cost in a block\n        \"\"\"\n        current_excess_data_gas = 0\n        current_data_gas_price = 1\n        while current_data_gas_price < data_gas_price:\n            current_excess_data_gas += Spec.DATA_GAS_PER_BLOB.value\n            current_data_gas_price = Spec.get_data_gasprice(\n                excess_data_gas=current_excess_data_gas\n            )\n        return current_excess_data_gas\n\n    @classmethod\n    def get_min_excess_data_blobs_for_data_gas_price(cls, data_gas_price: int) -> int:\n\"\"\"\n        Gets the minimum required excess data blobs to get a given data gas cost in a block\n        \"\"\"\n        return (\n            cls.get_min_excess_data_gas_for_data_gas_price(data_gas_price)\n            // Spec.DATA_GAS_PER_BLOB.value\n        )\n
"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition/#tests.cancun.eip4844_blobs.test_excess_data_gas_fork_transition.test_invalid_pre_fork_block_with_blob_fields","title":"test_invalid_pre_fork_block_with_blob_fields(blockchain_test, env, pre, pre_fork_blocks, excess_data_gas_present, data_gas_used_present)","text":"

Test block rejection when excessDataGas and/or dataGasUsed fields are present on a pre-fork block.

Source code in tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition.py
@pytest.mark.parametrize(\n    \"excess_data_gas_present,data_gas_used_present\",\n    [\n        (True, False),\n        (False, True),\n        (True, True),\n    ],\n)\ndef test_invalid_pre_fork_block_with_blob_fields(\n    blockchain_test: BlockchainTestFiller,\n    env: Environment,\n    pre: Mapping[str, Account],\n    pre_fork_blocks: List[Block],\n    excess_data_gas_present: bool,\n    data_gas_used_present: bool,\n):\n\"\"\"\n    Test block rejection when `excessDataGas` and/or `dataGasUsed` fields are present on a pre-fork\n    block.\n    \"\"\"\n    header_modifier = Header()\n    if excess_data_gas_present:\n        header_modifier.excess_data_gas = 0\n    if data_gas_used_present:\n        header_modifier.data_gas_used = 0\n    blockchain_test(\n        pre=pre,\n        post={},\n        blocks=pre_fork_blocks[:-1]\n        + [\n            Block(\n                timestamp=(FORK_TIMESTAMP - 1),\n                rlp_modifier=header_modifier,\n                exception=\"invalid field\",\n            )\n        ],\n        genesis_environment=env,\n        tag=\"invalid_pre_fork_excess_data_gas\",\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition/#tests.cancun.eip4844_blobs.test_excess_data_gas_fork_transition.test_invalid_post_fork_block_without_blob_fields","title":"test_invalid_post_fork_block_without_blob_fields(blockchain_test, env, pre, pre_fork_blocks, excess_data_gas_missing, data_gas_used_missing)","text":"

Test block rejection when excessDataGas and/or dataGasUsed fields are missing on a post-fork block.

Source code in tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition.py
@pytest.mark.parametrize(\n    \"excess_data_gas_missing,data_gas_used_missing\",\n    [\n        (True, False),\n        (False, True),\n        (True, True),\n    ],\n)\ndef test_invalid_post_fork_block_without_blob_fields(\n    blockchain_test: BlockchainTestFiller,\n    env: Environment,\n    pre: Mapping[str, Account],\n    pre_fork_blocks: List[Block],\n    excess_data_gas_missing: bool,\n    data_gas_used_missing: bool,\n):\n\"\"\"\n    Test block rejection when `excessDataGas` and/or `dataGasUsed` fields are missing on a\n    post-fork block.\n    \"\"\"\n    header_modifier = Header()\n    if excess_data_gas_missing:\n        header_modifier.excess_data_gas = Header.REMOVE_FIELD\n    if data_gas_used_missing:\n        header_modifier.data_gas_used = Header.REMOVE_FIELD\n    blockchain_test(\n        pre=pre,\n        post={},\n        blocks=pre_fork_blocks\n        + [\n            Block(\n                timestamp=FORK_TIMESTAMP,\n                rlp_modifier=header_modifier,\n                exception=\"missing field\",\n            )\n        ],\n        genesis_environment=env,\n        tag=\"excess_data_gas_missing_post_fork\",\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition/#tests.cancun.eip4844_blobs.test_excess_data_gas_fork_transition.test_fork_transition_excess_data_gas","title":"test_fork_transition_excess_data_gas(blockchain_test, env, pre, pre_fork_blocks, post_fork_blocks, post)","text":"

Test excessDataGas calculation in the header when the fork is activated.

Also produce enough blocks to test the data gas price increase when the block is full with SpecHelpers.max_blobs_per_block()bs_per_block() blobs.

Source code in tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition.py
@pytest.mark.parametrize(\n    \"post_fork_block_count,blob_count_per_block\",\n    [\n        (\n            SpecHelpers.get_min_excess_data_blobs_for_data_gas_price(2)\n            // (SpecHelpers.max_blobs_per_block() - SpecHelpers.target_blobs_per_block())\n            + 2,\n            SpecHelpers.max_blobs_per_block(),\n        ),\n        (10, 0),\n        (10, SpecHelpers.target_blobs_per_block()),\n    ],\n    ids=[\"max_blobs\", \"no_blobs\", \"target_blobs\"],\n)\ndef test_fork_transition_excess_data_gas(\n    blockchain_test: BlockchainTestFiller,\n    env: Environment,\n    pre: Mapping[str, Account],\n    pre_fork_blocks: List[Block],\n    post_fork_blocks: List[Block],\n    post: Mapping[str, Account],\n):\n\"\"\"\n    Test `excessDataGas` calculation in the header when the fork is activated.\n\n    Also produce enough blocks to test the data gas price increase when the block is full with\n    `SpecHelpers.max_blobs_per_block()bs_per_block()` blobs.\n    \"\"\"\n    blockchain_test(\n        pre=pre,\n        post=post,\n        blocks=pre_fork_blocks + post_fork_blocks,\n        genesis_environment=env,\n        tag=\"correct_initial_data_gas_calc\",\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition/index/test_cases/","title":"Test Excess Data Gas Fork Transition - Test Cases","text":"

Test cases generated from tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition.py

Parametrized test cases generated from the test module tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition.py:

test_invalid_pre_fork_block_with_blob_fields[fork=ShanghaiToCancunAtTime15k-excess_data_gas_present=True-data_gas_used_present=False]\ntest_invalid_pre_fork_block_with_blob_fields[fork=ShanghaiToCancunAtTime15k-excess_data_gas_present=False-data_gas_used_present=True]\ntest_invalid_pre_fork_block_with_blob_fields[fork=ShanghaiToCancunAtTime15k-excess_data_gas_present=True-data_gas_used_present=True]\ntest_invalid_post_fork_block_without_blob_fields[fork=ShanghaiToCancunAtTime15k-excess_data_gas_missing=True-data_gas_used_missing=False]\ntest_invalid_post_fork_block_without_blob_fields[fork=ShanghaiToCancunAtTime15k-excess_data_gas_missing=False-data_gas_used_missing=True]\ntest_invalid_post_fork_block_without_blob_fields[fork=ShanghaiToCancunAtTime15k-excess_data_gas_missing=True-data_gas_used_missing=True]\ntest_fork_transition_excess_data_gas[fork=ShanghaiToCancunAtTime15k-max_blobs]\ntest_fork_transition_excess_data_gas[fork=ShanghaiToCancunAtTime15k-no_blobs]\ntest_fork_transition_excess_data_gas[fork=ShanghaiToCancunAtTime15k-target_blobs]\n

This output was extracted from the result of:

fill --collect-only -q --until Cancun tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition.py\n
"},{"location":"tests/cancun/eip4844_blobs/test_point_evaluation_precompile/","title":"Test Point Evaluation Precompile","text":"

Documentation for tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py.

Generate fixtures for these test cases for Cancun with:

Cancun only:

fill -v tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py --fork=Cancun --evm-bin=/path/to/evm-tool-dev-version\n
For all forks up to and including Cancun:
fill -v tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py --until=Cancun --evm-bin=/path/to/evm-tool-dev-version\n

Tests point evaluation precompile for EIP-4844: Shard Blob Transactions

Test point evaluation precompile for EIP-4844: Shard Blob Transactions.

Adding a new test

Add a function that is named test_<test_name> and takes at least the following arguments:

  • blockchain_test
  • pre
  • tx
  • post

The following arguments need to be parametrized or the test will not be generated:

  • versioned_hash
  • kzg_commitment
  • z
  • y
  • kzg_proof
  • success

These values correspond to a single call of the precompile, and success refers to whether the call should succeed or fail.

All other pytest.fixture fixtures can be parametrized to generate new combinations and test cases.

"},{"location":"tests/cancun/eip4844_blobs/test_point_evaluation_precompile/#tests.cancun.eip4844_blobs.test_point_evaluation_precompile.Spec","title":"Spec dataclass","text":"

Bases: IntEnum

Parameters from the EIP-4844 specifications as defined at https://eips.ethereum.org/EIPS/eip-4844#parameters

If the parameter is not currently used within the tests, it is commented out.

Source code in tests/cancun/eip4844_blobs/spec.py
@dataclass(frozen=True)\nclass Spec(IntEnum):\n\"\"\"\n    Parameters from the EIP-4844 specifications as defined at\n    https://eips.ethereum.org/EIPS/eip-4844#parameters\n\n    If the parameter is not currently used within the tests, it is commented\n    out.\n    \"\"\"\n\n    BLOB_TX_TYPE = 0x03\n    FIELD_ELEMENTS_PER_BLOB = 4096\n    BLS_MODULUS = 0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001\n    BLOB_COMMITMENT_VERSION_KZG = 1\n    POINT_EVALUATION_PRECOMPILE_ADDRESS = 20\n    POINT_EVALUATION_PRECOMPILE_GAS = 50_000\n    MAX_DATA_GAS_PER_BLOCK = 786432\n    TARGET_DATA_GAS_PER_BLOCK = 393216\n    MIN_DATA_GASPRICE = 1\n    DATA_GASPRICE_UPDATE_FRACTION = 3338477\n    # MAX_VERSIONED_HASHES_LIST_SIZE = 2**24\n    # MAX_CALLDATA_SIZE = 2**24\n    # MAX_ACCESS_LIST_SIZE = 2**24\n    # MAX_ACCESS_LIST_STORAGE_KEYS = 2**24\n    # MAX_TX_WRAP_COMMITMENTS = 2**12\n    # LIMIT_BLOBS_PER_TX = 2**12\n    DATA_GAS_PER_BLOB = 2**17\n    HASH_OPCODE_BYTE = 0x49\n    HASH_GAS_COST = 3\n\n    @classmethod\n    def kzg_to_versioned_hash(\n        cls,\n        kzg_commitment: bytes | int,  # 48 bytes\n        blob_commitment_version_kzg: Optional[bytes | int] = None,\n    ) -> bytes:\n\"\"\"\n        Calculates the versioned hash for a given KZG commitment.\n        \"\"\"\n        if blob_commitment_version_kzg is None:\n            blob_commitment_version_kzg = cls.BLOB_COMMITMENT_VERSION_KZG\n        if isinstance(kzg_commitment, int):\n            kzg_commitment = kzg_commitment.to_bytes(48, \"big\")\n        if isinstance(blob_commitment_version_kzg, int):\n            blob_commitment_version_kzg = blob_commitment_version_kzg.to_bytes(1, \"big\")\n        return blob_commitment_version_kzg + sha256(kzg_commitment).digest()[1:]\n\n    @classmethod\n    def fake_exponential(cls, factor: int, numerator: int, denominator: int) -> int:\n\"\"\"\n        Used to calculate the data gas cost.\n        \"\"\"\n        i = 1\n        output = 0\n        numerator_accumulator = factor * denominator\n        while numerator_accumulator > 0:\n            output += numerator_accumulator\n            numerator_accumulator = (numerator_accumulator * numerator) // (denominator * i)\n            i += 1\n        return output // denominator\n\n    @classmethod\n    def calc_excess_data_gas(cls, parent: BlockHeaderDataGasFields) -> int:\n\"\"\"\n        Calculate the excess data gas for a block given the parent excess data gas\n        and the number of blobs in the block.\n        \"\"\"\n        if parent.excess_data_gas + parent.data_gas_used < cls.TARGET_DATA_GAS_PER_BLOCK:\n            return 0\n        else:\n            return parent.excess_data_gas + parent.data_gas_used - cls.TARGET_DATA_GAS_PER_BLOCK\n\n    # Note: Currently unused.\n    # @classmethod\n    # def get_total_data_gas(cls, tx: Transaction) -> int:\n    #     \"\"\"\n    #     Calculate the total data gas for a transaction.\n    #     \"\"\"\n    #     if tx.blob_versioned_hashes is None:\n    #         return 0\n    #     return cls.DATA_GAS_PER_BLOB.value * len(tx.blob_versioned_hashes)\n\n    @classmethod\n    def get_data_gasprice(cls, *, excess_data_gas: int) -> int:\n\"\"\"\n        Calculate the data gas price from the excess.\n        \"\"\"\n        return cls.fake_exponential(\n            cls.MIN_DATA_GASPRICE.value,\n            excess_data_gas,\n            cls.DATA_GASPRICE_UPDATE_FRACTION.value,\n        )\n
"},{"location":"tests/cancun/eip4844_blobs/test_point_evaluation_precompile/#tests.cancun.eip4844_blobs.test_point_evaluation_precompile.test_valid_precompile_calls","title":"test_valid_precompile_calls(blockchain_test, pre, tx, post)","text":"

Test valid sanity precompile calls that are expected to succeed.

  • kzg_commitment and kzg_proof are set to values such that p(z)==0 for all values of z, hence y is tested to be zero, and call to be successful.
Source code in tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py
@pytest.mark.parametrize(\n    \"z,y,kzg_commitment,kzg_proof,versioned_hash\",\n    [\n        pytest.param(Spec.BLS_MODULUS - 1, 0, INF_POINT, INF_POINT, auto, id=\"in_bounds_z\"),\n    ],\n)\n@pytest.mark.parametrize(\"success\", [True])\n@pytest.mark.valid_from(\"Cancun\")\ndef test_valid_precompile_calls(\n    blockchain_test: BlockchainTestFiller,\n    pre: Dict,\n    tx: Transaction,\n    post: Dict,\n):\n\"\"\"\n    Test valid sanity precompile calls that are expected to succeed.\n\n    - `kzg_commitment` and `kzg_proof` are set to values such that `p(z)==0` for all values of `z`,\n    hence `y` is tested to be zero, and call to be successful.\n    \"\"\"\n    blockchain_test(\n        pre=pre,\n        post=post,\n        blocks=[Block(txs=[tx])],\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_point_evaluation_precompile/#tests.cancun.eip4844_blobs.test_point_evaluation_precompile.test_invalid_precompile_calls","title":"test_invalid_precompile_calls(blockchain_test, pre, tx, post)","text":"

Test invalid precompile calls:

  • Out of bounds inputs z and y
  • Correct proof, commitment, z and y, but incorrect lengths
  • Null inputs
  • Zero inputs
  • Correct proof, commitment, z and y, but incorrect version versioned hash
Source code in tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py
@pytest.mark.parametrize(\n    \"z,y,kzg_commitment,kzg_proof,versioned_hash\",\n    [\n        (Spec.BLS_MODULUS, 0, INF_POINT, INF_POINT, auto),\n        (0, Spec.BLS_MODULUS, INF_POINT, INF_POINT, auto),\n        (Z, 0, INF_POINT, INF_POINT[:-1], auto),\n        (Z, 0, INF_POINT, INF_POINT[0:1], auto),\n        (Z, 0, INF_POINT, INF_POINT + bytes([0]), auto),\n        (Z, 0, INF_POINT, INF_POINT + bytes([0] * 1023), auto),\n        (bytes(), bytes(), bytes(), bytes(), bytes()),\n        (0, 0, 0, 0, 0),\n        (0, 0, 0, 0, auto),\n        (Z, 0, INF_POINT, INF_POINT, Spec.kzg_to_versioned_hash(0xC0 << 376, 0x00)),\n        (Z, 0, INF_POINT, INF_POINT, Spec.kzg_to_versioned_hash(0xC0 << 376, 0x02)),\n        (Z, 0, INF_POINT, INF_POINT, Spec.kzg_to_versioned_hash(0xC0 << 376, 0xFF)),\n    ],\n    ids=[\n        \"out_of_bounds_z\",\n        \"out_of_bounds_y\",\n        \"correct_proof_1_input_too_short\",\n        \"correct_proof_1_input_too_short_2\",\n        \"correct_proof_1_input_too_long\",\n        \"correct_proof_1_input_extra_long\",\n        \"null_inputs\",\n        \"zeros_inputs\",\n        \"zeros_inputs_correct_versioned_hash\",\n        \"correct_proof_1_incorrect_versioned_hash_version_0x00\",\n        \"correct_proof_1_incorrect_versioned_hash_version_0x02\",\n        \"correct_proof_1_incorrect_versioned_hash_version_0xff\",\n    ],\n)\n@pytest.mark.parametrize(\"success\", [False])\n@pytest.mark.valid_from(\"Cancun\")\ndef test_invalid_precompile_calls(\n    blockchain_test: BlockchainTestFiller,\n    pre: Dict,\n    tx: Transaction,\n    post: Dict,\n):\n\"\"\"\n    Test invalid precompile calls:\n\n    - Out of bounds inputs `z` and `y`\n    - Correct proof, commitment, z and y, but incorrect lengths\n    - Null inputs\n    - Zero inputs\n    - Correct proof, commitment, z and y, but incorrect version versioned hash\n    \"\"\"\n    blockchain_test(\n        pre=pre,\n        post=post,\n        blocks=[Block(txs=[tx])],\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_point_evaluation_precompile/#tests.cancun.eip4844_blobs.test_point_evaluation_precompile.test_point_evaluation_precompile_external_vectors","title":"test_point_evaluation_precompile_external_vectors(blockchain_test, pre, tx, post)","text":"

Test precompile calls using external test vectors compiled from different sources:

  • go_kzg_4844_verify_kzg_proof.json: test vectors from the go-kzg-4844 repository.
Source code in tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py
@pytest.mark.parametrize(\n    \"z,y,kzg_commitment,kzg_proof,success\",\n    all_external_vectors(),\n)\n@pytest.mark.parametrize(\"versioned_hash\", [auto])\n@pytest.mark.valid_from(\"Cancun\")\ndef test_point_evaluation_precompile_external_vectors(\n    blockchain_test: BlockchainTestFiller,\n    pre: Dict,\n    tx: Transaction,\n    post: Dict,\n):\n\"\"\"\n    Test precompile calls using external test vectors compiled from different sources:\n\n    - `go_kzg_4844_verify_kzg_proof.json`: test vectors from the\n    [go-kzg-4844](https://github.com/crate-crypto/go-kzg-4844) repository.\n    \"\"\"\n    blockchain_test(\n        pre=pre,\n        post=post,\n        blocks=[Block(txs=[tx])],\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_point_evaluation_precompile/#tests.cancun.eip4844_blobs.test_point_evaluation_precompile.test_point_evaluation_precompile_calls","title":"test_point_evaluation_precompile_calls(blockchain_test, pre, tx, post)","text":"

Test calling the Point Evaluation Precompile with different call types, gas and parameter configuration:

  • Using CALL, DELEGATECALL, CALLCODE and STATICCALL.
  • Using correct and incorrect proofs
  • Using barely insufficient gas
Source code in tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py
@pytest.mark.parametrize(\n    \"call_gas,y,success\",\n    [\n        (Spec.POINT_EVALUATION_PRECOMPILE_GAS, 0, True),\n        (Spec.POINT_EVALUATION_PRECOMPILE_GAS, 1, False),\n        (Spec.POINT_EVALUATION_PRECOMPILE_GAS - 1, 0, False),\n    ],\n    ids=[\"correct\", \"incorrect\", \"insufficient_gas\"],\n)\n@pytest.mark.parametrize(\n    \"call_type\",\n    [\n        Op.CALL,\n        Op.DELEGATECALL,\n        Op.CALLCODE,\n        Op.STATICCALL,\n    ],\n)\n@pytest.mark.parametrize(\n    \"z,kzg_commitment,kzg_proof,versioned_hash\",\n    [[Z, INF_POINT, INF_POINT, auto]],\n    ids=[\"\"],\n)\n@pytest.mark.valid_from(\"Cancun\")\ndef test_point_evaluation_precompile_calls(\n    blockchain_test: BlockchainTestFiller,\n    pre: Dict,\n    tx: Transaction,\n    post: Dict,\n):\n\"\"\"\n    Test calling the Point Evaluation Precompile with different call types, gas\n    and parameter configuration:\n\n    - Using CALL, DELEGATECALL, CALLCODE and STATICCALL.\n    - Using correct and incorrect proofs\n    - Using barely insufficient gas\n    \"\"\"\n    blockchain_test(\n        pre=pre,\n        post=post,\n        blocks=[Block(txs=[tx])],\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_point_evaluation_precompile/#tests.cancun.eip4844_blobs.test_point_evaluation_precompile.test_point_evaluation_precompile_gas_tx_to","title":"test_point_evaluation_precompile_gas_tx_to(blockchain_test, precompile_input, call_gas, proof_correct)","text":"

Test calling the Point Evaluation Precompile directly as transaction entry point, and measure the gas consumption.

  • Using gas_limit with exact necessary gas, insufficient gas and extra gas.
  • Using correct and incorrect proofs
Source code in tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py
@pytest.mark.parametrize(\n    \"call_gas\",\n    [\n        (Spec.POINT_EVALUATION_PRECOMPILE_GAS),\n        (Spec.POINT_EVALUATION_PRECOMPILE_GAS + 1),\n        (Spec.POINT_EVALUATION_PRECOMPILE_GAS - 1),\n    ],\n    ids=[\"exact_gas\", \"extra_gas\", \"insufficient_gas\"],\n)\n@pytest.mark.parametrize(\n    \"z,y,kzg_commitment,kzg_proof,versioned_hash,proof_correct\",\n    [\n        [Z, 0, INF_POINT, INF_POINT, auto, True],\n        [Z, 1, INF_POINT, INF_POINT, auto, False],\n    ],\n    ids=[\"correct_proof\", \"incorrect_proof\"],\n)\n@pytest.mark.valid_from(\"Cancun\")\ndef test_point_evaluation_precompile_gas_tx_to(\n    blockchain_test: BlockchainTestFiller,\n    precompile_input: bytes,\n    call_gas: int,\n    proof_correct: bool,\n):\n\"\"\"\n    Test calling the Point Evaluation Precompile directly as\n    transaction entry point, and measure the gas consumption.\n\n    - Using `gas_limit` with exact necessary gas, insufficient gas and extra gas.\n    - Using correct and incorrect proofs\n    \"\"\"\n    start_balance = 10**18\n    pre = {\n        TestAddress: Account(\n            nonce=0,\n            balance=start_balance,\n        )\n    }\n\n    # Gas is appended the intrinsic gas cost of the transaction\n    intrinsic_gas_cost = 21_000 + eip_2028_transaction_data_cost(precompile_input)\n\n    # Consumed gas will only be the precompile gas if the proof is correct and\n    # the call gas is sufficient.\n    # Otherwise, the call gas will be consumed in full.\n    consumed_gas = (\n        Spec.POINT_EVALUATION_PRECOMPILE_GAS\n        if call_gas >= Spec.POINT_EVALUATION_PRECOMPILE_GAS and proof_correct\n        else call_gas\n    ) + intrinsic_gas_cost\n\n    fee_per_gas = 7\n\n    tx = Transaction(\n        ty=2,\n        nonce=0,\n        data=precompile_input,\n        to=to_address(Spec.POINT_EVALUATION_PRECOMPILE_ADDRESS.value),\n        value=0,\n        gas_limit=call_gas + intrinsic_gas_cost,\n        max_fee_per_gas=7,\n        max_priority_fee_per_gas=0,\n    )\n\n    post = {\n        TestAddress: Account(\n            nonce=1,\n            balance=start_balance - (consumed_gas * fee_per_gas),\n        )\n    }\n\n    blockchain_test(\n        pre=pre,\n        post=post,\n        blocks=[Block(txs=[tx])],\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_point_evaluation_precompile/#tests.cancun.eip4844_blobs.test_point_evaluation_precompile.test_point_evaluation_precompile_before_fork","title":"test_point_evaluation_precompile_before_fork(blockchain_test, pre, tx)","text":"

Test calling the Point Evaluation Precompile before the appropriate fork.

Source code in tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py
@pytest.mark.parametrize(\n    \"z,y,kzg_commitment,kzg_proof,versioned_hash\",\n    [[Z, 0, INF_POINT, INF_POINT, auto]],\n    ids=[\"correct_proof\"],\n)\n@pytest.mark.valid_at_transition_to(\"Cancun\")\ndef test_point_evaluation_precompile_before_fork(\n    blockchain_test: BlockchainTestFiller,\n    pre: Dict,\n    tx: Transaction,\n):\n\"\"\"\n    Test calling the Point Evaluation Precompile before the appropriate fork.\n    \"\"\"\n    precompile_caller_code = Op.SSTORE(\n        Op.NUMBER,\n        Op.CALL(\n            Op.GAS,\n            Spec.POINT_EVALUATION_PRECOMPILE_ADDRESS,\n            1,  # Value\n            0,  # Zero-length calldata\n            0,\n            0,  # Zero-length return\n            0,\n        ),\n    )\n    precompile_caller_address = to_address(0x100)\n\n    pre = {\n        TestAddress: Account(\n            nonce=0,\n            balance=0x10**18,\n        ),\n        precompile_caller_address: Account(\n            nonce=0,\n            code=precompile_caller_code,\n            balance=0x10**18,\n        ),\n    }\n\n    def tx_generator() -> Iterator[Transaction]:\n        nonce = 0  # Initial value\n        while True:\n            yield tx.with_nonce(nonce)\n            nonce = nonce + 1\n\n    iter_tx = tx_generator()\n\n    FORK_TIMESTAMP = 15_000\n    PRE_FORK_BLOCK_RANGE = range(999, FORK_TIMESTAMP, 1_000)\n\n    # Blocks before fork\n    blocks = [Block(timestamp=t, txs=[next(iter_tx)]) for t in PRE_FORK_BLOCK_RANGE]\n    # Block after fork\n    blocks += [Block(timestamp=FORK_TIMESTAMP, txs=[next(iter_tx)])]\n\n    post = {\n        precompile_caller_address: Account(\n            storage={b: 1 for b in range(1, len(PRE_FORK_BLOCK_RANGE) + 1)},\n            # The tx in last block succeeds; storage 0 by default.\n        ),\n        to_address(Spec.POINT_EVALUATION_PRECOMPILE_ADDRESS.value): Account(\n            balance=len(PRE_FORK_BLOCK_RANGE),\n        ),\n    }\n\n    blockchain_test(\n        tag=\"point_evaluation_precompile_before_fork\",\n        pre=pre,\n        post=post,\n        blocks=blocks,\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_point_evaluation_precompile/index/test_cases/","title":"Test Point Evaluation Precompile - Test Cases","text":"

Test cases generated from tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py

Parametrized test cases generated from the test module tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py:

test_valid_precompile_calls[fork=Cancun-success=True-in_bounds_z]\ntest_invalid_precompile_calls[fork=Cancun-success=False-out_of_bounds_z]\ntest_invalid_precompile_calls[fork=Cancun-success=False-out_of_bounds_y]\ntest_invalid_precompile_calls[fork=Cancun-success=False-correct_proof_1_input_too_short]\ntest_invalid_precompile_calls[fork=Cancun-success=False-correct_proof_1_input_too_short_2]\ntest_invalid_precompile_calls[fork=Cancun-success=False-correct_proof_1_input_too_long]\ntest_invalid_precompile_calls[fork=Cancun-success=False-correct_proof_1_input_extra_long]\ntest_invalid_precompile_calls[fork=Cancun-success=False-null_inputs]\ntest_invalid_precompile_calls[fork=Cancun-success=False-zeros_inputs]\ntest_invalid_precompile_calls[fork=Cancun-success=False-zeros_inputs_correct_versioned_hash]\ntest_invalid_precompile_calls[fork=Cancun-success=False-correct_proof_1_incorrect_versioned_hash_version_0x00]\ntest_invalid_precompile_calls[fork=Cancun-success=False-correct_proof_1_incorrect_versioned_hash_version_0x02]\ntest_invalid_precompile_calls[fork=Cancun-success=False-correct_proof_1_incorrect_versioned_hash_version_0xff]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_02e696ada7d4631d]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_08f9e2f1cb3d39db]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_0cf79b17cb5f4ea2]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_1ce8e4f69d5df899]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_26b753dec0560daa]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_31ebd010e6098750]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_3208425794224c3f]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_36817bfd67de97a8]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_392169c16a2e5ef6]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_3ac8dc31e9aa6a70]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_3c1e8b38219e3e12]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_3c87ec986c2656c2]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_3cd183d0bab85fb7]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_420f2a187ce77035]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_444b73ff54a19b44]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_53a9bdf4f75196da]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_7db4f140a955dd1a]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_83e53423a2dd93fe]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_9b24f8997145435c]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_9b754afb690c47e1]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_af669445747d2585]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_af8b75f664ed7d43]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_b6cb6698327d9835]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_b6ec3736f9ff2c62]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_becf2e1641bbd4e6]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_c3d4322ec17fe7cd]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_c5e1490d672d026d]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_cae5d3491190b777]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_d0992bc0387790a4]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_d736268229bd87ec]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_e68d7111a2364a49]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_ed6b180ec759bcf6]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_f0ed3dc11cdeb130]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_f47eb9fc139f6bfd]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_f7f44e1e864aa967]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_ffa6e97b97146517]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_02e696ada7d4631d]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_08f9e2f1cb3d39db]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_0cf79b17cb5f4ea2]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_1ce8e4f69d5df899]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_26b753dec0560daa]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_31ebd010e6098750]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_3208425794224c3f]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_36817bfd67de97a8]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_392169c16a2e5ef6]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_3ac8dc31e9aa6a70]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_3c1e8b38219e3e12]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_3c87ec986c2656c2]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_3cd183d0bab85fb7]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_420f2a187ce77035]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_444b73ff54a19b44]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_53a9bdf4f75196da]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_7db4f140a955dd1a]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_83e53423a2dd93fe]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_9b24f8997145435c]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_9b754afb690c47e1]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_af669445747d2585]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_af8b75f664ed7d43]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_b6cb6698327d9835]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_b6ec3736f9ff2c62]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_becf2e1641bbd4e6]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_c3d4322ec17fe7cd]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_c5e1490d672d026d]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_cae5d3491190b777]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_d0992bc0387790a4]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_d736268229bd87ec]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_e68d7111a2364a49]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_ed6b180ec759bcf6]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_f0ed3dc11cdeb130]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_f47eb9fc139f6bfd]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_f7f44e1e864aa967]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_ffa6e97b97146517]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_invalid_commitment_1b44e341d56c757d]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_invalid_commitment_32afa9561a4b3b91]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_invalid_commitment_3e55802a5ed3c757]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_invalid_commitment_e9d3e9ec16fbc15f]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_invalid_proof_1b44e341d56c757d]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_invalid_proof_32afa9561a4b3b91]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_invalid_proof_3e55802a5ed3c757]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_invalid_proof_e9d3e9ec16fbc15f]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_invalid_y_35d08d612aad2197]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_invalid_y_4aa6def8c35c9097]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_invalid_y_4e51cef08a61606f]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_invalid_y_64b9ff2b8f7dddee]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_invalid_y_b358a2e763727b70]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_invalid_y_eb0601fec84cc5e9]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_invalid_z_35d08d612aad2197]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_invalid_z_4aa6def8c35c9097]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_invalid_z_4e51cef08a61606f]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_invalid_z_64b9ff2b8f7dddee]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_invalid_z_b358a2e763727b70]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_invalid_z_eb0601fec84cc5e9]\ntest_point_evaluation_precompile_calls[fork=Cancun--call_type=CALL-correct]\ntest_point_evaluation_precompile_calls[fork=Cancun--call_type=CALL-incorrect]\ntest_point_evaluation_precompile_calls[fork=Cancun--call_type=CALL-insufficient_gas]\ntest_point_evaluation_precompile_calls[fork=Cancun--call_type=DELEGATECALL-correct]\ntest_point_evaluation_precompile_calls[fork=Cancun--call_type=DELEGATECALL-incorrect]\ntest_point_evaluation_precompile_calls[fork=Cancun--call_type=DELEGATECALL-insufficient_gas]\ntest_point_evaluation_precompile_calls[fork=Cancun--call_type=CALLCODE-correct]\ntest_point_evaluation_precompile_calls[fork=Cancun--call_type=CALLCODE-incorrect]\ntest_point_evaluation_precompile_calls[fork=Cancun--call_type=CALLCODE-insufficient_gas]\ntest_point_evaluation_precompile_calls[fork=Cancun--call_type=STATICCALL-correct]\ntest_point_evaluation_precompile_calls[fork=Cancun--call_type=STATICCALL-incorrect]\ntest_point_evaluation_precompile_calls[fork=Cancun--call_type=STATICCALL-insufficient_gas]\ntest_point_evaluation_precompile_gas_tx_to[fork=Cancun-correct_proof-exact_gas]\ntest_point_evaluation_precompile_gas_tx_to[fork=Cancun-correct_proof-extra_gas]\ntest_point_evaluation_precompile_gas_tx_to[fork=Cancun-correct_proof-insufficient_gas]\ntest_point_evaluation_precompile_gas_tx_to[fork=Cancun-incorrect_proof-exact_gas]\ntest_point_evaluation_precompile_gas_tx_to[fork=Cancun-incorrect_proof-extra_gas]\ntest_point_evaluation_precompile_gas_tx_to[fork=Cancun-incorrect_proof-insufficient_gas]\ntest_point_evaluation_precompile_before_fork[fork=ShanghaiToCancunAtTime15k-correct_proof]\n

This output was extracted from the result of:

fill --collect-only -q --until Cancun tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py\n
"},{"location":"tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas/","title":"Test Point Evaluation Precompile Gas","text":"

Documentation for tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas.py.

Generate fixtures for these test cases for Cancun with:

Cancun only:

fill -v tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas.py --fork=Cancun --evm-bin=/path/to/evm-tool-dev-version\n
For all forks up to and including Cancun:
fill -v tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas.py --until=Cancun --evm-bin=/path/to/evm-tool-dev-version\n

Tests gas usage on point evaluation precompile for EIP-4844: Shard Blob Transactions

Test gas usage on point evaluation precompile for EIP-4844: Shard Blob Transactions.

"},{"location":"tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas/#tests.cancun.eip4844_blobs.test_point_evaluation_precompile_gas.Spec","title":"Spec dataclass","text":"

Bases: IntEnum

Parameters from the EIP-4844 specifications as defined at https://eips.ethereum.org/EIPS/eip-4844#parameters

If the parameter is not currently used within the tests, it is commented out.

Source code in tests/cancun/eip4844_blobs/spec.py
@dataclass(frozen=True)\nclass Spec(IntEnum):\n\"\"\"\n    Parameters from the EIP-4844 specifications as defined at\n    https://eips.ethereum.org/EIPS/eip-4844#parameters\n\n    If the parameter is not currently used within the tests, it is commented\n    out.\n    \"\"\"\n\n    BLOB_TX_TYPE = 0x03\n    FIELD_ELEMENTS_PER_BLOB = 4096\n    BLS_MODULUS = 0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001\n    BLOB_COMMITMENT_VERSION_KZG = 1\n    POINT_EVALUATION_PRECOMPILE_ADDRESS = 20\n    POINT_EVALUATION_PRECOMPILE_GAS = 50_000\n    MAX_DATA_GAS_PER_BLOCK = 786432\n    TARGET_DATA_GAS_PER_BLOCK = 393216\n    MIN_DATA_GASPRICE = 1\n    DATA_GASPRICE_UPDATE_FRACTION = 3338477\n    # MAX_VERSIONED_HASHES_LIST_SIZE = 2**24\n    # MAX_CALLDATA_SIZE = 2**24\n    # MAX_ACCESS_LIST_SIZE = 2**24\n    # MAX_ACCESS_LIST_STORAGE_KEYS = 2**24\n    # MAX_TX_WRAP_COMMITMENTS = 2**12\n    # LIMIT_BLOBS_PER_TX = 2**12\n    DATA_GAS_PER_BLOB = 2**17\n    HASH_OPCODE_BYTE = 0x49\n    HASH_GAS_COST = 3\n\n    @classmethod\n    def kzg_to_versioned_hash(\n        cls,\n        kzg_commitment: bytes | int,  # 48 bytes\n        blob_commitment_version_kzg: Optional[bytes | int] = None,\n    ) -> bytes:\n\"\"\"\n        Calculates the versioned hash for a given KZG commitment.\n        \"\"\"\n        if blob_commitment_version_kzg is None:\n            blob_commitment_version_kzg = cls.BLOB_COMMITMENT_VERSION_KZG\n        if isinstance(kzg_commitment, int):\n            kzg_commitment = kzg_commitment.to_bytes(48, \"big\")\n        if isinstance(blob_commitment_version_kzg, int):\n            blob_commitment_version_kzg = blob_commitment_version_kzg.to_bytes(1, \"big\")\n        return blob_commitment_version_kzg + sha256(kzg_commitment).digest()[1:]\n\n    @classmethod\n    def fake_exponential(cls, factor: int, numerator: int, denominator: int) -> int:\n\"\"\"\n        Used to calculate the data gas cost.\n        \"\"\"\n        i = 1\n        output = 0\n        numerator_accumulator = factor * denominator\n        while numerator_accumulator > 0:\n            output += numerator_accumulator\n            numerator_accumulator = (numerator_accumulator * numerator) // (denominator * i)\n            i += 1\n        return output // denominator\n\n    @classmethod\n    def calc_excess_data_gas(cls, parent: BlockHeaderDataGasFields) -> int:\n\"\"\"\n        Calculate the excess data gas for a block given the parent excess data gas\n        and the number of blobs in the block.\n        \"\"\"\n        if parent.excess_data_gas + parent.data_gas_used < cls.TARGET_DATA_GAS_PER_BLOCK:\n            return 0\n        else:\n            return parent.excess_data_gas + parent.data_gas_used - cls.TARGET_DATA_GAS_PER_BLOCK\n\n    # Note: Currently unused.\n    # @classmethod\n    # def get_total_data_gas(cls, tx: Transaction) -> int:\n    #     \"\"\"\n    #     Calculate the total data gas for a transaction.\n    #     \"\"\"\n    #     if tx.blob_versioned_hashes is None:\n    #         return 0\n    #     return cls.DATA_GAS_PER_BLOB.value * len(tx.blob_versioned_hashes)\n\n    @classmethod\n    def get_data_gasprice(cls, *, excess_data_gas: int) -> int:\n\"\"\"\n        Calculate the data gas price from the excess.\n        \"\"\"\n        return cls.fake_exponential(\n            cls.MIN_DATA_GASPRICE.value,\n            excess_data_gas,\n            cls.DATA_GASPRICE_UPDATE_FRACTION.value,\n        )\n
"},{"location":"tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas/#tests.cancun.eip4844_blobs.test_point_evaluation_precompile_gas.test_point_evaluation_precompile_gas_usage","title":"test_point_evaluation_precompile_gas_usage(blockchain_test, pre, tx, post)","text":"

Test point evaluation precompile gas usage under different call contexts and gas limits:

  • Test using all call types (CALL, DELEGATECALL, CALLCODE, STATICCALL)
  • Test using different gas limits (exact gas, insufficient gas, extra gas)
  • Test using correct and incorrect proofs
Source code in tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas.py
@pytest.mark.parametrize(\n    \"call_type\",\n    [Op.CALL, Op.DELEGATECALL, Op.CALLCODE, Op.STATICCALL],\n)\n@pytest.mark.parametrize(\n    \"call_gas\",\n    [\n        Spec.POINT_EVALUATION_PRECOMPILE_GAS.value,\n        Spec.POINT_EVALUATION_PRECOMPILE_GAS.value - 1,\n        Spec.POINT_EVALUATION_PRECOMPILE_GAS.value + 1,\n    ],\n    ids=[\"exact_gas\", \"insufficient_gas\", \"extra_gas\"],\n)\n@pytest.mark.parametrize(\"proof\", [\"correct\", \"incorrect\"])\n@pytest.mark.valid_from(\"Cancun\")\ndef test_point_evaluation_precompile_gas_usage(\n    blockchain_test: BlockchainTestFiller,\n    pre: Dict,\n    tx: Transaction,\n    post: Dict,\n):\n\"\"\"\n    Test point evaluation precompile gas usage under different call contexts and gas limits:\n\n    - Test using all call types (CALL, DELEGATECALL, CALLCODE, STATICCALL)\n    - Test using different gas limits (exact gas, insufficient gas, extra gas)\n    - Test using correct and incorrect proofs\n    \"\"\"\n    blockchain_test(\n        pre=pre,\n        post=post,\n        blocks=[Block(txs=[tx])],\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas/index/test_cases/","title":"Test Point Evaluation Precompile Gas - Test Cases","text":"

Test cases generated from tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas.py

Parametrized test cases generated from the test module tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas.py:

test_point_evaluation_precompile_gas_usage[fork=Cancun-proof=correct-exact_gas-call_type=CALL]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=correct-exact_gas-call_type=DELEGATECALL]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=correct-exact_gas-call_type=CALLCODE]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=correct-exact_gas-call_type=STATICCALL]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=correct-insufficient_gas-call_type=CALL]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=correct-insufficient_gas-call_type=DELEGATECALL]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=correct-insufficient_gas-call_type=CALLCODE]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=correct-insufficient_gas-call_type=STATICCALL]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=correct-extra_gas-call_type=CALL]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=correct-extra_gas-call_type=DELEGATECALL]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=correct-extra_gas-call_type=CALLCODE]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=correct-extra_gas-call_type=STATICCALL]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=incorrect-exact_gas-call_type=CALL]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=incorrect-exact_gas-call_type=DELEGATECALL]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=incorrect-exact_gas-call_type=CALLCODE]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=incorrect-exact_gas-call_type=STATICCALL]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=incorrect-insufficient_gas-call_type=CALL]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=incorrect-insufficient_gas-call_type=DELEGATECALL]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=incorrect-insufficient_gas-call_type=CALLCODE]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=incorrect-insufficient_gas-call_type=STATICCALL]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=incorrect-extra_gas-call_type=CALL]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=incorrect-extra_gas-call_type=DELEGATECALL]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=incorrect-extra_gas-call_type=CALLCODE]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=incorrect-extra_gas-call_type=STATICCALL]\n

This output was extracted from the result of:

fill --collect-only -q --until Cancun tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas.py\n
"},{"location":"tests/frontier/","title":"Frontier","text":"

Documentation for tests/frontier.

Generate fixtures for these test cases with:

fill -v tests/frontier\n

Test cases for EVM functionality introduced in Frontier.

"},{"location":"tests/frontier/opcodes/","title":"Opcodes","text":"

Documentation for tests/frontier/opcodes.

Generate fixtures for these test cases with:

fill -v tests/frontier/opcodes\n

Test for opcodes introduced in Frontier.

"},{"location":"tests/frontier/opcodes/test_dup/","title":"Test DUP","text":"

Documentation for tests/frontier/opcodes/test_dup.py.

Generate fixtures for these test cases with:

fill -v tests/frontier/opcodes/test_dup.py\n
Test DUP

Test the DUP opcodes.

"},{"location":"tests/frontier/opcodes/test_dup/#tests.frontier.opcodes.test_dup.test_dup","title":"test_dup(state_test)","text":"

Test the DUP1-DUP16 opcodes.

Test case ported from:
  • ethereum/tests/GeneralStateTests/VMTests/vmTests/dup.json by Ori Pomerantz.
Source code in tests/frontier/opcodes/test_dup.py
def test_dup(state_test: StateTestFiller):\n\"\"\"\n    Test the DUP1-DUP16 opcodes.\n\n    note: Test case ported from:\n\n        - [ethereum/tests/GeneralStateTests/VMTests/vmTests/dup.json](https://github.com/ethereum/tests/blob/develop/GeneralStateTests/VMTests/vmTests/dup.json)\n        by Ori Pomerantz.\n    \"\"\"  # noqa: E501\n    env = Environment()\n    pre = {\"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b\": Account(balance=1000000000000000000000)}\n    txs = []\n    post = {}\n\n\"\"\"\n    We are setting up 16 accounts, ranging from 0x100 to 0x10f.\n    They push values into the stack from 0-16, but each contract uses a\n    different DUP opcode, and depending on the opcode used, the item copied\n    into the storage changes.\n    \"\"\"\n    for i in range(0, 16):\n\"\"\"\n        Account 0x100 uses DUP1,\n        Account 0x10f uses DUP16.\n        \"\"\"\n        account = to_address(0x100 + i)\n        dup_opcode = 0x80 + i\n\n        pre[account] = Account(\n            code=(\n                # Push 0 - 16 onto the stack\n\"\"\"0x6000 6001 6002 6003 6004 6005 6006 6007 6008 6009\n                         600A 600B 600C 600D 600E 600F 6010\"\"\"\n                +\n                # Use the DUP opcode for this account\n                hex(dup_opcode)[2:]\n                +\n                # Save each stack value into different keys in storage\n\"\"\"6000 55 6001 55 6002 55 6003 55 6004 55 6005 55\n                       6006 55 6007 55 6008 55 6009 55 600A 55 600B 55\n                       600C 55 600D 55 600E 55 600F 55 6010 55\"\"\"\n            )\n        )\n\n\"\"\"\n        Also we are sending one transaction to each account.\n        The storage of each will only change by one item: storage[0]\n        The value depends on the DUP opcode used.\n        \"\"\"\n        tx = Transaction(\n            ty=0x0,\n            nonce=i,\n            to=account,\n            gas_limit=500000,\n            gas_price=10,\n            protected=False,\n            data=\"\",\n        )\n        txs.append(tx)\n\n\"\"\"\n        Storage will be structured as follows:\n\n        0x00: 0x10-0x01 (Depending on DUP opcode)\n        0x01: 0x10\n        0x02: 0x0F\n        0x03: 0x0E\n        0x04: 0x0D\n        0x05: 0x0C\n        0x06: 0x0B\n        0x07: 0x0A\n        0x08: 0x09\n        0x09: 0x08\n        0x0A: 0x07\n        0x0B: 0x06\n        0x0C: 0x05\n        0x0D: 0x04\n        0x0E: 0x03\n        0x0F: 0x02\n        0x10: 0x01\n\n        DUP1 copies the first element of the stack (0x10).\n        DUP16 copies the 16th element of the stack (0x01).\n        \"\"\"\n        s: Storage.StorageDictType = dict(zip(range(1, 17), range(16, 0, -1)))\n        s[0] = 16 - i\n\n        post[account] = Account(storage=s)\n\n    state_test(env=env, pre=pre, post=post, txs=txs)\n
"},{"location":"tests/frontier/opcodes/test_dup/index/test_cases/","title":"Test DUP - Test Cases","text":"

Test cases generated from tests/frontier/opcodes/test_dup.py

Parametrized test cases generated from the test module tests/frontier/opcodes/test_dup.py:

test_dup[fork=Frontier]\ntest_dup[fork=Homestead]\ntest_dup[fork=Byzantium]\ntest_dup[fork=Constantinople]\ntest_dup[fork=ConstantinopleFix]\ntest_dup[fork=Istanbul]\ntest_dup[fork=Berlin]\ntest_dup[fork=London]\ntest_dup[fork=Merge]\ntest_dup[fork=Shanghai]\ntest_dup[fork=Cancun]\n

This output was extracted from the result of:

fill --collect-only -q --until Cancun tests/frontier/opcodes/test_dup.py\n
"},{"location":"tests/homestead/","title":"Homestead","text":"

Documentation for tests/homestead.

Generate fixtures for these test cases with:

fill -v tests/homestead\n

Test cases for EVM functionality introduced in Homestead.

"},{"location":"tests/homestead/yul/","title":"Yul","text":"

Documentation for tests/homestead/yul.

Generate fixtures for these test cases with:

fill -v tests/homestead/yul\n

Tests using Yul source for contracts.

"},{"location":"tests/homestead/yul/test_yul_example/","title":"Test Yul Example","text":"

Documentation for tests/homestead/yul/test_yul_example.py.

Generate fixtures for these test cases with:

fill -v tests/homestead/yul/test_yul_example.py\n

Test Yul Source Code Examples

"},{"location":"tests/homestead/yul/test_yul_example/#tests.homestead.yul.test_yul_example.test_yul","title":"test_yul(state_test, yul)","text":"

Test YUL compiled bytecode.

Source code in tests/homestead/yul/test_yul_example.py
@pytest.mark.valid_from(\"Homestead\")\ndef test_yul(state_test: StateTestFiller, yul: YulCompiler):\n\"\"\"\n    Test YUL compiled bytecode.\n    \"\"\"\n    env = Environment()\n\n    pre = {\n        \"0x1000000000000000000000000000000000000000\": Account(\n            balance=0x0BA1A9CE0BA1A9CE,\n            code=yul(\n\"\"\"\n            {\n                function f(a, b) -> c {\n                    c := add(a, b)\n                }\n\n                sstore(0, f(1, 2))\n                return(0, 32)\n            }\n            \"\"\"\n            ),\n        ),\n        TestAddress: Account(balance=0x0BA1A9CE0BA1A9CE),\n    }\n\n    tx = Transaction(\n        ty=0x0,\n        chain_id=0x0,\n        nonce=0,\n        to=\"0x1000000000000000000000000000000000000000\",\n        gas_limit=500000,\n        gas_price=10,\n        protected=False,\n    )\n\n    post = {\n        \"0x1000000000000000000000000000000000000000\": Account(\n            storage={\n                0x00: 0x03,\n            },\n        ),\n    }\n\n    state_test(env=env, pre=pre, post=post, txs=[tx])\n
"},{"location":"tests/homestead/yul/test_yul_example/index/test_cases/","title":"Test Yul Example - Test Cases","text":"

Test cases generated from tests/homestead/yul/test_yul_example.py

Parametrized test cases generated from the test module tests/homestead/yul/test_yul_example.py:

test_yul[fork=Homestead]\ntest_yul[fork=Byzantium]\ntest_yul[fork=Constantinople]\ntest_yul[fork=ConstantinopleFix]\ntest_yul[fork=Istanbul]\ntest_yul[fork=Berlin]\ntest_yul[fork=London]\ntest_yul[fork=Merge]\ntest_yul[fork=Shanghai]\ntest_yul[fork=Cancun]\n

This output was extracted from the result of:

fill --collect-only -q --until Cancun tests/homestead/yul/test_yul_example.py\n
"},{"location":"tests/istanbul/","title":"Istanbul","text":"

Documentation for tests/istanbul.

Generate fixtures for these test cases with:

fill -v tests/istanbul\n

Test cases for EVM functionality introduced in Istanbul.

"},{"location":"tests/istanbul/eip1344_chainid/","title":"EIP-1344 CHAINID","text":"

Documentation for tests/istanbul/eip1344_chainid.

Generate fixtures for these test cases with:

fill -v tests/istanbul/eip1344_chainid\n
Tests EIP-1344: ChainID Opcode

Test cases for EIP-1344: ChainID Opcode.

"},{"location":"tests/istanbul/eip1344_chainid/test_chainid/","title":"Test CHAINID","text":"

Documentation for tests/istanbul/eip1344_chainid/test_chainid.py.

Generate fixtures for these test cases with:

fill -v tests/istanbul/eip1344_chainid/test_chainid.py\n
Tests EIP-1344: CHAINID opcode

Test cases for EIP-1344: CHAINID opcode.

"},{"location":"tests/istanbul/eip1344_chainid/test_chainid/#tests.istanbul.eip1344_chainid.test_chainid.test_chainid","title":"test_chainid(state_test)","text":"

Test CHAINID opcode.

Source code in tests/istanbul/eip1344_chainid/test_chainid.py
@pytest.mark.valid_from(\"Istanbul\")\ndef test_chainid(state_test: StateTestFiller):\n\"\"\"\n    Test CHAINID opcode.\n    \"\"\"\n    env = Environment(\n        coinbase=\"0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba\",\n        difficulty=0x20000,\n        gas_limit=10000000000,\n        number=1,\n        timestamp=1000,\n    )\n\n    pre = {\n        to_address(0x100): Account(code=Op.SSTORE(1, Op.CHAINID) + Op.STOP),\n        TestAddress: Account(balance=1000000000000000000000),\n    }\n\n    tx = Transaction(\n        ty=0x0,\n        chain_id=0x0,\n        nonce=0,\n        to=to_address(0x100),\n        gas_limit=100000000,\n        gas_price=10,\n        protected=False,\n    )\n\n    post = {\n        to_address(0x100): Account(code=\"0x4660015500\", storage={\"0x01\": \"0x01\"}),\n    }\n\n    state_test(env=env, pre=pre, post=post, txs=[tx])\n
"},{"location":"tests/istanbul/eip1344_chainid/test_chainid/index/test_cases/","title":"Test CHAINID - Test Cases","text":"

Test cases generated from tests/istanbul/eip1344_chainid/test_chainid.py

Parametrized test cases generated from the test module tests/istanbul/eip1344_chainid/test_chainid.py:

test_chainid[fork=Istanbul]\ntest_chainid[fork=Berlin]\ntest_chainid[fork=London]\ntest_chainid[fork=Merge]\ntest_chainid[fork=Shanghai]\ntest_chainid[fork=Cancun]\n

This output was extracted from the result of:

fill --collect-only -q --until Cancun tests/istanbul/eip1344_chainid/test_chainid.py\n
"},{"location":"tests/merge/","title":"Merge","text":"

Documentation for tests/merge.

Generate fixtures for these test cases with:

fill -v tests/merge\n

Test cases for EVM functionality introduced in the Merge.

"},{"location":"tests/merge/security/","title":"Security","text":"

Documentation for tests/merge/security.

Generate fixtures for these test cases with:

fill -v tests/merge/security\n

Ethereum execution client tests related to security issues.

"},{"location":"tests/merge/security/test_selfdestruct_balance_bug/","title":"Test Selfdestruct Balance Bug","text":"

Documentation for tests/merge/security/test_selfdestruct_balance_bug.py.

Generate fixtures for these test cases with:

fill -v tests/merge/security/test_selfdestruct_balance_bug.py\n
Tests the Consensus Flaw During Block Processing related to SELFDESTRUCT

Tests the consensus-vulnerability reported in go-ethereum/security/advisories/GHSA-xw37-57qp-9mm4.

To reproduce the issue with this test case:

  1. Fill the test with the most recent geth evm version.
  2. Run the fixture output within a vulnerable geth version: v1.9.20 > geth >= v1.9.4.
"},{"location":"tests/merge/security/test_selfdestruct_balance_bug/#tests.merge.security.test_selfdestruct_balance_bug.test_tx_selfdestruct_balance_bug","title":"test_tx_selfdestruct_balance_bug(blockchain_test, yul)","text":"

Test that the vulnerability is not present by checking the balance of the 0xaa contract after executing specific transactions:

  1. Start with contract 0xaa which has initial balance of 3 wei. 0xaa contract code simply performs a self-destruct to itself.

  2. Send a transaction (tx 1) to invoke caller contract 0xcc (which has a balance of 1 wei), which in turn invokes 0xaa with a 1 wei call.

  3. Store the balance of 0xaa after the first transaction is processed. 0xaa self-destructed. Expected outcome: 0 wei.

  4. Send another transaction (tx 2) to call 0xaa with 5 wei.

  5. Store the balance of 0xaa after the second transaction is processed. No self-destruct. Expected outcome: 5 wei.

  6. Verify that:

    • Call within tx 1 is successful, i.e 0xaa self-destructed.
    • The balances of 0xaa after each tx are correct.
    • During tx 2, code in 0xaa does not execute, hence self-destruct mechanism does not trigger.
Source code in tests/merge/security/test_selfdestruct_balance_bug.py
@pytest.mark.compile_yul_with(\"Merge\")  # Shanghai refuses to compile SELFDESTRUCT\n@pytest.mark.valid_from(\"Constantinople\")\ndef test_tx_selfdestruct_balance_bug(blockchain_test: BlockchainTestFiller, yul: YulCompiler):\n\"\"\"\n    Test that the vulnerability is not present by checking the balance of the\n    `0xaa` contract after executing specific transactions:\n\n    1. Start with contract `0xaa` which has initial balance of 3 wei.\n        `0xaa` contract code simply performs a self-destruct to itself.\n\n    2. Send a transaction (tx 1) to invoke caller contract `0xcc` (which\n        has a balance of 1 wei), which in turn invokes `0xaa` with a 1 wei call.\n\n    3. Store the balance of `0xaa` after the first transaction\n        is processed. `0xaa` self-destructed. Expected outcome: 0 wei.\n\n    4. Send another transaction (tx 2) to call 0xaa with 5 wei.\n\n    5. Store the balance of `0xaa` after the second transaction\n        is processed. No self-destruct. Expected outcome: 5 wei.\n\n    6. Verify that:\n        - Call within tx 1 is successful, i.e `0xaa` self-destructed.\n        - The balances of `0xaa` after each tx are correct.\n        - During tx 2, code in `0xaa` does not execute,\n            hence self-destruct mechanism does not trigger.\n    \"\"\"\n    aa_code = yul(\n\"\"\"\n        {\n            /* 1st entrance is self-destruct */\n            if eq(0, callvalue()) {\n                selfdestruct(0x00000000000000000000000000000000000000AA)\n            }\n\n            /* 2nd entrance is other rnd code execution */\n            if eq(1, callvalue()) {\n                let x := selfbalance()\n                sstore(0, x)\n            }\n        }\n        \"\"\"\n    )\n\n    cc_code = Op.SSTORE(0xCA1101, Op.CALL(100000, 0xAA, 0, 0, 0, 0, 0)) + Op.CALL(\n        100000, 0xAA, 1, 0, 0, 0, 0\n    )\n\n    balance_code = Op.SSTORE(0xBA1AA, Op.BALANCE(0xAA))\n\n    pre = {\n        # sender\n        TestAddress: Account(balance=1000000000),\n        # caller\n        to_address(0xCC): Account(balance=1000000000, code=cc_code),\n        # initial balance of 3 wei\n        to_address(0xAA): Account(balance=3, code=aa_code),\n        # stores balance of 0xaa after each tx 1\n        to_address(0xBA11): Account(code=balance_code),\n        # stores balance of 0xaa after each tx 2\n        to_address(0xBA12): Account(code=balance_code),\n    }\n\n    blocks = [\n        Block(\n            txs=[\n                # Sender invokes caller, caller invokes 0xaa:\n                # calling with 1 wei call\n                Transaction(\n                    nonce=0,\n                    to=to_address(0xCC),\n                    gas_limit=1000000,\n                    gas_price=10,\n                ),\n                # Dummy tx to store balance of 0xaa after first TX.\n                Transaction(\n                    nonce=1,\n                    to=to_address(0xBA11),\n                    gas_limit=100000,\n                    gas_price=10,\n                ),\n                # Sender calls 0xaa with 5 wei.\n                Transaction(\n                    nonce=2,\n                    to=to_address(0xAA),\n                    gas_limit=100000,\n                    gas_price=10,\n                    value=5,\n                ),\n                # Dummy tx to store balance of 0xaa after second TX.\n                Transaction(\n                    nonce=3,\n                    to=to_address(0xBA12),\n                    gas_limit=100000,\n                    gas_price=10,\n                ),\n            ],\n        ),\n    ]\n\n    post = {\n        # Check call from caller has succeeded.\n        to_address(0xCC): Account(storage={0xCA1101: 1}),\n        # Check balance of 0xaa after tx 1 is 0 wei, i.e self-destructed.\n        # Vulnerable versions should return 1 wei.\n        to_address(0xBA11): Account(storage={0xBA1AA: 0}),\n        # Check that 0xaa exists and balance after tx 2 is 5 wei.\n        # Vulnerable versions should return 6 wei.\n        to_address(0xBA12): Account(storage={0xBA1AA: 5}),\n        to_address(0xAA): Account(storage={0: 0}),\n    }\n\n    blockchain_test(pre=pre, post=post, blocks=blocks)\n
"},{"location":"tests/merge/security/test_selfdestruct_balance_bug/index/test_cases/","title":"Test Selfdestruct Balance Bug - Test Cases","text":"

Test cases generated from tests/merge/security/test_selfdestruct_balance_bug.py

Parametrized test cases generated from the test module tests/merge/security/test_selfdestruct_balance_bug.py:

test_tx_selfdestruct_balance_bug[fork=Constantinople]\ntest_tx_selfdestruct_balance_bug[fork=ConstantinopleFix]\ntest_tx_selfdestruct_balance_bug[fork=Istanbul]\ntest_tx_selfdestruct_balance_bug[fork=Berlin]\ntest_tx_selfdestruct_balance_bug[fork=London]\ntest_tx_selfdestruct_balance_bug[fork=Merge]\ntest_tx_selfdestruct_balance_bug[fork=Shanghai]\ntest_tx_selfdestruct_balance_bug[fork=Cancun]\n

This output was extracted from the result of:

fill --collect-only -q --until Cancun tests/merge/security/test_selfdestruct_balance_bug.py\n
"},{"location":"tests/shanghai/","title":"Shanghai","text":"

Documentation for tests/shanghai.

Generate fixtures for these test cases with:

fill -v tests/shanghai\n

Test cases for EVM functionality introduced in Shanghai.

"},{"location":"tests/shanghai/eip3651_warm_coinbase/","title":"EIP-3651 Warm Coinbase","text":"

Documentation for tests/shanghai/eip3651_warm_coinbase.

Generate fixtures for these test cases with:

fill -v tests/shanghai/eip3651_warm_coinbase\n
Tests EIP-3651: Warm COINBASE

Tests for EIP-3651: Warm COINBASE.

"},{"location":"tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase/","title":"Test Warm Coinbase","text":"

Documentation for tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase.py.

Generate fixtures for these test cases with:

fill -v tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase.py\n
Tests EIP-3651: Warm COINBASE

Tests for EIP-3651: Warm COINBASE.

Tests ported from:
  • ethereum/tests/pull/1082.
"},{"location":"tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase/#tests.shanghai.eip3651_warm_coinbase.test_warm_coinbase.test_warm_coinbase_call_out_of_gas","title":"test_warm_coinbase_call_out_of_gas(state_test, fork, opcode, contract_under_test_code, call_gas_exact, use_sufficient_gas)","text":"

Test that the coinbase is warm by accessing the COINBASE with each of the following opcodes:

  • CALL
  • CALLCODE
  • DELEGATECALL
  • STATICCALL
Source code in tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase.py
@pytest.mark.valid_from(\"Shanghai\")\n@pytest.mark.parametrize(\n    \"use_sufficient_gas\",\n    [True, False],\n    ids=[\"sufficient_gas\", \"insufficient_gas\"],\n)\n@pytest.mark.parametrize(\n    \"opcode,contract_under_test_code,call_gas_exact\",\n    [\n        (\n            \"call\",\n            Op.POP(Op.CALL(0, Op.COINBASE, 0, 0, 0, 0, 0)),\n            # Extra gas: COINBASE + 4*PUSH1 + 2*DUP1 + POP\n            GAS_REQUIRED_CALL_WARM_ACCOUNT + 22,\n        ),\n        (\n            \"callcode\",\n            Op.POP(Op.CALLCODE(0, Op.COINBASE, 0, 0, 0, 0, 0)),\n            # Extra gas: COINBASE + 4*PUSH1 + 2*DUP1 + POP\n            GAS_REQUIRED_CALL_WARM_ACCOUNT + 22,\n        ),\n        (\n            \"delegatecall\",\n            Op.POP(Op.DELEGATECALL(0, Op.COINBASE, 0, 0, 0, 0)),\n            # Extra: COINBASE + 3*PUSH1 + 2*DUP1 + POP\n            GAS_REQUIRED_CALL_WARM_ACCOUNT + 19,\n        ),\n        (\n            \"staticcall\",\n            Op.POP(Op.STATICCALL(0, Op.COINBASE, 0, 0, 0, 0)),\n            # Extra: COINBASE + 3*PUSH1 + 2*DUP1 + POP\n            GAS_REQUIRED_CALL_WARM_ACCOUNT + 19,\n        ),\n    ],\n    ids=[\"CALL\", \"CALLCODE\", \"DELEGATECALL\", \"STATICCALL\"],\n)\ndef test_warm_coinbase_call_out_of_gas(\n    state_test,\n    fork,\n    opcode,\n    contract_under_test_code,\n    call_gas_exact,\n    use_sufficient_gas,\n):\n\"\"\"\n    Test that the coinbase is warm by accessing the COINBASE with each\n    of the following opcodes:\n\n    - CALL\n    - CALLCODE\n    - DELEGATECALL\n    - STATICCALL\n    \"\"\"\n    env = Environment(\n        coinbase=\"0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba\",\n        difficulty=0x20000,\n        gas_limit=10000000000,\n        number=1,\n        timestamp=1000,\n    )\n    caller_address = \"0xcccccccccccccccccccccccccccccccccccccccc\"\n    contract_under_test_address = 0x100\n\n    if not use_sufficient_gas:\n        call_gas_exact -= 1\n\n    caller_code = Op.SSTORE(\n        0,\n        Op.CALL(call_gas_exact, contract_under_test_address, 0, 0, 0, 0, 0),\n    )\n\n    pre = {\n        TestAddress: Account(balance=1000000000000000000000),\n        caller_address: Account(code=caller_code),\n        to_address(contract_under_test_address): Account(code=contract_under_test_code),\n    }\n\n    tx = Transaction(\n        ty=0x0,\n        chain_id=0x0,\n        nonce=0,\n        to=caller_address,\n        gas_limit=100000000,\n        gas_price=10,\n        protected=False,\n    )\n\n    post = {}\n\n    if use_sufficient_gas and is_fork(fork=fork, which=Shanghai):\n        post[caller_address] = Account(\n            storage={\n                # On shanghai and beyond, calls with only 100 gas to\n                # coinbase will succeed.\n                0: 1,\n            }\n        )\n    else:\n        post[caller_address] = Account(\n            storage={\n                # Before shanghai, calls with only 100 gas to\n                # coinbase will fail.\n                0: 0,\n            }\n        )\n\n    state_test(\n        env=env,\n        pre=pre,\n        post=post,\n        txs=[tx],\n        tag=\"opcode_\" + opcode,\n    )\n
"},{"location":"tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase/#tests.shanghai.eip3651_warm_coinbase.test_warm_coinbase.test_warm_coinbase_gas_usage","title":"test_warm_coinbase_gas_usage(state_test, fork, opcode, code_gas_measure)","text":"

Test the gas usage of opcodes affected by assuming a warm coinbase:

  • EXTCODESIZE
  • EXTCODECOPY
  • EXTCODEHASH
  • BALANCE
  • CALL
  • CALLCODE
  • DELEGATECALL
  • STATICCALL
Source code in tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase.py
@pytest.mark.valid_from(\"Merge\")  # these tests fill for fork >= Berlin\n@pytest.mark.parametrize(\n    \"opcode,code_gas_measure\",\n    gas_measured_opcodes,\n    ids=[i[0] for i in gas_measured_opcodes],\n)\ndef test_warm_coinbase_gas_usage(state_test, fork, opcode, code_gas_measure):\n\"\"\"\n    Test the gas usage of opcodes affected by assuming a warm coinbase:\n\n    - EXTCODESIZE\n    - EXTCODECOPY\n    - EXTCODEHASH\n    - BALANCE\n    - CALL\n    - CALLCODE\n    - DELEGATECALL\n    - STATICCALL\n    \"\"\"\n    env = Environment(\n        coinbase=\"0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba\",\n        difficulty=0x20000,\n        gas_limit=10000000000,\n        number=1,\n        timestamp=1000,\n    )\n\n    measure_address = to_address(0x100)\n    pre = {\n        TestAddress: Account(balance=1000000000000000000000),\n        measure_address: Account(\n            code=code_gas_measure,\n        ),\n    }\n\n    if is_fork(fork, Shanghai):\n        expected_gas = GAS_REQUIRED_CALL_WARM_ACCOUNT  # Warm account access cost after EIP-3651\n    else:\n        expected_gas = 2600  # Cold account access cost before EIP-3651\n\n    post = {\n        measure_address: Account(\n            storage={\n                0x00: expected_gas,\n            }\n        )\n    }\n    tx = Transaction(\n        ty=0x0,\n        chain_id=0x0,\n        nonce=0,\n        to=measure_address,\n        gas_limit=100000000,\n        gas_price=10,\n        protected=False,\n    )\n\n    state_test(\n        env=env,\n        pre=pre,\n        post=post,\n        txs=[tx],\n        tag=\"opcode_\" + opcode.lower(),\n    )\n
"},{"location":"tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase/index/test_cases/","title":"Test Warm Coinbase - Test Cases","text":"

Test cases generated from tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase.py

Parametrized test cases generated from the test module tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase.py:

test_warm_coinbase_call_out_of_gas[fork=Shanghai-CALL-sufficient_gas]\ntest_warm_coinbase_call_out_of_gas[fork=Shanghai-CALL-insufficient_gas]\ntest_warm_coinbase_call_out_of_gas[fork=Shanghai-CALLCODE-sufficient_gas]\ntest_warm_coinbase_call_out_of_gas[fork=Shanghai-CALLCODE-insufficient_gas]\ntest_warm_coinbase_call_out_of_gas[fork=Shanghai-DELEGATECALL-sufficient_gas]\ntest_warm_coinbase_call_out_of_gas[fork=Shanghai-DELEGATECALL-insufficient_gas]\ntest_warm_coinbase_call_out_of_gas[fork=Shanghai-STATICCALL-sufficient_gas]\ntest_warm_coinbase_call_out_of_gas[fork=Shanghai-STATICCALL-insufficient_gas]\ntest_warm_coinbase_call_out_of_gas[fork=Cancun-CALL-sufficient_gas]\ntest_warm_coinbase_call_out_of_gas[fork=Cancun-CALL-insufficient_gas]\ntest_warm_coinbase_call_out_of_gas[fork=Cancun-CALLCODE-sufficient_gas]\ntest_warm_coinbase_call_out_of_gas[fork=Cancun-CALLCODE-insufficient_gas]\ntest_warm_coinbase_call_out_of_gas[fork=Cancun-DELEGATECALL-sufficient_gas]\ntest_warm_coinbase_call_out_of_gas[fork=Cancun-DELEGATECALL-insufficient_gas]\ntest_warm_coinbase_call_out_of_gas[fork=Cancun-STATICCALL-sufficient_gas]\ntest_warm_coinbase_call_out_of_gas[fork=Cancun-STATICCALL-insufficient_gas]\ntest_warm_coinbase_gas_usage[fork=Merge-EXTCODESIZE]\ntest_warm_coinbase_gas_usage[fork=Merge-EXTCODECOPY]\ntest_warm_coinbase_gas_usage[fork=Merge-EXTCODEHASH]\ntest_warm_coinbase_gas_usage[fork=Merge-BALANCE]\ntest_warm_coinbase_gas_usage[fork=Merge-CALL]\ntest_warm_coinbase_gas_usage[fork=Merge-CALLCODE]\ntest_warm_coinbase_gas_usage[fork=Merge-DELEGATECALL]\ntest_warm_coinbase_gas_usage[fork=Merge-STATICCALL]\ntest_warm_coinbase_gas_usage[fork=Shanghai-EXTCODESIZE]\ntest_warm_coinbase_gas_usage[fork=Shanghai-EXTCODECOPY]\ntest_warm_coinbase_gas_usage[fork=Shanghai-EXTCODEHASH]\ntest_warm_coinbase_gas_usage[fork=Shanghai-BALANCE]\ntest_warm_coinbase_gas_usage[fork=Shanghai-CALL]\ntest_warm_coinbase_gas_usage[fork=Shanghai-CALLCODE]\ntest_warm_coinbase_gas_usage[fork=Shanghai-DELEGATECALL]\ntest_warm_coinbase_gas_usage[fork=Shanghai-STATICCALL]\ntest_warm_coinbase_gas_usage[fork=Cancun-EXTCODESIZE]\ntest_warm_coinbase_gas_usage[fork=Cancun-EXTCODECOPY]\ntest_warm_coinbase_gas_usage[fork=Cancun-EXTCODEHASH]\ntest_warm_coinbase_gas_usage[fork=Cancun-BALANCE]\ntest_warm_coinbase_gas_usage[fork=Cancun-CALL]\ntest_warm_coinbase_gas_usage[fork=Cancun-CALLCODE]\ntest_warm_coinbase_gas_usage[fork=Cancun-DELEGATECALL]\ntest_warm_coinbase_gas_usage[fork=Cancun-STATICCALL]\n

This output was extracted from the result of:

fill --collect-only -q --until Cancun tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase.py\n
"},{"location":"tests/shanghai/eip3855_push0/","title":"EIP-3855 Push0","text":"

Documentation for tests/shanghai/eip3855_push0.

Generate fixtures for these test cases with:

fill -v tests/shanghai/eip3855_push0\n
Tests EIP-3855: PUSH0 Instruction

Tests for EIP-3855: PUSH0 Instruction.

"},{"location":"tests/shanghai/eip3855_push0/test_push0/","title":"Test Push0","text":"

Documentation for tests/shanghai/eip3855_push0/test_push0.py.

Generate fixtures for these test cases with:

fill -v tests/shanghai/eip3855_push0/test_push0.py\n
Tests EIP-3855: PUSH0 Instruction

Tests for EIP-3855: PUSH0 Instruction.

Tests ported from:
  • ethereum/tests/pull/1033.
"},{"location":"tests/shanghai/eip3855_push0/test_push0/#tests.shanghai.eip3855_push0.test_push0.test_push0_key_sstore","title":"test_push0_key_sstore(state_test, env, pre, post, tx, addr_1)","text":"

Use PUSH0 to set a key for SSTORE.

Source code in tests/shanghai/eip3855_push0/test_push0.py
def test_push0_key_sstore(\n    state_test: StateTestFiller,\n    env: Environment,\n    pre: dict,\n    post: dict,\n    tx: Transaction,\n    addr_1: str,\n):\n\"\"\"\n    Use PUSH0 to set a key for SSTORE.\n    \"\"\"\n    code = Op.SSTORE(Op.PUSH0, 1)\n\n    pre[addr_1] = Account(code=code)\n    post[addr_1] = Account(storage={0x00: 0x01})\n\n    state_test(env=env, pre=pre, post=post, txs=[tx], tag=\"key_sstore\")\n
"},{"location":"tests/shanghai/eip3855_push0/test_push0/#tests.shanghai.eip3855_push0.test_push0.test_push0_fill_stack","title":"test_push0_fill_stack(state_test, env, pre, post, tx, addr_1)","text":"

Fill stack with PUSH0, then OR all values and save using SSTORE.

Source code in tests/shanghai/eip3855_push0/test_push0.py
def test_push0_fill_stack(\n    state_test: StateTestFiller,\n    env: Environment,\n    pre: dict,\n    post: dict,\n    tx: Transaction,\n    addr_1: str,\n):\n\"\"\"\n    Fill stack with PUSH0, then OR all values and save using SSTORE.\n    \"\"\"\n    code = Op.PUSH0 * 1024\n    code += Op.OR * 1023\n    code += Op.SSTORE(Op.SWAP1, 1)\n\n    pre[addr_1] = Account(code=code)\n    post[addr_1] = Account(storage={0x00: 0x01})\n\n    state_test(env=env, pre=pre, post=post, txs=[tx], tag=\"fill_stack\")\n
"},{"location":"tests/shanghai/eip3855_push0/test_push0/#tests.shanghai.eip3855_push0.test_push0.test_push0_stack_overflow","title":"test_push0_stack_overflow(state_test, env, pre, post, tx, addr_1)","text":"

Stack overflow by using PUSH0 1025 times.

Source code in tests/shanghai/eip3855_push0/test_push0.py
def test_push0_stack_overflow(\n    state_test: StateTestFiller,\n    env: Environment,\n    pre: dict,\n    post: dict,\n    tx: Transaction,\n    addr_1: str,\n):\n\"\"\"\n    Stack overflow by using PUSH0 1025 times.\n    \"\"\"\n    code = Op.SSTORE(Op.PUSH0, 1)\n    code += Op.PUSH0 * 1025\n\n    pre[addr_1] = Account(code=code)\n    post[addr_1] = Account(storage={0x00: 0x00})\n\n    state_test(env=env, pre=pre, post=post, txs=[tx], tag=\"stack_overflow\")\n
"},{"location":"tests/shanghai/eip3855_push0/test_push0/#tests.shanghai.eip3855_push0.test_push0.test_push0_storage_overwrite","title":"test_push0_storage_overwrite(state_test, env, pre, post, tx, addr_1)","text":"

Update an already existing storage value.

Source code in tests/shanghai/eip3855_push0/test_push0.py
def test_push0_storage_overwrite(\n    state_test: StateTestFiller,\n    env: Environment,\n    pre: dict,\n    post: dict,\n    tx: Transaction,\n    addr_1: str,\n):\n\"\"\"\n    Update an already existing storage value.\n    \"\"\"\n    code = Op.SSTORE(Op.PUSH0, 2) + Op.SSTORE(1, Op.PUSH0)\n\n    pre[addr_1] = Account(code=code, storage={0x00: 0x0A, 0x01: 0x0A})\n    post[addr_1] = Account(storage={0x00: 0x02, 0x01: 0x00})\n\n    state_test(env=env, pre=pre, post=post, txs=[tx], tag=\"storage_overwrite\")\n
"},{"location":"tests/shanghai/eip3855_push0/test_push0/#tests.shanghai.eip3855_push0.test_push0.test_push0_during_staticcall","title":"test_push0_during_staticcall(state_test, env, pre, post, tx, addr_1)","text":"

Test PUSH0 during STATICCALL.

Source code in tests/shanghai/eip3855_push0/test_push0.py
def test_push0_during_staticcall(\n    state_test: StateTestFiller,\n    env: Environment,\n    pre: dict,\n    post: dict,\n    tx: Transaction,\n    addr_1: str,\n):\n\"\"\"\n    Test PUSH0 during STATICCALL.\n    \"\"\"\n    addr_2 = to_address(0x200)\n\n    code_1 = (\n        Op.SSTORE(0, Op.STATICCALL(100000, 0x200, 0, 0, 0, 0))\n        + Op.SSTORE(0, 1)\n        + Op.RETURNDATACOPY(0x1F, 0, 1)\n        + Op.SSTORE(1, Op.MLOAD(0))\n    )\n    code_2 = Op.MSTORE8(Op.PUSH0, 0xFF) + Op.RETURN(Op.PUSH0, 1)\n\n    pre[addr_1] = Account(code=code_1)\n    pre[addr_2] = Account(code=code_2)\n    post[addr_1] = Account(storage={0x00: 0x01, 0x01: 0xFF})\n\n    state_test(env=env, pre=pre, post=post, txs=[tx], tag=\"during_staticcall\")\n
"},{"location":"tests/shanghai/eip3855_push0/test_push0/#tests.shanghai.eip3855_push0.test_push0.test_push0_before_jumpdest","title":"test_push0_before_jumpdest(state_test, env, pre, post, tx, addr_1)","text":"

Jump to a JUMPDEST next to a PUSH0, must succeed.

Source code in tests/shanghai/eip3855_push0/test_push0.py
def test_push0_before_jumpdest(\n    state_test: StateTestFiller,\n    env: Environment,\n    pre: dict,\n    post: dict,\n    tx: Transaction,\n    addr_1: str,\n):\n\"\"\"\n    Jump to a JUMPDEST next to a PUSH0, must succeed.\n    \"\"\"\n    code = Op.PUSH1(4) + Op.JUMP + Op.PUSH0 + Op.JUMPDEST + Op.SSTORE(Op.PUSH0, 1) + Op.STOP\n\n    pre[addr_1] = Account(code=code)\n    post[addr_1] = Account(storage={0x00: 0x01})\n\n    state_test(env=env, pre=pre, post=post, txs=[tx], tag=\"before_jumpdest\")\n
"},{"location":"tests/shanghai/eip3855_push0/test_push0/#tests.shanghai.eip3855_push0.test_push0.test_push0_gas_cost","title":"test_push0_gas_cost(state_test, env, pre, post, tx, addr_1)","text":"

Test PUSH0 gas cost.

Source code in tests/shanghai/eip3855_push0/test_push0.py
def test_push0_gas_cost(\n    state_test: StateTestFiller,\n    env: Environment,\n    pre: dict,\n    post: dict,\n    tx: Transaction,\n    addr_1: str,\n):\n\"\"\"\n    Test PUSH0 gas cost.\n    \"\"\"\n    code = CodeGasMeasure(\n        code=Op.PUSH0,\n        extra_stack_items=1,\n    )\n\n    pre[addr_1] = Account(code=code)\n    post[addr_1] = Account(storage={0x00: 0x02})\n\n    state_test(env=env, pre=pre, post=post, txs=[tx], tag=\"gas_cost\")\n
"},{"location":"tests/shanghai/eip3855_push0/test_push0/index/test_cases/","title":"Test Push0 - Test Cases","text":"

Test cases generated from tests/shanghai/eip3855_push0/test_push0.py

Parametrized test cases generated from the test module tests/shanghai/eip3855_push0/test_push0.py:

test_push0_key_sstore[fork=Shanghai]\ntest_push0_key_sstore[fork=Cancun]\ntest_push0_fill_stack[fork=Shanghai]\ntest_push0_fill_stack[fork=Cancun]\ntest_push0_stack_overflow[fork=Shanghai]\ntest_push0_stack_overflow[fork=Cancun]\ntest_push0_storage_overwrite[fork=Shanghai]\ntest_push0_storage_overwrite[fork=Cancun]\ntest_push0_during_staticcall[fork=Shanghai]\ntest_push0_during_staticcall[fork=Cancun]\ntest_push0_before_jumpdest[fork=Shanghai]\ntest_push0_before_jumpdest[fork=Cancun]\ntest_push0_gas_cost[fork=Shanghai]\ntest_push0_gas_cost[fork=Cancun]\n

This output was extracted from the result of:

fill --collect-only -q --until Cancun tests/shanghai/eip3855_push0/test_push0.py\n
"},{"location":"tests/shanghai/eip3860_initcode/","title":"EIP-3860 Initcode","text":"

Documentation for tests/shanghai/eip3860_initcode.

Generate fixtures for these test cases with:

fill -v tests/shanghai/eip3860_initcode\n
Test EIP-3860: Limit and meter initcode

Tests for EIP-3860: Limit and meter initcode.

"},{"location":"tests/shanghai/eip3860_initcode/test_initcode/","title":"Test Initcode","text":"

Documentation for tests/shanghai/eip3860_initcode/test_initcode.py.

Generate fixtures for these test cases with:

fill -v tests/shanghai/eip3860_initcode/test_initcode.py\n
Test EIP-3860: Limit and meter initcode

Tests for EIP-3860: Limit and meter initcode.

Tests ported from:
  • ethereum/tests/pull/990
  • ethereum/tests/pull/1012
"},{"location":"tests/shanghai/eip3860_initcode/test_initcode/#tests.shanghai.eip3860_initcode.test_initcode.test_contract_creating_tx","title":"test_contract_creating_tx(blockchain_test, initcode)","text":"

Test cases using a contract creating transaction

Test creating a contract using a transaction using an initcode that is on/over the max allowed limit.

Generates a BlockchainTest based on the provided initcode and its length.

Source code in tests/shanghai/eip3860_initcode/test_initcode.py
@pytest.mark.parametrize(\n    \"initcode\",\n    [\n        INITCODE_ZEROS_MAX_LIMIT,\n        INITCODE_ONES_MAX_LIMIT,\n        INITCODE_ZEROS_OVER_LIMIT,\n        INITCODE_ONES_OVER_LIMIT,\n    ],\n    ids=get_initcode_name,\n)\ndef test_contract_creating_tx(blockchain_test: BlockchainTestFiller, initcode: Initcode):\n\"\"\"\n    Test cases using a contract creating transaction\n\n    Test creating a contract using a transaction using an initcode that is\n    on/over the max allowed limit.\n\n    Generates a BlockchainTest based on the provided `initcode` and its\n    length.\n    \"\"\"\n    eip_3860_active = True\n    env = Environment()\n\n    pre = {\n        TestAddress: Account(balance=1000000000000000000000),\n    }\n\n    post: Dict[Any, Any] = {}\n\n    created_contract_address = compute_create_address(\n        address=TestAddress,\n        nonce=0,\n    )\n\n    tx = Transaction(\n        nonce=0,\n        to=None,\n        data=initcode,\n        gas_limit=10000000,\n        gas_price=10,\n    )\n\n    block = Block(txs=[tx])\n\n    if len(initcode.assemble()) > MAX_INITCODE_SIZE and eip_3860_active:\n        # Initcode is above the max size, tx inclusion in the block makes\n        # it invalid.\n        post[created_contract_address] = Account.NONEXISTENT\n        tx.error = \"max initcode size exceeded\"\n        block.exception = \"max initcode size exceeded\"\n    else:\n        # Initcode is at or below the max size, tx inclusion in the block\n        # is ok and the contract is successfully created.\n        post[created_contract_address] = Account(code=Op.STOP)\n\n    blockchain_test(\n        pre=pre,\n        post=post,\n        blocks=[block],\n        genesis_environment=env,\n        tag=f\"{initcode.name}\",\n    )\n
"},{"location":"tests/shanghai/eip3860_initcode/test_initcode/#tests.shanghai.eip3860_initcode.test_initcode.TestContractCreationGasUsage","title":"TestContractCreationGasUsage","text":"

Test EIP-3860 Limit Initcode Gas Usage for a contract creating transaction, using different initcode lengths.

Generates 4 test cases that verify the gas cost behavior of a contract creating transaction:

  1. Test with exact intrinsic gas minus one, contract create fails and tx is invalid.
  2. Test with exact intrinsic gas, contract create fails, but tx is valid.
  3. Test with exact execution gas minus one, contract create fails, but tx is valid.
  4. Test with exact execution gas, contract create succeeds.

Initcode must be within valid EIP-3860 length.

Source code in tests/shanghai/eip3860_initcode/test_initcode.py
@pytest.mark.parametrize(\n    \"initcode\",\n    [\n        INITCODE_ZEROS_MAX_LIMIT,\n        INITCODE_ONES_MAX_LIMIT,\n        EMPTY_INITCODE,\n        SINGLE_BYTE_INITCODE,\n        INITCODE_ZEROS_32_BYTES,\n        INITCODE_ZEROS_33_BYTES,\n        INITCODE_ZEROS_49120_BYTES,\n        INITCODE_ZEROS_49121_BYTES,\n    ],\n    ids=get_initcode_name,\n)\n@pytest.mark.parametrize(\n    \"gas_test_case\",\n    [\n        \"too_little_intrinsic_gas\",\n        \"exact_intrinsic_gas\",\n        \"too_little_execution_gas\",\n        \"exact_execution_gas\",\n    ],\n    ids=lambda x: x,\n)\nclass TestContractCreationGasUsage:\n\"\"\"\n    Test EIP-3860 Limit Initcode Gas Usage for a contract\n    creating transaction, using different initcode lengths.\n\n    Generates 4 test cases that verify the gas cost behavior of a\n    contract creating transaction:\n\n    1. Test with exact intrinsic gas minus one, contract create fails\n        and tx is invalid.\n    2. Test with exact intrinsic gas, contract create fails,\n        but tx is valid.\n    3. Test with exact execution gas minus one, contract create fails,\n        but tx is valid.\n    4. Test with exact execution gas, contract create succeeds.\n\n    Initcode must be within valid EIP-3860 length.\n    \"\"\"\n\n    @pytest.fixture\n    def eip_3860_active(self):  # noqa: D102\n        return True\n\n    @pytest.fixture\n    def exact_intrinsic_gas(self, initcode, eip_3860_active):\n\"\"\"\n        Calculates the intrinsic tx gas cost.\n        \"\"\"\n        return calculate_create_tx_intrinsic_cost(initcode, eip_3860_active)\n\n    @pytest.fixture\n    def exact_execution_gas(self, initcode, eip_3860_active):\n\"\"\"\n        Calculates the total execution gas cost.\n        \"\"\"\n        return calculate_create_tx_execution_cost(\n            initcode,\n            eip_3860_active,\n        )\n\n    @pytest.fixture\n    def created_contract_address(self):\n\"\"\"\n        Calculates the address of the contract deployed via CREATE.\n        \"\"\"\n        return compute_create_address(\n            address=TestAddress,\n            nonce=0,\n        )\n\n    @pytest.fixture\n    def env(self) -> Environment:  # noqa: D102\n        return Environment()\n\n    @pytest.fixture\n    def pre(self) -> Dict[Any, Any]:  # noqa: D102\n        return {\n            TestAddress: Account(balance=1000000000000000000000),\n        }\n\n    @pytest.fixture\n    def tx_error(self, gas_test_case) -> str | None:\n\"\"\"\n        Test that the transaction is invalid if too little intrinsic gas is\n        specified, otherwise the tx succeeds.\n        \"\"\"\n        if gas_test_case == \"too_little_intrinsic_gas\":\n            return \"intrinsic gas too low\"\n        return None\n\n    @pytest.fixture\n    def tx(\n        self,\n        gas_test_case,\n        initcode,\n        tx_error,\n        exact_intrinsic_gas,\n        exact_execution_gas,\n    ) -> Transaction:\n\"\"\"\n        Implement the gas_test_case by setting the gas_limit of the tx\n        appropriately and test whether the tx succeeds or fails with\n        appropriate error.\n        \"\"\"\n        if gas_test_case == \"too_little_intrinsic_gas\":\n            gas_limit = exact_intrinsic_gas - 1\n        elif gas_test_case == \"exact_intrinsic_gas\":\n            gas_limit = exact_intrinsic_gas\n        elif gas_test_case == \"too_little_execution_gas\":\n            gas_limit = exact_execution_gas - 1\n        elif gas_test_case == \"exact_execution_gas\":\n            gas_limit = exact_execution_gas\n        else:\n            pytest.fail(\"Invalid gas test case provided.\")\n\n        return Transaction(\n            nonce=0,\n            to=None,\n            data=initcode,\n            gas_limit=gas_limit,\n            gas_price=10,\n            error=tx_error,\n        )\n\n    @pytest.fixture\n    def block(self, tx, tx_error) -> Block:\n\"\"\"\n        Test that the tx_error is also propagated on the Block for the case of\n        too little intrinsic gas.\n        \"\"\"\n        return Block(txs=[tx], exception=tx_error)\n\n    @pytest.fixture\n    def post(\n        self,\n        gas_test_case,\n        initcode,\n        created_contract_address,\n        exact_intrinsic_gas,\n        exact_execution_gas,\n    ) -> Dict[Any, Any]:\n\"\"\"\n        Test that contract creation fails unless enough execution gas is\n        provided.\n        \"\"\"\n        if gas_test_case == \"exact_intrinsic_gas\" and exact_intrinsic_gas == exact_execution_gas:\n            # Special scenario where the execution of the initcode and\n            # gas cost to deploy are zero\n            return {created_contract_address: Account(code=initcode.deploy_code)}\n        elif gas_test_case == \"exact_execution_gas\":\n            return {created_contract_address: Account(code=initcode.deploy_code)}\n        return {created_contract_address: Account.NONEXISTENT}\n\n    def test_gas_usage(\n        self,\n        blockchain_test: BlockchainTestFiller,\n        gas_test_case: str,\n        initcode: Initcode,\n        exact_intrinsic_gas,\n        exact_execution_gas,\n        env,\n        pre,\n        block,\n        post,\n    ):\n\"\"\"\n        Test transaction and contract creation behavior for different gas\n        limits.\n        \"\"\"\n        if (gas_test_case == \"too_little_execution_gas\") and (\n            exact_execution_gas == exact_intrinsic_gas\n        ):\n            pytest.skip(\n                \"Special case, the execution of the initcode and gas \"\n                \"cost to deploy are zero: Then this test case is \"\n                \"equivalent to that of 'test_exact_intrinsic_gas'.\"\n            )\n\n        blockchain_test(\n            pre=pre,\n            post=post,\n            blocks=[block],\n            genesis_environment=env,\n            tag=f\"{initcode.name}_{gas_test_case}\",\n        )\n
"},{"location":"tests/shanghai/eip3860_initcode/test_initcode/#tests.shanghai.eip3860_initcode.test_initcode.TestContractCreationGasUsage.test_gas_usage","title":"test_gas_usage(blockchain_test, gas_test_case, initcode, exact_intrinsic_gas, exact_execution_gas, env, pre, block, post)","text":"

Test transaction and contract creation behavior for different gas limits.

Source code in tests/shanghai/eip3860_initcode/test_initcode.py
def test_gas_usage(\n    self,\n    blockchain_test: BlockchainTestFiller,\n    gas_test_case: str,\n    initcode: Initcode,\n    exact_intrinsic_gas,\n    exact_execution_gas,\n    env,\n    pre,\n    block,\n    post,\n):\n\"\"\"\n    Test transaction and contract creation behavior for different gas\n    limits.\n    \"\"\"\n    if (gas_test_case == \"too_little_execution_gas\") and (\n        exact_execution_gas == exact_intrinsic_gas\n    ):\n        pytest.skip(\n            \"Special case, the execution of the initcode and gas \"\n            \"cost to deploy are zero: Then this test case is \"\n            \"equivalent to that of 'test_exact_intrinsic_gas'.\"\n        )\n\n    blockchain_test(\n        pre=pre,\n        post=post,\n        blocks=[block],\n        genesis_environment=env,\n        tag=f\"{initcode.name}_{gas_test_case}\",\n    )\n
"},{"location":"tests/shanghai/eip3860_initcode/test_initcode/#tests.shanghai.eip3860_initcode.test_initcode.TestCreateInitcode","title":"TestCreateInitcode","text":"

Test contract creation via the CREATE/CREATE2 opcodes that have an initcode that is on/over the max allowed limit.

Source code in tests/shanghai/eip3860_initcode/test_initcode.py
@pytest.mark.parametrize(\n    \"initcode\",\n    [\n        INITCODE_ZEROS_MAX_LIMIT,\n        INITCODE_ONES_MAX_LIMIT,\n        INITCODE_ZEROS_OVER_LIMIT,\n        INITCODE_ONES_OVER_LIMIT,\n        EMPTY_INITCODE,\n        SINGLE_BYTE_INITCODE,\n        INITCODE_ZEROS_32_BYTES,\n        INITCODE_ZEROS_33_BYTES,\n        INITCODE_ZEROS_49120_BYTES,\n        INITCODE_ZEROS_49121_BYTES,\n    ],\n    ids=get_initcode_name,\n)\n@pytest.mark.parametrize(\"opcode\", [Op.CREATE, Op.CREATE2], ids=get_create_id)\nclass TestCreateInitcode:\n\"\"\"\n    Test contract creation via the CREATE/CREATE2 opcodes that have an initcode\n    that is on/over the max allowed limit.\n    \"\"\"\n\n    @pytest.fixture\n    def create_code(self, opcode: Op, initcode: Initcode):  # noqa: D102\n        if opcode == Op.CREATE:\n            create_call = Op.CREATE(0, 0, Op.CALLDATASIZE)\n        elif opcode == Op.CREATE2:\n            create_call = Op.CREATE2(0, 0, Op.CALLDATASIZE, 0xDEADBEEF)\n        else:\n            raise Exception(\"Invalid opcode specified for test.\")\n        return (\n            Op.CALLDATACOPY(0, 0, Op.CALLDATASIZE)\n            + Op.GAS\n            + create_call\n            + Op.GAS\n            # stack: [Gas 2, Call Result, Gas 1]\n            + Op.SWAP1\n            # stack: [Call Result, Gas 2, Gas 1]\n            + Op.SSTORE(0)\n            # stack: [Gas 2, Gas 1]\n            + Op.SWAP1\n            # stack: [Gas 1, Gas 2]\n            + Op.SUB\n            # stack: [Gas 1 - Gas 2]\n            + Op.SSTORE(1)\n        )\n\n    @pytest.fixture\n    def created_contract_address(self, initcode: Initcode, opcode: Op):  # noqa: D102\n        if opcode == Op.CREATE:\n            return compute_create_address(\n                address=0x100,\n                nonce=1,\n            )\n        if opcode == Op.CREATE2:\n            return compute_create2_address(\n                address=0x100,\n                salt=0xDEADBEEF,\n                initcode=initcode.assemble(),\n            )\n        raise Exception(\"invalid opcode for generator\")\n\n    def test_create_opcode_initcode(\n        self,\n        state_test: StateTestFiller,\n        opcode: Op,\n        initcode: Initcode,\n        create_code: Yul,\n        created_contract_address: str,\n    ):\n\"\"\"\n        Test contract creation via the CREATE/CREATE2 opcodes that have an\n        initcode that is on/over the max allowed limit.\n        \"\"\"\n        eip_3860_active = True\n        env = Environment()\n\n        call_code = Op.CALLDATACOPY(0, 0, Op.CALLDATASIZE)\n        call_code += Op.SSTORE(\n            Op.CALL(5000000, 0x100, 0, 0, Op.CALLDATASIZE, 0, 0),\n            1,\n        )\n\n        pre = {\n            TestAddress: Account(balance=1000000000000000000000),\n            to_address(0x100): Account(\n                code=create_code,\n                nonce=1,\n            ),\n            to_address(0x200): Account(\n                code=call_code,\n                nonce=1,\n            ),\n        }\n\n        post: Dict[Any, Any] = {}\n\n        tx = Transaction(\n            nonce=0,\n            to=to_address(0x200),\n            data=initcode,\n            gas_limit=10000000,\n            gas_price=10,\n        )\n\n        # Calculate the expected gas of the contract creation operation\n        expected_gas_usage = (\n            CREATE_CONTRACT_BASE_GAS\n            + GAS_OPCODE_GAS\n            + (2 * PUSH_DUP_OPCODE_GAS)\n            + CALLDATASIZE_OPCODE_GAS\n        )\n        if opcode == Op.CREATE2:\n            # Extra PUSH operation\n            expected_gas_usage += PUSH_DUP_OPCODE_GAS\n\n        if len(initcode.assemble()) > MAX_INITCODE_SIZE and eip_3860_active:\n            # Call returns 0 as out of gas s[0]==1\n            post[to_address(0x200)] = Account(\n                nonce=1,\n                storage={\n                    0: 1,\n                    1: 0,\n                },\n            )\n\n            post[created_contract_address] = Account.NONEXISTENT\n            post[to_address(0x100)] = Account(\n                nonce=1,\n                storage={\n                    0: 0,\n                    1: 0,\n                },\n            )\n\n        else:\n            # The initcode is only executed if the length check succeeds\n            expected_gas_usage += initcode.execution_gas\n            # The code is only deployed if the length check succeeds\n            expected_gas_usage += initcode.deployment_gas\n\n            if opcode == Op.CREATE2:\n                # CREATE2 hashing cost should only be deducted if the initcode\n                # does not exceed the max length\n                expected_gas_usage += calculate_create2_word_cost(len(initcode.assemble()))\n\n            if eip_3860_active:\n                # Initcode word cost is only deducted if the length check\n                # succeeds\n                expected_gas_usage += calculate_initcode_word_cost(len(initcode.assemble()))\n\n            # Call returns 1 as valid initcode length s[0]==1 && s[1]==1\n            post[to_address(0x200)] = Account(\n                nonce=1,\n                storage={\n                    0: 0,\n                    1: 1,\n                },\n            )\n\n            post[created_contract_address] = Account(code=initcode.deploy_code)\n            post[to_address(0x100)] = Account(\n                nonce=2,\n                storage={\n                    0: created_contract_address,\n                    1: expected_gas_usage,\n                },\n            )\n\n        state_test(\n            env=env,\n            pre=pre,\n            post=post,\n            txs=[tx],\n            tag=f\"{initcode.name}_{opcode}\",\n        )\n
"},{"location":"tests/shanghai/eip3860_initcode/test_initcode/#tests.shanghai.eip3860_initcode.test_initcode.TestCreateInitcode.test_create_opcode_initcode","title":"test_create_opcode_initcode(state_test, opcode, initcode, create_code, created_contract_address)","text":"

Test contract creation via the CREATE/CREATE2 opcodes that have an initcode that is on/over the max allowed limit.

Source code in tests/shanghai/eip3860_initcode/test_initcode.py
def test_create_opcode_initcode(\n    self,\n    state_test: StateTestFiller,\n    opcode: Op,\n    initcode: Initcode,\n    create_code: Yul,\n    created_contract_address: str,\n):\n\"\"\"\n    Test contract creation via the CREATE/CREATE2 opcodes that have an\n    initcode that is on/over the max allowed limit.\n    \"\"\"\n    eip_3860_active = True\n    env = Environment()\n\n    call_code = Op.CALLDATACOPY(0, 0, Op.CALLDATASIZE)\n    call_code += Op.SSTORE(\n        Op.CALL(5000000, 0x100, 0, 0, Op.CALLDATASIZE, 0, 0),\n        1,\n    )\n\n    pre = {\n        TestAddress: Account(balance=1000000000000000000000),\n        to_address(0x100): Account(\n            code=create_code,\n            nonce=1,\n        ),\n        to_address(0x200): Account(\n            code=call_code,\n            nonce=1,\n        ),\n    }\n\n    post: Dict[Any, Any] = {}\n\n    tx = Transaction(\n        nonce=0,\n        to=to_address(0x200),\n        data=initcode,\n        gas_limit=10000000,\n        gas_price=10,\n    )\n\n    # Calculate the expected gas of the contract creation operation\n    expected_gas_usage = (\n        CREATE_CONTRACT_BASE_GAS\n        + GAS_OPCODE_GAS\n        + (2 * PUSH_DUP_OPCODE_GAS)\n        + CALLDATASIZE_OPCODE_GAS\n    )\n    if opcode == Op.CREATE2:\n        # Extra PUSH operation\n        expected_gas_usage += PUSH_DUP_OPCODE_GAS\n\n    if len(initcode.assemble()) > MAX_INITCODE_SIZE and eip_3860_active:\n        # Call returns 0 as out of gas s[0]==1\n        post[to_address(0x200)] = Account(\n            nonce=1,\n            storage={\n                0: 1,\n                1: 0,\n            },\n        )\n\n        post[created_contract_address] = Account.NONEXISTENT\n        post[to_address(0x100)] = Account(\n            nonce=1,\n            storage={\n                0: 0,\n                1: 0,\n            },\n        )\n\n    else:\n        # The initcode is only executed if the length check succeeds\n        expected_gas_usage += initcode.execution_gas\n        # The code is only deployed if the length check succeeds\n        expected_gas_usage += initcode.deployment_gas\n\n        if opcode == Op.CREATE2:\n            # CREATE2 hashing cost should only be deducted if the initcode\n            # does not exceed the max length\n            expected_gas_usage += calculate_create2_word_cost(len(initcode.assemble()))\n\n        if eip_3860_active:\n            # Initcode word cost is only deducted if the length check\n            # succeeds\n            expected_gas_usage += calculate_initcode_word_cost(len(initcode.assemble()))\n\n        # Call returns 1 as valid initcode length s[0]==1 && s[1]==1\n        post[to_address(0x200)] = Account(\n            nonce=1,\n            storage={\n                0: 0,\n                1: 1,\n            },\n        )\n\n        post[created_contract_address] = Account(code=initcode.deploy_code)\n        post[to_address(0x100)] = Account(\n            nonce=2,\n            storage={\n                0: created_contract_address,\n                1: expected_gas_usage,\n            },\n        )\n\n    state_test(\n        env=env,\n        pre=pre,\n        post=post,\n        txs=[tx],\n        tag=f\"{initcode.name}_{opcode}\",\n    )\n
"},{"location":"tests/shanghai/eip3860_initcode/test_initcode/index/test_cases/","title":"Test Initcode - Test Cases","text":"

Test cases generated from tests/shanghai/eip3860_initcode/test_initcode.py

Parametrized test cases generated from the test module tests/shanghai/eip3860_initcode/test_initcode.py:

test_contract_creating_tx[fork=Shanghai-max_size_zeros]\ntest_contract_creating_tx[fork=Shanghai-max_size_ones]\ntest_contract_creating_tx[fork=Shanghai-over_limit_zeros]\ntest_contract_creating_tx[fork=Shanghai-over_limit_ones]\ntest_contract_creating_tx[fork=Cancun-max_size_zeros]\ntest_contract_creating_tx[fork=Cancun-max_size_ones]\ntest_contract_creating_tx[fork=Cancun-over_limit_zeros]\ntest_contract_creating_tx[fork=Cancun-over_limit_ones]\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\n

This output was extracted from the result of:

fill --collect-only -q --until Cancun tests/shanghai/eip3860_initcode/test_initcode.py\n
"},{"location":"tests/shanghai/eip4895_withdrawals/","title":"EIP-4895 Withdrawals","text":"

Documentation for tests/shanghai/eip4895_withdrawals.

Generate fixtures for these test cases with:

fill -v tests/shanghai/eip4895_withdrawals\n
Tests EIP-4895: Beacon chain withdrawals

Test cases for EIP-4895: Beacon chain push withdrawals as operations.

"},{"location":"tests/shanghai/eip4895_withdrawals/test_withdrawals/","title":"Test Withdrawals","text":"

Documentation for tests/shanghai/eip4895_withdrawals/test_withdrawals.py.

Generate fixtures for these test cases with:

fill -v tests/shanghai/eip4895_withdrawals/test_withdrawals.py\n
Tests EIP-4895: Beacon chain withdrawals

Test cases for EIP-4895: Beacon chain push withdrawals as operations.

"},{"location":"tests/shanghai/eip4895_withdrawals/test_withdrawals/#tests.shanghai.eip4895_withdrawals.test_withdrawals.TestUseValueInTx","title":"TestUseValueInTx","text":"

Test that the value from a withdrawal can be used in a transaction:

  1. tx_in_withdrawals_block: Test that the withdrawal value can not be used by a transaction in the same block as the withdrawal.

  2. tx_after_withdrawals_block: Test that the withdrawal value can be used by a transaction in the subsequent block.

Source code in tests/shanghai/eip4895_withdrawals/test_withdrawals.py
@pytest.mark.parametrize(\n    \"test_case\",\n    [\"tx_in_withdrawals_block\", \"tx_after_withdrawals_block\"],\n    ids=lambda x: x,\n)\nclass TestUseValueInTx:\n\"\"\"\n    Test that the value from a withdrawal can be used in a transaction:\n\n    1. `tx_in_withdrawals_block`: Test that the withdrawal value can not be used by a transaction\n        in the same block as the withdrawal.\n\n    2. `tx_after_withdrawals_block`: Test that the withdrawal value can be used by a transaction\n        in the subsequent block.\n    \"\"\"\n\n    @pytest.fixture\n    def tx(self):  # noqa: D102\n        # Transaction sent from the `TestAddress`, which has 0 balance at start\n        return Transaction(\n            nonce=0,\n            gas_price=ONE_GWEI,\n            gas_limit=21000,\n            to=to_address(0x100),\n            data=\"0x\",\n        )\n\n    @pytest.fixture\n    def withdrawal(self, tx: Transaction):  # noqa: D102\n        return Withdrawal(\n            index=0,\n            validator=0,\n            address=TestAddress,\n            amount=tx.gas_limit + 1,\n        )\n\n    @pytest.fixture\n    def blocks(self, tx: Transaction, withdrawal: Withdrawal, test_case):  # noqa: D102\n        if test_case == \"tx_in_withdrawals_block\":\n            return [\n                Block(\n                    txs=[tx.with_error(\"intrinsic gas too low: have 0, want 21000\")],\n                    withdrawals=[\n                        withdrawal,\n                    ],\n                    exception=\"Transaction without funds\",\n                )\n            ]\n        if test_case == \"tx_after_withdrawals_block\":\n            return [\n                Block(\n                    txs=[],\n                    withdrawals=[\n                        withdrawal,\n                    ],\n                ),\n                Block(\n                    txs=[tx],\n                    withdrawals=[],\n                ),\n            ]\n        raise Exception(\"Invalid test case.\")\n\n    @pytest.fixture\n    def post(self, test_case: str) -> Dict:  # noqa: D102\n        if test_case == \"tx_in_withdrawals_block\":\n            return {}\n        if test_case == \"tx_after_withdrawals_block\":\n            return {TestAddress: Account(balance=ONE_GWEI)}\n        raise Exception(\"Invalid test case.\")\n\n    def test_use_value_in_tx(\n        self,\n        blockchain_test: BlockchainTestFiller,\n        post: dict,\n        blocks: List[Block],\n    ):\n\"\"\"\n        Test sending withdrawal value in a transaction.\n        \"\"\"\n        pre = {TestAddress: Account(balance=0)}\n        blockchain_test(pre=pre, post=post, blocks=blocks)\n
"},{"location":"tests/shanghai/eip4895_withdrawals/test_withdrawals/#tests.shanghai.eip4895_withdrawals.test_withdrawals.TestUseValueInTx.test_use_value_in_tx","title":"test_use_value_in_tx(blockchain_test, post, blocks)","text":"

Test sending withdrawal value in a transaction.

Source code in tests/shanghai/eip4895_withdrawals/test_withdrawals.py
def test_use_value_in_tx(\n    self,\n    blockchain_test: BlockchainTestFiller,\n    post: dict,\n    blocks: List[Block],\n):\n\"\"\"\n    Test sending withdrawal value in a transaction.\n    \"\"\"\n    pre = {TestAddress: Account(balance=0)}\n    blockchain_test(pre=pre, post=post, blocks=blocks)\n
"},{"location":"tests/shanghai/eip4895_withdrawals/test_withdrawals/#tests.shanghai.eip4895_withdrawals.test_withdrawals.test_use_value_in_contract","title":"test_use_value_in_contract(blockchain_test)","text":"

Test sending value from contract that has not received a withdrawal

Source code in tests/shanghai/eip4895_withdrawals/test_withdrawals.py
def test_use_value_in_contract(blockchain_test: BlockchainTestFiller):\n\"\"\"\n    Test sending value from contract that has not received a withdrawal\n    \"\"\"\n    SEND_ONE_GWEI = Op.SSTORE(\n        Op.NUMBER,\n        Op.CALL(Op.GAS, 0x200, 1000000000, 0, 0, 0, 0),\n    )\n\n    pre = {\n        TestAddress: Account(balance=1000000000000000000000, nonce=0),\n        to_address(0x100): Account(balance=0, code=SEND_ONE_GWEI),\n        to_address(0x200): Account(balance=0),\n    }\n    tx = Transaction(\n        # Transaction sent from the `TestAddress`, which has 0 balance at start\n        nonce=0,\n        value=0,\n        gas_price=10,\n        gas_limit=100000,\n        to=to_address(0x100),\n        data=\"0x\",\n    )\n    withdrawal = Withdrawal(\n        index=0,\n        validator=0,\n        address=to_address(0x100),\n        amount=1,\n    )\n\n    blocks = [\n        Block(\n            txs=[tx.with_nonce(0)],\n            withdrawals=[withdrawal],\n        ),\n        Block(\n            txs=[tx.with_nonce(1)],  # Same tx again, just increase nonce\n        ),\n    ]\n    post = {\n        to_address(0x100): Account(\n            storage={\n                0x1: 0x0,  # Call fails on the first attempt\n                0x2: 0x1,  # Succeeds on the second attempt\n            }\n        ),\n        to_address(0x200): Account(\n            balance=ONE_GWEI,\n        ),\n    }\n\n    blockchain_test(pre=pre, post=post, blocks=blocks)\n
"},{"location":"tests/shanghai/eip4895_withdrawals/test_withdrawals/#tests.shanghai.eip4895_withdrawals.test_withdrawals.test_balance_within_block","title":"test_balance_within_block(blockchain_test)","text":"

Test Withdrawal balance increase within the same block, inside contract call.

Source code in tests/shanghai/eip4895_withdrawals/test_withdrawals.py
def test_balance_within_block(blockchain_test: BlockchainTestFiller):\n\"\"\"\n    Test Withdrawal balance increase within the same block,\n    inside contract call.\n    \"\"\"\n    SAVE_BALANCE_ON_BLOCK_NUMBER = Op.SSTORE(\n        Op.NUMBER,\n        Op.BALANCE(Op.CALLDATALOAD(0)),\n    )\n    pre = {\n        TestAddress: Account(balance=1000000000000000000000, nonce=0),\n        to_address(0x100): Account(\n            code=SAVE_BALANCE_ON_BLOCK_NUMBER,\n        ),\n        to_address(0x200): Account(\n            balance=ONE_GWEI,\n        ),\n    }\n    blocks = [\n        Block(\n            txs=[\n                Transaction(\n                    nonce=0,\n                    gas_limit=100000,\n                    to=to_address(0x100),\n                    data=to_hash(0x200),\n                )\n            ],\n            withdrawals=[\n                Withdrawal(\n                    index=0,\n                    validator=0,\n                    address=to_address(0x200),\n                    amount=1,\n                )\n            ],\n        ),\n        Block(\n            txs=[\n                Transaction(\n                    nonce=1,\n                    gas_limit=100000,\n                    to=to_address(0x100),\n                    data=to_hash(0x200),\n                )\n            ]\n        ),\n    ]\n\n    post = {\n        to_address(0x100): Account(\n            storage={\n                1: ONE_GWEI,\n                2: 2 * ONE_GWEI,\n            }\n        )\n    }\n\n    blockchain_test(pre=pre, post=post, blocks=blocks)\n
"},{"location":"tests/shanghai/eip4895_withdrawals/test_withdrawals/#tests.shanghai.eip4895_withdrawals.test_withdrawals.TestMultipleWithdrawalsSameAddress","title":"TestMultipleWithdrawalsSameAddress","text":"

Test that multiple withdrawals can be sent to the same address in:

  1. A single block.

  2. Multiple blocks.

Source code in tests/shanghai/eip4895_withdrawals/test_withdrawals.py
@pytest.mark.parametrize(\"test_case\", [\"single_block\", \"multiple_blocks\"])\nclass TestMultipleWithdrawalsSameAddress:\n\"\"\"\n    Test that multiple withdrawals can be sent to the same address in:\n\n    1. A single block.\n\n    2. Multiple blocks.\n    \"\"\"\n\n    ADDRESSES = [\n        to_address(0x0),  # Zero address\n        to_address(0x1),  # Pre-compiles\n        to_address(0x2),\n        to_address(0x3),\n        to_address(0x4),\n        to_address(0x5),\n        to_address(0x6),\n        to_address(0x7),\n        to_address(0x8),\n        to_address(0x9),\n        to_address(2**160 - 1),\n    ]\n\n    @pytest.fixture\n    def blocks(self, test_case: str):  # noqa: D102\n        if test_case == \"single_block\":\n            # Many repeating withdrawals of the same accounts in the same\n            # block.\n            return [\n                Block(\n                    withdrawals=[\n                        Withdrawal(\n                            index=i,\n                            validator=i,\n                            address=self.ADDRESSES[i % len(self.ADDRESSES)],\n                            amount=1,\n                        )\n                        for i in range(len(self.ADDRESSES) * 16)\n                    ],\n                ),\n            ]\n        if test_case == \"multiple_blocks\":\n            # Similar test but now use multiple blocks each with multiple\n            # withdrawals to the same withdrawal address.\n            return [\n                Block(\n                    withdrawals=[\n                        Withdrawal(\n                            index=i * 16 + j,\n                            validator=i,\n                            address=self.ADDRESSES[i],\n                            amount=1,\n                        )\n                        for j in range(16)\n                    ],\n                )\n                for i in range(len(self.ADDRESSES))\n            ]\n        raise Exception(\"Invalid test case.\")\n\n    def test_multiple_withdrawals_same_address(\n        self,\n        blockchain_test: BlockchainTestFiller,\n        test_case: str,\n        blocks: List[Block],\n    ):\n\"\"\"\n        Test Withdrawals can be done to the same address multiple times in\n        the same block.\n        \"\"\"\n        pre = {\n            TestAddress: Account(balance=1000000000000000000000, nonce=0),\n        }\n        for addr in self.ADDRESSES:\n            pre[addr] = Account(\n                # set a storage value unconditionally on call\n                code=Op.SSTORE(Op.NUMBER, 1),\n            )\n\n        # Expected post is the same for both test cases.\n        post = {}\n        for addr in self.ADDRESSES:\n            post[addr] = Account(\n                balance=16 * ONE_GWEI,\n                storage={},\n            )\n\n        blockchain_test(pre=pre, post=post, blocks=blocks, tag=test_case)\n
"},{"location":"tests/shanghai/eip4895_withdrawals/test_withdrawals/#tests.shanghai.eip4895_withdrawals.test_withdrawals.TestMultipleWithdrawalsSameAddress.test_multiple_withdrawals_same_address","title":"test_multiple_withdrawals_same_address(blockchain_test, test_case, blocks)","text":"

Test Withdrawals can be done to the same address multiple times in the same block.

Source code in tests/shanghai/eip4895_withdrawals/test_withdrawals.py
def test_multiple_withdrawals_same_address(\n    self,\n    blockchain_test: BlockchainTestFiller,\n    test_case: str,\n    blocks: List[Block],\n):\n\"\"\"\n    Test Withdrawals can be done to the same address multiple times in\n    the same block.\n    \"\"\"\n    pre = {\n        TestAddress: Account(balance=1000000000000000000000, nonce=0),\n    }\n    for addr in self.ADDRESSES:\n        pre[addr] = Account(\n            # set a storage value unconditionally on call\n            code=Op.SSTORE(Op.NUMBER, 1),\n        )\n\n    # Expected post is the same for both test cases.\n    post = {}\n    for addr in self.ADDRESSES:\n        post[addr] = Account(\n            balance=16 * ONE_GWEI,\n            storage={},\n        )\n\n    blockchain_test(pre=pre, post=post, blocks=blocks, tag=test_case)\n
"},{"location":"tests/shanghai/eip4895_withdrawals/test_withdrawals/#tests.shanghai.eip4895_withdrawals.test_withdrawals.test_many_withdrawals","title":"test_many_withdrawals(blockchain_test)","text":"

Test Withdrawals with a count of N withdrawals in a single block where N is a high number not expected to be seen in mainnet.

Source code in tests/shanghai/eip4895_withdrawals/test_withdrawals.py
def test_many_withdrawals(blockchain_test: BlockchainTestFiller):\n\"\"\"\n    Test Withdrawals with a count of N withdrawals in a single block where\n    N is a high number not expected to be seen in mainnet.\n    \"\"\"\n    N = 400\n    pre = {\n        TestAddress: Account(balance=1000000000000000000000, nonce=0),\n    }\n    withdrawals = []\n    post = {}\n    for i in range(N):\n        addr = to_address(0x100 * i)\n        amount = i * 1\n        pre[addr] = Account(\n            code=Op.SSTORE(Op.NUMBER, 1),\n        )\n        withdrawals.append(\n            Withdrawal(\n                index=i,\n                validator=i,\n                address=addr,\n                amount=amount,\n            )\n        )\n        post[addr] = Account(\n            code=Op.SSTORE(Op.NUMBER, 1),\n            balance=amount * ONE_GWEI,\n            storage={},\n        )\n\n    blocks = [\n        Block(\n            withdrawals=withdrawals,\n        ),\n    ]\n\n    blockchain_test(pre=pre, post=post, blocks=blocks)\n
"},{"location":"tests/shanghai/eip4895_withdrawals/test_withdrawals/#tests.shanghai.eip4895_withdrawals.test_withdrawals.test_self_destructing_account","title":"test_self_destructing_account(blockchain_test)","text":"

Test withdrawals can be done to self-destructed accounts. Account 0x100 self-destructs and sends all its balance to 0x200. Then, a withdrawal is received at 0x100 with 99 wei.

Source code in tests/shanghai/eip4895_withdrawals/test_withdrawals.py
def test_self_destructing_account(blockchain_test: BlockchainTestFiller):\n\"\"\"\n    Test withdrawals can be done to self-destructed accounts.\n    Account `0x100` self-destructs and sends all its balance to `0x200`.\n    Then, a withdrawal is received at `0x100` with 99 wei.\n    \"\"\"\n    pre = {\n        TestAddress: Account(balance=1000000000000000000000, nonce=0),\n        to_address(0x100): Account(\n            code=Op.SELFDESTRUCT(Op.CALLDATALOAD(0)),\n            balance=(100 * ONE_GWEI),\n        ),\n        to_address(0x200): Account(\n            balance=0,\n        ),\n    }\n\n    tx_1 = Transaction(\n        # Transaction sent from the `TestAddress`, that calls a\n        # self-destructing contract.\n        nonce=0,\n        gas_price=10,\n        gas_limit=100000,\n        to=to_address(0x100),\n        data=to_hash(0x200),\n    )\n\n    withdrawal = Withdrawal(\n        index=0,\n        validator=0,\n        address=to_address(0x100),\n        amount=(99),\n    )\n\n    block = Block(\n        txs=[tx_1],\n        withdrawals=[withdrawal],\n    )\n\n    post = {\n        to_address(0x100): Account(\n            code=None,\n            balance=(99 * ONE_GWEI),\n        ),\n        to_address(0x200): Account(\n            code=None,\n            balance=(100 * ONE_GWEI),\n        ),\n    }\n\n    blockchain_test(pre=pre, post=post, blocks=[block])\n
"},{"location":"tests/shanghai/eip4895_withdrawals/test_withdrawals/#tests.shanghai.eip4895_withdrawals.test_withdrawals.test_newly_created_contract","title":"test_newly_created_contract(blockchain_test, include_value_in_tx, request)","text":"

Test Withdrawing to a newly created contract.

Source code in tests/shanghai/eip4895_withdrawals/test_withdrawals.py
@pytest.mark.parametrize(\n    \"include_value_in_tx\",\n    [False, True],\n    ids=[\"without_tx_value\", \"with_tx_value\"],\n)\ndef test_newly_created_contract(\n    blockchain_test: BlockchainTestFiller,\n    include_value_in_tx: bool,\n    request,\n):\n\"\"\"\n    Test Withdrawing to a newly created contract.\n    \"\"\"\n    created_contract = compute_create_address(TestAddress, 0)\n\n    pre = {\n        TestAddress: Account(balance=1000000000000000000000, nonce=0),\n    }\n\n    initcode = Op.RETURN(0, 1)\n\n    tx = Transaction(\n        # Transaction sent from the `TestAddress`, that creates a\n        # new contract.\n        nonce=0,\n        gas_price=10,\n        gas_limit=1000000,\n        to=None,\n        data=initcode,\n    )\n\n    withdrawal = Withdrawal(\n        index=0,\n        validator=0,\n        address=created_contract,\n        amount=1,\n    )\n\n    block = Block(\n        txs=[tx],\n        withdrawals=[withdrawal],\n    )\n\n    post = {\n        created_contract: Account(\n            code=\"0x00\",\n            balance=ONE_GWEI,\n        ),\n    }\n    if include_value_in_tx:\n        tx.value = ONE_GWEI\n        post[created_contract].balance = 2 * ONE_GWEI\n\n    tag = request.node.callspec.id.split(\"-\")[0]  # remove fork; brittle\n    blockchain_test(pre=pre, post=post, blocks=[block], tag=tag)\n
"},{"location":"tests/shanghai/eip4895_withdrawals/test_withdrawals/#tests.shanghai.eip4895_withdrawals.test_withdrawals.test_no_evm_execution","title":"test_no_evm_execution(blockchain_test)","text":"

Test Withdrawals don't trigger EVM execution.

Source code in tests/shanghai/eip4895_withdrawals/test_withdrawals.py
def test_no_evm_execution(blockchain_test: BlockchainTestFiller):\n\"\"\"\n    Test Withdrawals don't trigger EVM execution.\n    \"\"\"\n    pre = {\n        TestAddress: Account(balance=1000000000000000000000, nonce=0),\n        to_address(0x100): Account(\n            code=Op.SSTORE(Op.NUMBER, 1),\n        ),\n        to_address(0x200): Account(\n            code=Op.SSTORE(Op.NUMBER, 1),\n        ),\n        to_address(0x300): Account(\n            code=Op.SSTORE(Op.NUMBER, 1),\n        ),\n        to_address(0x400): Account(\n            code=Op.SSTORE(Op.NUMBER, 1),\n        ),\n    }\n    blocks = [\n        Block(\n            txs=[\n                Transaction(\n                    nonce=0,\n                    gas_limit=100000,\n                    to=to_address(0x300),\n                ),\n                Transaction(\n                    nonce=1,\n                    gas_limit=100000,\n                    to=to_address(0x400),\n                ),\n            ],\n            withdrawals=[\n                Withdrawal(\n                    index=0,\n                    validator=0,\n                    address=to_address(0x100),\n                    amount=1,\n                ),\n                Withdrawal(\n                    index=1,\n                    validator=1,\n                    address=to_address(0x200),\n                    amount=1,\n                ),\n            ],\n        ),\n        Block(\n            txs=[\n                Transaction(\n                    nonce=2,\n                    gas_limit=100000,\n                    to=to_address(0x100),\n                ),\n                Transaction(\n                    nonce=3,\n                    gas_limit=100000,\n                    to=to_address(0x200),\n                ),\n            ],\n            withdrawals=[\n                Withdrawal(\n                    index=0,\n                    validator=0,\n                    address=to_address(0x300),\n                    amount=1,\n                ),\n                Withdrawal(\n                    index=1,\n                    validator=1,\n                    address=to_address(0x400),\n                    amount=1,\n                ),\n            ],\n        ),\n    ]\n\n    post = {\n        to_address(0x100): Account(storage={2: 1}),\n        to_address(0x200): Account(storage={2: 1}),\n        to_address(0x300): Account(storage={1: 1}),\n        to_address(0x400): Account(storage={1: 1}),\n    }\n\n    blockchain_test(pre=pre, post=post, blocks=blocks)\n
"},{"location":"tests/shanghai/eip4895_withdrawals/test_withdrawals/#tests.shanghai.eip4895_withdrawals.test_withdrawals.test_zero_amount","title":"test_zero_amount(blockchain_test, test_case)","text":"

Test withdrawals with zero amount for the following cases, all withdrawals are included in one block:

  1. Two withdrawals of zero amount to two different addresses; one to an untouched account, one to an account with a balance.
  2. As 1., but with an additional withdrawal with positive value.
  3. As 2., but with an additional withdrawal containing the maximum value possible.
  4. As 3., but with order of withdrawals in the block reversed.
Source code in tests/shanghai/eip4895_withdrawals/test_withdrawals.py
@pytest.mark.parametrize(\n    \"test_case\",\n    [case for case in ZeroAmountTestCases],\n    ids=[case.value for case in ZeroAmountTestCases],\n)\ndef test_zero_amount(\n    blockchain_test: BlockchainTestFiller,\n    test_case: ZeroAmountTestCases,\n):\n\"\"\"\n    Test withdrawals with zero amount for the following cases, all withdrawals\n    are included in one block:\n\n    1. Two withdrawals of zero amount to two different addresses; one to an\n       untouched account, one to an account with a balance.\n    2. As 1., but with an additional withdrawal with positive value.\n    3. As 2., but with an additional withdrawal containing the maximum value\n       possible.\n    4. As 3., but with order of withdrawals in the block reversed.\n\n    \"\"\"\n    pre = {\n        TestAddress: Account(balance=1000000000000000000000, nonce=0),\n        to_address(0x200): Account(\n            code=\"0x00\",\n            balance=0,\n        ),\n    }\n\n    all_withdrawals = [\n        # No value, untouched account\n        Withdrawal(\n            index=0,\n            validator=0,\n            address=to_address(0x100),\n            amount=0,\n        ),\n        # No value, touched account\n        Withdrawal(\n            index=0,\n            validator=0,\n            address=to_address(0x200),\n            amount=0,\n        ),\n        # Withdrawal with value\n        Withdrawal(\n            index=1,\n            validator=0,\n            address=to_address(0x300),\n            amount=1,\n        ),\n        # Withdrawal with maximum amount\n        Withdrawal(\n            index=2,\n            validator=0,\n            address=to_address(0x400),\n            amount=2**64 - 1,\n        ),\n    ]\n    all_post = {\n        to_address(0x100): Account.NONEXISTENT,\n        to_address(0x200): Account(code=\"0x00\", balance=0),\n        to_address(0x300): Account(balance=ONE_GWEI),\n        to_address(0x400): Account(balance=(2**64 - 1) * ONE_GWEI),\n    }\n\n    withdrawals: List[Withdrawal] = []\n    post: Mapping[str, Account | object] = {}\n    if test_case == ZeroAmountTestCases.TWO_ZERO:\n        withdrawals = all_withdrawals[0:2]\n        post = {\n            account: all_post[account]\n            for account in post\n            if account in [to_address(0x100), to_address(0x200)]\n        }\n    elif test_case == ZeroAmountTestCases.THREE_ONE_WITH_VALUE:\n        withdrawals = all_withdrawals[0:3]\n        post = {\n            account: all_post[account]\n            for account in post\n            if account\n            in [\n                to_address(0x100),\n                to_address(0x200),\n                to_address(0x300),\n            ]\n        }\n    elif test_case == ZeroAmountTestCases.FOUR_ONE_WITH_MAX:\n        withdrawals = all_withdrawals\n        post = all_post\n    elif test_case == ZeroAmountTestCases.FOUR_ONE_WITH_MAX_REVERSED:\n        withdrawals = all_withdrawals\n        withdrawals.reverse()\n        set_withdrawal_index(withdrawals)\n        post = all_post\n    else:\n        raise Exception(\"Unknown test case.\")\n\n    blockchain_test(\n        pre=pre,\n        # TODO: Fix in BlockchainTest? post: Mapping[str, Account | object]\n        # to allow for Account.NONEXISTENT\n        post=post,  # type: ignore\n        blocks=[Block(withdrawals=withdrawals)],\n        tag=test_case.value,\n    )\n
"},{"location":"tests/shanghai/eip4895_withdrawals/test_withdrawals/#tests.shanghai.eip4895_withdrawals.test_withdrawals.test_large_amount","title":"test_large_amount(blockchain_test)","text":"

Test Withdrawals that have a large gwei amount, so that (gwei * 1e9) could overflow uint64 but not uint256.

Source code in tests/shanghai/eip4895_withdrawals/test_withdrawals.py
def test_large_amount(blockchain_test: BlockchainTestFiller):\n\"\"\"\n    Test Withdrawals that have a large gwei amount, so that (gwei * 1e9)\n    could overflow uint64 but not uint256.\n    \"\"\"\n    pre = {\n        TestAddress: Account(balance=1000000000000000000000, nonce=0),\n    }\n\n    withdrawals: List[Withdrawal] = []\n    amounts: List[int] = [\n        (2**35),\n        (2**64) - 1,\n        (2**63) + 1,\n        (2**63),\n        (2**63) - 1,\n    ]\n\n    post = {}\n\n    for i, amount in enumerate(amounts):\n        addr = to_address(0x100 * (i + 1))\n        withdrawals.append(\n            Withdrawal(\n                index=i,\n                validator=i,\n                address=addr,\n                amount=amount,\n            )\n        )\n        post[addr] = Account(balance=(amount * ONE_GWEI))\n\n    blocks = [\n        Block(\n            withdrawals=withdrawals,\n        )\n    ]\n    blockchain_test(pre=pre, post=post, blocks=blocks)\n
"},{"location":"tests/shanghai/eip4895_withdrawals/test_withdrawals/index/test_cases/","title":"Test Withdrawals - Test Cases","text":"

Test cases generated from tests/shanghai/eip4895_withdrawals/test_withdrawals.py

Parametrized test cases generated from the test module tests/shanghai/eip4895_withdrawals/test_withdrawals.py:

TestUseValueInTx\nTestUseValueInTx\nTestUseValueInTx\nTestUseValueInTx\ntest_use_value_in_contract[fork=Shanghai]\ntest_use_value_in_contract[fork=Cancun]\ntest_balance_within_block[fork=Shanghai]\ntest_balance_within_block[fork=Cancun]\nTestMultipleWithdrawalsSameAddress\nTestMultipleWithdrawalsSameAddress\nTestMultipleWithdrawalsSameAddress\nTestMultipleWithdrawalsSameAddress\ntest_many_withdrawals[fork=Shanghai]\ntest_many_withdrawals[fork=Cancun]\ntest_self_destructing_account[fork=Shanghai]\ntest_self_destructing_account[fork=Cancun]\ntest_newly_created_contract[fork=Shanghai-without_tx_value]\ntest_newly_created_contract[fork=Shanghai-with_tx_value]\ntest_newly_created_contract[fork=Cancun-without_tx_value]\ntest_newly_created_contract[fork=Cancun-with_tx_value]\ntest_no_evm_execution[fork=Shanghai]\ntest_no_evm_execution[fork=Cancun]\ntest_zero_amount[fork=Shanghai-two_withdrawals_no_value]\ntest_zero_amount[fork=Shanghai-three_withdrawals_one_with_value]\ntest_zero_amount[fork=Shanghai-four_withdrawals_one_with_value_one_with_max]\ntest_zero_amount[fork=Shanghai-four_withdrawals_one_with_value_one_with_max_reversed_order]\ntest_zero_amount[fork=Cancun-two_withdrawals_no_value]\ntest_zero_amount[fork=Cancun-three_withdrawals_one_with_value]\ntest_zero_amount[fork=Cancun-four_withdrawals_one_with_value_one_with_max]\ntest_zero_amount[fork=Cancun-four_withdrawals_one_with_value_one_with_max_reversed_order]\ntest_large_amount[fork=Shanghai]\ntest_large_amount[fork=Cancun]\n

This output was extracted from the result of:

fill --collect-only -q --until Cancun tests/shanghai/eip4895_withdrawals/test_withdrawals.py\n
"},{"location":"tutorials/blockchain/","title":"Blockchain Tests","text":"

This tutorial teaches you to create a blockchain execution specification test. These tests verify that a blockchain, starting from a defined pre-state, will process given blocks and arrive at a defined post-state.

"},{"location":"tutorials/blockchain/#pre-requisites","title":"Pre-requisites","text":"

Before proceeding with this tutorial, it is assumed that you have prior knowledge and experience with the following:

  • Set up and run an execution specification test as outlined in the quick start guide.
  • Understand how to read a blockchain test.
  • Know the basics of Yul, which is an EVM assembly language.
  • Familiarity with Python.
  • Understand how to write an execution spec state transition test.
"},{"location":"tutorials/blockchain/#example-tests","title":"Example Tests","text":"

In this tutorial we will go over [test_block_number] in test_block_example.py(https://github.com/ethereum/execution-spec-tests/tree/main/tests/example/test_block_example.py#L19).

It is assumed you have already gone through the state transition test tutorial. Only new concepts will be discussed.

"},{"location":"tutorials/blockchain/#smart-contract","title":"Smart Contract","text":"

A smart contract is defined that is called by each transaction in the test. It stores a pointer to storage at storage[0]. When it is called storage cell 0 gets the current block number, and the pointer is incremented to the next value.

contract_addr: Account(\n    balance=1000000000000000000000,\n    code=Yul(\n\"\"\"\n        {\n            let next_slot := sload(0)\n            sstore(next_slot, number())\n            sstore(0, add(next_slot, 1))\n        }\n        \"\"\"\n    ),\n    storage={\n        0x00: 0x01,\n    },\n),\n
"},{"location":"tutorials/blockchain/#transaction-generator","title":"Transaction Generator","text":"

The transactions used in this test are nearly identical. Their only different is the nonce value which needs to be incremented.

def tx_generator():\n    nonce = 0  # Initial value\n    while True:\n        tx = Transaction(\n            ty=0x0,\n            chain_id=0x0,\n            nonce=nonce,\n            to=contractAddr,\n            gas_limit=500000,\n            gas_price=10,\n        )\n        nonce = nonce + 1\n        yield tx\n\ntx_generator = tx_generator()\n

This looks like an infinite loop but it isn't because this is a generator function. When generator encounters the yield keyword it returns the value and stops execution, keeping a copy of all the local variables, until it is called again. Hence infinite loops inside a generator are not a problem as long as they include yield. This code section is responsible for creating the Transaction object and incrementing the nonce.

Every time the function tx_generator() is called, it returns a new generator with a nonce of zero. To increment the nonce we need to use the same generator. We assign this generator to tx_generator.

"},{"location":"tutorials/blockchain/#blocks","title":"Blocks","text":"

Each integer in the tx_per_block array is the number of transactions in a block. The genesis block is block 0 (no transactions). It follows that we have 2 transactions in block 1, 0 in block two, 4 in block 3, ..., and 50 in block 9.

tx_per_block = [2, 0, 4, 8, 0, 0, 20, 1, 50]\n

The code section that creates the blocks is a bit complex in this test. For some simpler definitions of Block creation you can browse tests within test_withdrawals.py.

blocks = map(\n    lambda len: Block(\n        txs=list(map(lambda x: next(tx_generator), range(len)))\n    ),\n    tx_per_block,\n)\n

We use lambda notation to specify short functions. In this case, the function doesn't actually care about its input, it just returns the next transaction from the generator.

lambda x: next(tx_generator)\n

Python uses range(n) to create a list of numbers from 0 to n-1. Among other things, it's a simple way to create a list of n values.

range(len)\n

The map function runs the function (the first parameter) on every element of the list (the second parameter). Putting together what we know, it means that it runs next(tx_generator) len times, giving us len transactions. We then use list to turn the transactions into a list that we can provide as the txs parameter to the Block constructor.

list(map(lambda x: next(tx_generator), range(len)))\n

The outer lambda function takes an integer, len, and creates a Block object with len transactions. This function is then run on every value of tx_per_block to generate the blocks.

blocks = map(\n    lambda len: Block(\n        txs=list of len transactions\n    ),\n    tx_per_block,\n)\n

For example, if we had tx_per_block = [0,2,4], we'd get this result:

blocks = [\n    Blocks(txs=[]),\n    Blocks(txs=[next(tx_generator), next(tx_generator)]),\n    Blocks(txs=[next(tx_generator), next(tx_generator), next(tx_generator), next(tx_generator)])        \n]\n
"},{"location":"tutorials/blockchain/#post-state","title":"Post State","text":"

Recall that storage slot 0 retains the value of the next slot that the block number is written into. It starts at one and is incremented after each transaction. Hence it's the total number of transactions plus 1.

storage = {0: sum(tx_per_block) + 1}\n

For every block and transaction within the block, we write the block number and increment the next slot number in storage slot 0. As Python lists are 0 indexed, we must increment the block number by 1.

next_slot = 1\nfor blocknum in range(len(tx_per_block)):\n    for _ in range(tx_per_block[blocknum]):\n        storage[next_slot] = blocknum + 1\n        next_slot = next_slot + 1\n

Now that the expeced storage values are calculated, the post state can be defined and yielded within the BlockchainTest, synonymous to the state test example.

post = {contract_addr: Account(storage=storage)}\n\nyield BlockchainTest(\n    genesis_environment=env,\n    pre=pre,\n    blocks=blocks,\n    post=post,\n)\n

Note that because of the yield we could have multiple tests under the same name.

"},{"location":"tutorials/blockchain/#conclusion","title":"Conclusion","text":"

At this point you should be able to write blockchain tests.

"},{"location":"tutorials/state_transition/","title":"State Transition Tests","text":"

This tutorial teaches you to create a state transition execution specification test. These tests verify that a blockchain, starting from a defined pre-state, will reach a specified post-state after executing a set of specific transactions.

"},{"location":"tutorials/state_transition/#pre-requisites","title":"Pre-requisites","text":"

Before proceeding with this tutorial, it is assumed that you have prior knowledge and experience with the following:

  • Set up and run an execution specification test as outlined in the quick start guide.
  • Understand how to read a static state transition test.
  • Know the basics of Yul, which is an EVM assembly language.
  • Familiarity with Python.
"},{"location":"tutorials/state_transition/#example-tests","title":"Example Tests","text":"

The most effective method of learning how to write tests is to study a couple of straightforward examples. In this tutorial we will go over the Yul state test.

"},{"location":"tutorials/state_transition/#yul-test","title":"Yul Test","text":"

You can find the source code for the Yul test in tests/homestead/yul/test_yul_example.py. It is the spec test equivalent of this static test.

Lets examine each section.

\"\"\"\nTest Yul Source Code Examples\n\"\"\"\n

In Python, multi-line strings are denoted using \"\"\". As a convention, a file's purpose is often described in the opening string of the file.

from ethereum_test_forks import Fork\nfrom ethereum_test_tools import (\n    Account,\n    Environment,\n    StateTestFiller,\n    TestAddress,\n    Transaction,\n    Yul,\n)\n

In this snippet the required constants, types and helper functions are imported from ethereum_test_tools and ethereum_test_forks. We will go over these as we come across them.

@pytest.mark.valid_from(\"Berlin\")\n

In Python this kind of definition is called a decorator. It modifies the action of the function after it. In this case, the decorator is a custom pytest fixture defined by the execution-specs-test framework that specifies that the test is valid for the Berlin fork and all forks after it. The framework will then execute this test case for all forks in the fork range specified by the command-line arguments.

Executing the test

To execute this test for all the specified forks, we can specify pytest's -k flag that filters test cases by keyword expression:

fill -k test_yul\n
and to execute it for a specific fork range, we can provide the --from and --until command-line arguments:
fill -k test_yul --from London --until Merge\n

def test_yul(state_test: StateTestFiller, fork: Fork):\n\"\"\"\n    Test YUL compiled bytecode.\n    \"\"\"\n

This is the format of a Python function. It starts with def <function name>(<parameters>):, and then has indented code for the function. The function definition ends when there is a line that is no longer indented. As with files, by convention functions start with a string that explains what the function does.

The state_test function argument

This test defines a state test and, as such, must include the state_test in its function arguments. This is a callable object (actually a wrapper class to the StateTest); we will see how it is called later.

    env = Environment()\n

This line specifies that env is an Environment object, and that we just use the default parameters. If necessary we can modify the environment to have different block gas limits, block numbers, etc. In most tests the defaults are good enough.

For more information, see the static test documentation.

"},{"location":"tutorials/state_transition/#pre-state","title":"Pre State","text":"
    pre = {\n

Here we define the pre-state section, the one that tells us what is on the \"blockchain\" before the test. It is a dictionary, which is the Python term for an associative array.

        \"0x1000000000000000000000000000000000000000\": Account(\n

The keys of the dictionary are addresses (as strings), and the values are Account objects. You can read more about address fields in the static test documentation.

            balance=0x0BA1A9CE0BA1A9CE,\n

This field is the balance: the amount of Wei that the account has. It usually doesn't matter what its value is in the case of state test contracts.

            code=Yul(\n

Here we define the Yul code for the contract. It is defined as a multi-line string and starts and ends with curly braces ({ <yul> }).

When running the test filler fill, the solidity compiler solc will automatically translate the Yul to EVM opcode at runtime.

Note

Currently Yul and direct EVM opcode are supported in execution spec tests. LLL and Solidity may be supported in the future.

                \"\"\"\n                {\n                    function f(a, b) -> c {\n                        c := add(a, b)\n                    }\n                    sstore(0, f(1, 2))\n                    return(0, 32)\n                }\n                \"\"\"\n            ),\n        ),\n

Within this example test Yul code we have a function definition, and inside it we are using the Yul add instruction. When compiled with solc it translates the instruction directly to theADD opcode. For further Yul instructions see here. Notice that function is utilised with the Yul sstore instruction, which stores the result of add(1, 2) to the storage address 0x00.

Generally for execution spec tests the sstore instruction acts as a high-level assertion method to check pre to post-state changes. The test filler achieves this by verifying that the correct value is held within post-state storage, hence we can validate that the Yul code has run successfully.

        TestAddress: Account(balance=0x0BA1A9CE0BA1A9CE),\n    }\n

TestAddress is an address for which the test filler has the private key. This means that the test runner can issue a transaction as that contract. Of course, this address also needs a balance to be able to issue transactions.

"},{"location":"tutorials/state_transition/#transactions","title":"Transactions","text":"
    tx = Transaction(\n        ty=0x0,\n        chain_id=0x0,\n        nonce=0,\n        to=\"0x1000000000000000000000000000000000000000\",\n        gas_limit=500000,\n        gas_price=10,\n        protected=False,\n    )\n

With the pre-state specified, we can add a description for the Transaction. For more information, see the static test documentation

"},{"location":"tutorials/state_transition/#post-state","title":"Post State","text":"
    post = {\n        \"0x1000000000000000000000000000000000000000\": Account(\n            storage={\n                0x00: 0x03,\n            },\n        ),\n    }\n

This is the post-state which is equivalent to expect in static tests, but without the indexes. It is similar to the pre-state, except that we do not need to specify everything, only those accounts and fields we wish to test.

In this case, we look at the storage of the contract we called and add to it what we expect to see. In this example storage cell 0x00 should be 0x03 as in the pre-state we essentially stored the result of the Yul instruction add(1, 2).

"},{"location":"tutorials/state_transition/#state-test","title":"State Test","text":"
    state_test(env=env, pre=pre, post=post, txs=[tx])\n

This line calls the wrapper to the StateTest object that provides all the objects required (for example, the fork parameter) in order to fill the test, generate the test fixtures and write them to file (by default, ./fixtures/example/yul_example/test_yul.json).

"},{"location":"tutorials/state_transition/#conclusion","title":"Conclusion","text":"

At this point you should be able to state transition tests within a single block.

"},{"location":"tutorials/state_transition_bad_opcode/","title":"State transition bad opcode","text":""},{"location":"tutorials/state_transition_bad_opcode/#bad-opcode-test","title":"Bad Opcode Test","text":"

The source code for this test is here. We will only go over the parts that are new.

We use Python string templates, so we need to import that library.

from string import Template\n

In this test we need a couple of addresses, so we create them here. Python lets us specify <string>*<number> when we need a string repeated multiple times, which makes for more readable code than 0x00...000C0DE.

    code_addr = \"0x\" + \"0\"*(40-4) + \"C0DE\"\n    goat_addr = \"0x\" + \"0\"*(40-4) + \"60A7\"\n

We create env and tx first because they are constant. This function will yield multiple tests, but always with the same env and tx values.

    env = Environment()\n\n    tx = Transaction(\n           .\n           .\n           .\n        )\n

Here we create two post states. We will use whichever one is appropriate to the test we create.

    post_valid = {\n       code_addr: Account(\n         storage={0x00: 1},\n       ),\n    }\n\n    post_invalid = {\n       code_addr: Account(\n         storage={0x00: 0},\n       ),\n    }\n

Here we define a function (opc_valid) inside another function. Python supports this, and it has two advantages:

  • Avoid namespace pollution by restricting the function to where it is needed.
  • Functions defined inside other functions can use the parameters and local variables of those functions. In this case, we need to use fork.
    # Check if an Opcode is valid\n    def opc_valid(opc):\n\"\"\"\n        Return whether opc will be evaluated as valid by the test or not.\n        Note that some opcodes are evaluated as invalid because the way they act\n        \"\"\"\n

This is the syntax for Python comments, # <rest of the line>.

        # PUSH0 is only valid Shanghai and later\n

Opcode 0x5F (PUSH0) is only valid starting with the Shangai fork. We don't know what will be the fork names after Shanghai, so it is easiest to specify that prior to Shanghai it is invalid. We don't need to worry about forks prior to London because the decorator for this test says it is only valid from London.

        if fork in {\"london\", \"merge\"} and opc==0x5F:\n

Python has a set data structure. We use this structure when the order of the values are irrelevant, and we just want to be able to check if something is a member or not.

Note that if statements are also followed by a colon (:) and the code inside them indented. That is the general Python syntax.

            return False\n

Boolean values in Python are either True or False.

This test works by running an opcode and then does a SSTORE. Opcodes that terminate execution, such as STOP and RETURN also cause the SSTORE not to happen, so they must be treated as invalid. The same is true for JUMP.

        # Valid opcodes, but they are terminal, and so cause\n        # the SSTORE not to happen\n        if opc in {0x00, 0xF3, 0xFD, 0xFF}:\n            return False\n\n\n        # Jumps. If you jump to a random location, you skip the SSTORE\n        if opc in {0x56}:\n            return False\n

Next we return True for supported opcodes.

        # Opcodes that aren't part of a range\n        # 0x20 - SHA3\n        # 0xFA - STATICCALL\n        if opc in {0x20, 0xFA}:\n            return True\n

In Python, as in math, you can use a < b < c for a < b and b < c.

        # Arithmetic opcodes\n        if 0x01 <= opc <= 0x0b:\n            return True\n\n        .\n        .\n        .\n

The last part the function returns False. If we got here, then this is not a valid opcode.

        return False\n        # End of opc_valid\n

As this is the end of the function, the next code line is unindented (compared to the function definition code).

This is a for loop. For loops iterate over a sequnce, and the range function, in this case, gives us the range 0..255. As with functions and if statements, the for loop has a colon and includes the indented code.

    # For every possible opcode\n    for opc in range(256):\n

We have two post states. One, post_valid, has the value of 1 in storage location 0. The other, post_invalid has the value of 0 in storage location 0. But SELFDESTRUCT destroys the contract so there is no longer an account at that address. Neither is valid, so we just skip that test case.

        # We can't check SELFDESTRUCT using this technique\n        if opc in {0xFF}:\n           continue\n

We need the opcode in hexadecimal. The function hex gives us the hexadecimal number in hex. However, it also gives us a 0x prefix, which we don't want, so we use a slice to remove the first two characters.

        opc_hex = hex(opc)[2:]\n

We need opc_hex to be two characters. If the length is only one, prepend a zero.

        if len(opc_hex) == 1:\n          opc_hex = \"0\" + opc_hex\n

This is a Template string. This means we'll be able to substitute template variables (${<var name>}) with values to produce the actual code.

        yul_code = Template(\"\"\"\n        {\n

We start with a call 0x00...0060A7 (a.k.a. goat_addr) so we'll have some return data. Otherwise, RETURNDATACOPY will fail and appear like it is not an opcode.

           pop(call(gas(), 0x60A7, 0, 0, 0, 0, 0))\n\n           // fails on opcodes with >20 inputs\n           // (currently dup16, at 17 inputs, is the\n           // one that goes deepest)\n           //\n           // Follow with 32 NOPs (0x5B) to handle PUSH, which has an immediate\n           // operand\n

Opcodes can have two types of operands:

  • Immediate operands, which are part of the bytecode. For example, 6001 is PUSH1 with the value 0x01.
  • Implied operands (a.k.a. stack operands), which come from the stack.

This verbatim code provides both operand types. The code, ${opcode}${nop32} is the opcode we are testing, followed by 32 copies of 0x5B. When 0x5B is not used as an operand, it is JUMPDEST and does nothing.

           verbatim_20i_0o(hex\"${opcode}${nop32}\",\n

The opcode string is followed by the input parameters (in this case, twenty of them). These can be Yul expressions, but for the sake of simplicity here we just use constant values.

              0x00, 0x00, 0x00, 0xFF, 0xFF,\n              0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\n              0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\n              0xFF, 0xFF, 0xFF, 0xFF, 0xFF)\n

If the opcode terminates the smart contract execution (as invalid opcodes do), we don't get here. If we do get here, write to storage cell 0x00 to record that fact.

Note the syntax let <var> := <value>. This is how you specify variables in Yul.

           // We only get here is the opcode is legit (and it doesn't terminate\n           // execution like STOP and RETURN)\n           let zero := 0\n           let one := 1\n           sstore(zero, one)\n        }\n

Replace ${opcode} with the one byte hex code, and ${nop32} with 32 copies of 5b (for NOP).

        \"\"\").substitute(opcode=opc_hex, nop32=\"5B\"*32)\n        pre = {\n           TestAddress: Account(balance=0x0BA1A9CE0BA1A9CE),\n           codeAddr: Account(\n        balance=0,\n        nonce=1,\n        code=Yul(yul_code)\n           ),\n

This is the account for 0x00..0060A7. It just returns data (all zeros).

           goat_addr: Account(\n                balance=0,\n                nonce=1,\n                code=Yul(\"{ return(0, 0x100) }\"),\n           )\n        }\n

Every time the for loop gets here, it yields a separate test. Over the entire for loop, it yields 255 different tests.

    yield StateTest(\n        env=env, \n        pre=pre, \n        txs=[tx],\n        post=(post_valid if opc_valid(opc) else post_invalid),\n    )\n

The Python format for the ternary operation is a bit different from C-like languages. In C like languages the syntax is <condition> ? <yes value> : <no value>. In Python it is <yes value> if <condition> else <no value>.

"},{"location":"writing_tests/","title":"Writing Tests","text":"

The best way to get started is to use one of the existing test modules for inspiration. A good simple example is tests.berlin.eip2930_access_list.test_acl.test_access_list.

Please check that your code adheres to the repo's Coding Standards and read the other pages in this section for more background and an explanation of how to implement state transition and blockchain tests.

"},{"location":"writing_tests/adding_a_new_test/","title":"Adding a New Test","text":"

All test cases are located underneath the tests directory, which are then organized by fork. Each fork contains sub-directories containing test sub-categories.

\ud83d\udcc1 execution-test-specs/\n\u251c\u2500\u2574\ud83d\udcc1 tests/\n|   \u251c\u2500\u2500 \ud83d\udcc4 __init__.py\n\u2502   \u251c\u2500\u2500 \ud83d\udcc1 cancun/\n|   |    \u251c\u2500\u2500 \ud83d\udcc4 __init__.py\n\u2502   |    \u2514\u2500\u2500 \ud83d\udcc1 eip4844_blobs/\n|   |        \u251c\u2500\u2500 \ud83d\udcc4 __init__.py\n|   |        \u251c\u2500\u2500 \ud83d\udcc4 test_blobhash_opcode.py\n|   |        \u251c\u2500\u2500 \ud83d\udcc4 test_excess_data_gas.py\n|   |        \u2514\u2500\u2500 \ud83d\udcc4 ...\n|   \u251c\u2500\u2500 \ud83d\udcc1 shanghai\n|   |    \u251c\u2500\u2500 \ud83d\udcc1 eip3651_warm_coinbase\n|   |    |   \u251c\u2500\u2500 \ud83d\udcc4 __init__.py\n|   |    |   \u2514\u2500\u2500 \ud83d\udcc4 test_warm_coinbase.py\n|   |    \u251c\u2500\u2500 \ud83d\udcc1 eip3855_push0\n|   |    |   \u251c\u2500\u2500 \ud83d\udcc4 __init__.py\n|   |    |   \u2514\u2500\u2500 \ud83d\udcc4 test_push0.py\n|   |    \u251c\u2500\u2500 \ud83d\udcc1...\n|   |    ...\n\u2502   \u2514\u2500\u2500 \ud83d\udcc1 ...\n

Each category/sub-directory may have multiple Python test modules (*.py) which in turn may contain many test functions. The test functions themselves are always parametrized by fork (by the framework).

A new test can be added by either:

  • Adding a new test_ python function to an existing file in any of the existing category subdirectories within tests.
  • Creating a new source file in an existing category, and populating it with the new test function(s).
  • Creating an entirely new category by adding a subdirectory in tests with the appropriate source files and test functions.
"},{"location":"writing_tests/code_standards/","title":"Code Standards","text":"

The Python code in the tests subdirectory ./tests must fulfill the following checks:

Command Explanation 1 fname8 tests Spell check passes using the ./whitelist.txt dictionary file. 2 isort tests --check --diff Python imports ordered and arranged according to isort's standards. 3 black tests --check --diff Python source must be black-formatted. 4 flake8 tests Python lint checked. 5 mypy tests Objects that provide typehints pass type-checking via mypy. 6 fill All tests tests must execute correctly. 7 mkdocs build --strict Documentation generated without warnings.

While this seems like a long list, a correctly configured editor (see VS Code Setup) essentially assures:

  1. Points 2 and 3 are automatically covered.
  2. Points 1, 4 & 5 are mostly covered. Additionally, if you skip type hints, they won't be checked; we can help you add these in the PR.

These checks must pass in order for the execution-spec-tests Github Actions to pass upon pushing to remote.

Running the checks with tox

All these checks can be executed locally in a single command, tox, see Verifying Changes.

If you need help, get in touch!

"},{"location":"writing_tests/reference_specification/","title":"Referencing an EIP Spec Version","text":"

An Ethereum Improvement Proposal (ethereum/EIPs) and its SHA digest can be directly referenced within a python test module in order to check whether the test implementation could be out-dated. The test framework automatically generates tests for every module that defines a spec version. If the spec is out-of-date because the SHA of the specified file in the remote repo changes, the corresponding test_eip_spec_version() test fails.

<-snip->

The SHA value is the output from git's hash-object command, for example:

git clone git@github.com:ethereum/EIPs\ngit hash-object EIPS/EIPS/eip-3651.md\n# output: d94c694c6f12291bb6626669c3e8587eef3adff1\n
and can be retrieved from the remote repo via the Github API on the command-line as following:
sudo apt install jq\ncurl -s -H \"Accept: application/vnd.github.v3+json\" \\\nhttps://api.github.com/repos/ethereum/EIPs/contents/EIPS/eip-3651.md |\\\njq -r '.sha'\n# output: d94c694c6f12291bb6626669c3e8587eef3adff1\n

"},{"location":"writing_tests/reference_specification/#how-to-add-a-spec-version-check","title":"How to Add a Spec Version Check","text":"

This check accomplished by adding the following two global variables anywhere in the Python source file:

Variable Name Explanation REFERENCE_SPEC_GIT_PATH The relative path of the EIP markdown file in the ethereum/EIPs repository, e.g. \"EIPS/eip-1234.md\" REFERENCE_SPEC_VERSION The SHA hash of the latest version of the file retrieved from the Github API:https://api.github.com/repos/ethereum/EIPs/contents/EIPS/eip-<EIP Number>.md"},{"location":"writing_tests/reference_specification/#example","title":"Example","text":"

Here is an example from ./tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase.py:

REFERENCE_SPEC_GIT_PATH = \"EIPS/eip-3651.md\"\nREFERENCE_SPEC_VERSION = \"d94c694c6f12291bb6626669c3e8587eef3adff1\"\n

The SHA digest was retrieved from here.

"},{"location":"writing_tests/types_of_tests/","title":"Types of tests","text":"

There are currently two types of tests that can be produced by a test spec:

  1. State Tests
  2. Blockchain Tests
"},{"location":"writing_tests/types_of_tests/#state-tests","title":"State Tests","text":"

State tests span a single block and, ideally, a single transaction. For example:

  • Test a single opcode behavior.
  • Verify opcode gas costs.
  • Test interactions between multiple smart contracts.
  • Test creation of smart contracts.
"},{"location":"writing_tests/types_of_tests/#blockchain-tests","title":"Blockchain Tests","text":"

Blockchain tests span multiple blocks which may or may not contain transactions and mainly focus on the block to block effects to the Ethereum state. For example:

  • Verify system-level operations such as coinbase balance updates or withdrawals.
  • Verify fork transitions.
  • Verify blocks with invalid transactions/properties are rejected.
"},{"location":"writing_tests/types_of_tests/#fork-transition-tests","title":"Fork Transition Tests","text":"

There is a special type of blockchain test that is used to test a fork transition. It's not executed for all possible forks, rather it targets exactly the blocks at the point of transition from one evm implementation to the next. This type of test must be marked with the valid_at_transition_to marker, for example:

@pytest.mark.valid_at_transition_to(\"Cancun\")\ndef test_blob_type_tx_pre_fork(\n    blockchain_test: BlockchainTestFiller,\n    pre: Dict,\n    env: Environment,\n    blocks: List[Block],\n):\n\"\"\"\n    Reject blocks with blobs before blobs fork\n    \"\"\"\n
"},{"location":"writing_tests/verifying_changes/","title":"Verifying Changes","text":"

The tox tool can be used to lint, type check, test and verify that documentation is correctly generated. The tox tool can be executed locally to check that local changes won't cause Github Actions Checks to fail.

There are two tox environments available, one for the test cases (tests) and one for the framework and libraries (py3).

Tox Virtual Environment

The checks performed by tox are sandboxed in their own virtual environments (which are created automatically in the .tox/ subdirectory). These can be used to debug errors encountered during tox execution.

Whilst we create a virtual environment in the code snippets below, they are only to install the tox tool itself.

"},{"location":"writing_tests/verifying_changes/#test-case-verification-tests","title":"Test Case Verification: tests","text":"

Prerequisite:

python -m venv ./venv/\nsource ./venv/bin/activate\npip install tox\n
Verify:
tox -e tests\n

"},{"location":"writing_tests/verifying_changes/#framework-verification-py3","title":"Framework Verification: py3","text":"

Prerequisite:

python -m venv ./venv/\nsource ./venv/bin/activate\npip install tox\n
Verify:
tox -e py3\n

"},{"location":"writing_tests/writing_a_new_test/","title":"Writing a New Test","text":""},{"location":"writing_tests/writing_a_new_test/#test-functions","title":"Test Functions","text":"

Every test case is defined as a python function that defines a single StateTest or BlockchainTest by using one of the state_test or blockchain_test objects made available by the framework. Test cases, respectively test modules, must fulfil the following requirements:

Requirement When Be decorated with validity markers If the test case is not valid for all forks Use one of state_test or blockchain_test in its function arguments Always Call the state_test or blockchain_test in its test body Always Add a reference version of the EIP spec under test Test path contains eip"},{"location":"writing_tests/writing_a_new_test/#specifying-which-forks-tests-are-valid-for","title":"Specifying which Forks Tests are Valid For","text":"

Test cases can (and it most cases should) be decorated with one or more \"validity markers\" that define which the forks the test is valid for. This is achieved by applying:

  • pytest.mark.valid_from(FORK) and/or pytest.mark.valid_until(FORK)

or

  • pytest.mark.valid_at_transition_to(FORK)

markers on either the test function, test class or test module level:

FunctionClassModule
import pytest\n\n@pytest.mark.valid_from(\"Berlin\")\n@pytest.mark.valid_until(\"London\")\ndef test_access_list(state_test: StateTestFiller, fork: Fork):\n
import pytest\n\n\n@pytest.mark.valid_from(\"Shanghai\")\nclass TestMultipleWithdrawalsSameAddress:\n
import pytest\n\npytestmark = pytest.mark.valid_from(\"Shanghai\")\n

The ethereum_test_forks package defines the available forks and provides the following helpers that return all forks within the specified range:

  • forks_from
  • forks_from_until
"},{"location":"writing_tests/writing_a_new_test/#the-state_test-and-blockchain_test-test-function-arguments","title":"The state_test and blockchain_test Test Function Arguments","text":"

The test function's signature must contain exactly one of either a state_test or blockchain_test argument.

For example, for state tests:

def test_access_list(state_test: StateTestFiller):\n

and for blockchain tests:

def test_contract_creating_tx(\n    blockchain_test: BlockchainTestFiller, fork: Fork, initcode: Initcode\n):\n

The state_test and blockchain_test objects are actually wrapper classes to the StateTest, respectively BlockchainTest objects, that once called actually instantiate a new instance of these objects and fill the test case using the evm tool according to the pre and post states and the transactions defined within the test.

"},{"location":"writing_tests/writing_a_new_test/#statetest-object","title":"StateTest Object","text":"

The StateTest object represents a single test vector, and contains the following attributes:

  • env: Environment object which describes the global state of the blockchain before the test starts.
  • pre: Pre-State containing the information of all Ethereum accounts that exist before any transaction is executed.
  • post: Post-State containing the information of all Ethereum accounts that are created or modified after all transactions are executed.
  • txs: All transactions to be executed during test execution.
"},{"location":"writing_tests/writing_a_new_test/#blockchaintest-object","title":"BlockchainTest Object","text":"

The BlockchainTest object represents a single test vector that evaluates the Ethereum VM by attempting to append multiple blocks to the chain:

  • pre: Pre-State containing the information of all Ethereum accounts that exist before any block is executed.
  • post: Post-State containing the information of all Ethereum accounts that are created or modified after all blocks are executed.
  • blocks: All blocks to be appended to the blockchain during the test.
"},{"location":"writing_tests/writing_a_new_test/#prepost-state-of-the-test","title":"Pre/Post State of the Test","text":"

The pre and post states are elemental to setup and then verify the outcome of the state test.

Both pre and post are mappings of account addresses to account structures (see more info).

A single test vector can contain as many accounts in the pre and post states as required, and they can be also filled dynamically.

storage of an account is a key/value dictionary, and its values are integers within range of [0, 2**256 - 1].

txs are the steps which transform the pre-state into the post-state and must perform specific actions within the accounts (smart contracts) that result in verifiable changes to the balance, nonce, and/or storage in each of them.

post is compared against the outcome of the client after the execution of each transaction, and any differences are considered a failure

When designing a test, all the changes must be ideally saved into the contract's storage to be able to verify them in the post-state.

"},{"location":"writing_tests/writing_a_new_test/#test-transactions","title":"Test Transactions","text":"

Transactions can be crafted by sending them with specific data or to a specific account, which contains the code to be executed

Transactions can also create more accounts, by setting the to field to an empty string.

Transactions can be designed to fail, and a verification must be made that the transaction fails with the specific error that matches what is expected by the test.

"},{"location":"writing_tests/writing_a_new_test/#writing-code-for-the-accounts-in-the-test","title":"Writing code for the accounts in the test","text":"

Account bytecode can be embedded in the test accounts by adding it to the code field of the account object, or the data field of the tx object if the bytecode is meant to be treated as init code or call data.

The code can be in either of the following formats:

  • bytes object, representing the raw opcodes in binary format.
  • str, representing an hexadecimal format of the opcodes.
  • Code compilable object.

Currently supported built-in compilable objects are:

  • Yul object containing Yul source code.

Code objects can be concatenated together by using the + operator.

"},{"location":"writing_tests/writing_a_new_test/#verifying-the-accounts-post-states","title":"Verifying the Accounts' Post States","text":"

The state of the accounts after all blocks/transactions have been executed is the way of verifying that the execution client actually behaves like the test expects.

During their filling process, all tests automatically verify that the accounts specified in their post property actually match what was returned by the transition tool.

Within the post dictionary object, an account address can be:

  • None: The account will not be checked for absence or existence in the result returned by the transition tool.
  • Account object: The test expects that this account exists and also has properties equal to the properties specified by the Account object.
  • Account.NONEXISTENT: The test expects that this account does not exist in the result returned by the transition tool, and if the account exists, it results in error. E.g. when the transaction creating a contract is expected to fail and the test wants to verify that the address where the contract was supposed to be created is indeed empty.
"},{"location":"writing_tests/writing_a_new_test/#the-account-object","title":"The Account object","text":"

The Account object is used to specify the properties of an account to be verified in the post state.

The python representation can be found in src/ethereum_test_tools/common/types.py.

It can verify the following properties of an account:

  • nonce: the scalar value equal to a) the number of transactions sent by an Externally Owned Account, b) the amount of contracts created by a contract.

  • balance: the amount of Wei (10-18 Eth) the account has.

  • code: Bytecode contained by the account. To verify that an account contains no code, this property needs to be set to \"0x\" or \"\".

It is not recommended to verify Yul compiled code in the output account, because the bytecode can change from version to version.

  • storage: Storage within the account represented as a dict object. All storage keys that are expected to be set must be specified, and if a key is skipped, it is implied that its expected value is zero. Setting this property to {} (empty dict), means that all the keys in the account must be unset (equal to zero).

All account's properties are optional, and they can be skipped or set to None, which means that no check will be performed on that specific account property.

"},{"location":"writing_tests/writing_a_new_test/#verifying-correctness-of-the-new-test","title":"Verifying correctness of the new test","text":"

A well written test performs a single verification output at a time.

A verification output can be a single storage slot, the balance of an account, or a newly created contract.

It is not recommended to use balance changes to verify test correctness, as it can be easily affected by gas cost changes in future EIPs.

The best way to verify a transaction/block execution outcome is to check its storage.

A test can be written as a negative verification. E.g. a contract is not created, or a transaction fails to execute or runs out of gas.

These verifications must be carefully crafted because it is possible to end up having a false positive result, which means that the test passed but the intended verification was never made.

To avoid these scenarios, it is important to have a separate verification to check that test is effective. E.g. when a transaction is supposed to fail, it is necessary to check that the failure error is actually the one expected by the test.

"},{"location":"writing_tests/writing_a_new_test/#failing-or-invalid-transactions","title":"Failing or invalid transactions","text":"

Transactions included in a StateTest are expected to be intrinsically valid, i.e. the account sending the transaction must have enough funds to cover the gas costs, the max fee of the transaction must be equal or higher than the base fee of the block, etc.

An intrinsically valid transaction can still revert during its execution.

Blocks in a BlockchainTest can contain intrinsically invalid transactions but in this case the block is expected to be completely rejected, along with all transactions in it, including other valid transactions.

"}]} \ No newline at end of file +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Execution Spec Tests","text":"

ethereum/execution-spec-tests is both a collection of test cases and a framework in Python to generate tests for Ethereum execution clients implemented.

The framework collects and executes the test cases in order to generate test fixtures (JSON) which can be consumed by any execution client to verify their implementation of ethereum/execution-specs. Currently, the fixtures, which define state transition and block tests, are generated by the framework using the t8n command from the ethereum/go-ethereum evm command-line tool. Integration of other t8n tools is planned.

---\ntitle: Test Fixture Generation with execution-spec-tests\n---\nflowchart LR\n  style C stroke:#333,stroke-width:2px\n  style D stroke:#333,stroke-width:2px\n  style G stroke:#F9A825,stroke-width:2px\n  style H stroke:#F9A825,stroke-width:2px\n\n  subgraph ethereum/go-ethereum\n    C[<code>evm t8n</code>\\nexternal executable]\n  end\n\n  subgraph ethereum/solidity\n    D[<code>solc</code>\\nexternal executable]\n  end\n\n  subgraph ethereum/EIPs\n    E(<code>EIPS/EIP-*.md</code>\\nSHA digest via Github API)\n  end\n\n  subgraph \"ethereum/execution-spec-tests\"\n    A(<code>./tests/**/*.py</code>\\nPython Test Cases)\n    B([<code>$ fill ./tests/</code>\\nPython Framework])\n  end\n\n  subgraph Test Fixture Consumers\n    subgraph ethereum/hive\n      G([<code>$ hive ...</code>\\nGo Test Framework])\n    end\n    H([Client executables])\n  end\n\n  C <-.-> B  \n  D <-.-> B\n  A --> B\n  E <-.-> |retrieve latest spec version\\ncheck tested spec version| B\n  B -->|output| F(<code>./fixtures/**/*.json</code>\\nJSON Test Fixtures)\n  F -->|input| G\n  F -->|input| H

The generated test fixtures can be used:

  1. Directly by client teams' test frameworks, and,
  2. In the integration tests executed in the ethereum/hive framework.
"},{"location":"#relationship-to-ethereumtests","title":"Relationship to ethereum/tests","text":"

This collection of tests is relatively new (test case development started Q4, 2022) and mainly targets recent and upcoming Ethereum specification changes. It does not replace, but rather complements the existing tests in ethereum/tests.

"},{"location":"#motivation","title":"Motivation","text":"

The motivation to implement test cases in ethereum/execution-spec-tests is:

  1. To implement test cases as code and ensure that changes, due to spec changes, for example, can be easily made. Moreover, changes are easily understandable and available in version control.
  2. To avoid the 2-step approach often used in ethereum/tests:
    1. Code (often unavailable) -> Test case (YAML).
    2. Test case (YAML) -> Fixtures (JSON).

Contributing

Contributions via PR are welcome!

"},{"location":"navigation/","title":"Navigation","text":"
  • Overview
  • Getting Started
    • Quick Start
    • VS Code Setup
    • Repository Overview
    • Executing Tests at a Prompt
    • Executing Tests in VS Code
    • Executing Tests for Features Under Development
  • Writing Tests
    • Code Standards
    • Types of Test
    • Adding a New Test
    • Writing a New Test
    • Referencing an EIP Spec Version
    • Verifying Changes Locally
  • Tutorials
    • State Transition Tests
  • Getting Help
  • Developer Doc
    • Documentation
    • Coding Style
  • Library Reference
    • EVM Transition Tool Package
    • Ethereum Test Tools Package
    • Ethereum Test Forks Package
    • Pytest Plugins
  • Test case reference
    • Cancun
      • EIP-4844 Blobs
        • Spec
        • Test Blob Txs
          • Test Cases
        • Test Blob Txs Full
          • Test Cases
        • Test Blobhash Opcode
          • Test Cases
        • Test Blobhash Opcode Contexts
          • Test Cases
        • Test Excess Data Gas
          • Test Cases
        • Test Excess Data Gas Fork Transition
          • Test Cases
        • Test Point Evaluation Precompile
          • Test Cases
        • Test Point Evaluation Precompile Gas
          • Test Cases
        • Point Evaluation Vectors
          • Readme
    • Shanghai
      • EIP-3651 Warm Coinbase
        • Test Warm Coinbase
          • Test Cases
      • EIP-3855 Push0
        • Test Push0
          • Test Cases
      • EIP-3860 Initcode
        • Test Initcode
          • Test Cases
      • EIP-4895 Withdrawals
        • Test Withdrawals
          • Test Cases
    • Merge
      • Security
        • Test Selfdestruct Balance Bug
          • Test Cases
    • Berlin
      • EIP-2930 Access List
        • Test ACL
          • Test Cases
    • Istanbul
      • EIP-1344 CHAINID
        • Test CHAINID
          • Test Cases
    • Homestead
      • Yul
        • Test Yul Example
          • Test Cases
    • Frontier
      • Opcodes
        • Test DUP
          • Test Cases
"},{"location":"dev/","title":"Developer Documentation","text":"

This documentation is aimed at maintainers of execution-spec-tests but may be helpful during test case development:

  • generating documentation.
  • coding style.
  • enabling pre-commit checks.
"},{"location":"dev/coding_style/","title":"Coding Style","text":""},{"location":"dev/coding_style/#formatting-and-line-length","title":"Formatting and Line Length","text":"

The Python code in execution-spec-tests is black formatted with a maximum line length of 100. Using VS Code with editor.formatOnSave is a big help to ensure files conform to the repo's coding style, see VS Code Setup to configure this and other useful settings.

"},{"location":"dev/coding_style/#ignoring-bulk-change-commits","title":"Ignoring Bulk Change Commits","text":"

The max line length was changed from 80 to 100 in Q2 2023. To ignore this bulk change commit in git blame output, use the .git-blame-ignore-revs file, for example:

git blame --ignore-revs-file .git-blame-ignore-revs docs/gen_test_case_reference.py\n

To use the revs file persistently with git blame, run

git config blame.ignoreRevsFile .git-blame-ignore-revs\n
"},{"location":"dev/docs/","title":"Documentation","text":"

The execution-spec-tests documentation is generated via mkdocs and hosted remotely on Github Pages at ethereum.github.io/execution-spec-tests.

"},{"location":"dev/docs/#prerequisites","title":"Prerequisites","text":"
pip install -e .[docs]\n
"},{"location":"dev/docs/#build-the-documentation","title":"Build the Documentation","text":"

One time build:

mkdocs build\n

Pre-commit check: One time build and lint/type checking:

tox -e docs\n
"},{"location":"dev/docs/#local-deployment-and-test","title":"Local Deployment and Test","text":"

This runs continually: Deploys the site locally and re-generates the site upon modifications to docs/**/*.md or tests/**/*.py:

mkdocs serve\n
"},{"location":"dev/docs/#remote-deployment-and-versioning","title":"Remote Deployment and Versioning","text":"

The execution-specs-test docs are hosted on Github pages at the repo's Github pages. Versions are updated/deployed automatically as part of Github Actions, but this can also be performed on the command-line.

Our mkdocs configuration uses mike as a version provider. All deployments should be made via mike (whether as part of CI/CD or executed locally).

The deployed versions of the docs managed via mike are kept in the gh-pages branch. When you run mike it commits to this branch and optionally pushes the changes directly to remote.

"},{"location":"dev/docs/#aliases","title":"Aliases","text":"

We currently use two aliases:

  • latest: the latest stable release.
  • development: the current state of the main branch.

These aliases point to specific versions, as configured below. It's possible to share links containing either of these aliases or to specific versions, i.e, the following are all valid links:

  • https://ethereum.github.io/execution-spec-tests/ (redirects to latest/main)
  • https://ethereum.github.io/execution-spec-tests/latest (redirects to main)
  • https://ethereum.github.io/execution-spec-tests/development (redirects to tagged version)
  • https://ethereum.github.io/execution-spec-tests/main
  • https://ethereum.github.io/execution-spec-tests/v1.0.0
"},{"location":"dev/docs/#cicd-doc-deployment-via-github-actions","title":"CI/CD: Doc Deployment via Github Actions","text":"

There are two workflows that automatically deploy updated/new versions of the docs:

| Workflow yaml File | What | When | |-----------------_____|------|------| | docs_main.yaml | Update \"main\" version of docs | Push to 'main' branch, (e.g., on PR merge) | | docs_tags.yaml | Deploy new version of docs; tag is used as version name | Upon creating a tag matching v* |

"},{"location":"dev/docs/#build-and-deployment-without-alias-update","title":"Build and Deployment (without alias update)","text":"

Build a new version and deploy it to remote (this version will then show up in the version selector list):

mike deploy --push v1.2.3\n

Local deployment

If you deploy locally, the documentation will be built with any changes made in your local repository. Check out the tag to deploy tagged versions.

"},{"location":"dev/docs/#build-deploy-and-update-the-alias","title":"Build, Deploy and Update the Alias","text":"

Build, deploy and update the version an alias points to with:

mike deploy --push --update-aliases v1.2.3 latest\n

where v1.2.3 indicates the version's name and development is the alias. This will overwrite the version if it already exists.

Updating the 'main' version locally

\"main\" is just a version name (intended to reflect that it is build from the main branch). However, mike will build the docs site from the current local repository state (including local modifications). Therefore, make sure you're on the HEAD of the main branch before executing (unless you know what you're doing )!

mike deploy --push main\n

If the alias accidentally go change:

mike deploy --push --update-aliases main development\n
"},{"location":"dev/docs/#viewing-and-deleting-versions","title":"Viewing and Deleting Versions","text":"

List versions:

mike list\n

Delete a version:

mike delete v1.2.3a1-eof\n
"},{"location":"dev/docs/#set-default-version","title":"Set Default Version","text":"

Set the default version of the docs to open upon loading the page:

mike set-default --push latest\n

Typically, this must only be executed once for a repo.

"},{"location":"dev/docs/#implementation","title":"Implementation","text":""},{"location":"dev/docs/#plugins","title":"Plugins","text":"

The documentation flow uses mkdocs and the following additional plugins:

  • mkdocs: The main doc generation tool.
  • mkdocs-material: Provides many additional features and styling for mkdocs.
  • mkdocstrings and mkdocstrings-python: To generate documentation from Python docstrings.
  • mkdocs-gen-files: To generate markdown files automatically for each test case Python module. See this page for example usage. This plugin is used to programmatically generate the nav section for the generated test case reference documentation.
  • mkdocs-literate-nav: Is used to define the navigation layout for non-generated content and was created to work well with mkdocs-gen-files to add nav content for generated content.
  • blueswen/mkdocs-glightbox - for improved image and inline content display.
"},{"location":"dev/docs/#the-test-case-reference-section","title":"The \"Test Case Reference\" Section","text":"

This section is auto-generated via a combination of:

  1. mkdocstrings and mkdocstrings-python,
  2. mkdocs-gen-files,
  3. mkdocs-literate-nav.

It auto-generates a sequence of nested pages (with nav entries) of all python modules detected under ./tests. Each page contains a stub to the doc generated by mkdocstrings from the module's docstrings and source code. The mkdocs-gen-files and mkdocs-literate-nav plugins were created exactly for this purpose.

No action is necessary if a new test directory or module is added to ./tests, it will be picked up automatically.

Working with generated content

The files in the ./tests directory are watched by mkdocs serve. Run mkdocs serve and edit the source docstrings: The browser will reload with the new content automatically.

"},{"location":"dev/docs/#navigation","title":"Navigation","text":"

All pages that are to be included in the documentation and the navigation bar must be included in navigation.md, except \"Test Case Reference\" entries. This is enabled by mkdocs-literate-nav. The nav entries for the automatically generated \"Test Case Reference\" section are generated in mkdocs-gen-files and appended to navigation.md.

Current nav ordering limitations

The \"Test Case Reference\" section must currently be the last section in the nav. This is because our mkdocs flow:

  1. Reads navigation.md.
  2. Generates the Test Case Reference documentation and appends the Test Case Reference entries to navigation.md
  3. Generates the nav.

If necessary, we could probably split navigation.md into two files

  • navigation-pre-test-case-reference.md,
  • navigation-post-test-case-reference.md,

and create an arbitrary ordering in the Test Case Reference doc gen script. But this is untested.

"},{"location":"dev/docs/#read-the-docs","title":"Read the Docs","text":"

Originally, documentation was hosted at [readthedocs.io]. Currently, execution-spec-tests.readthedocs.io is configured to redirect to the Github Pages site. This is achieved by following the steps listed in the second half of this answer on stackoverflow. A public repo with dummy Sphinx project is required to achieve this: danceratopz/est-docs-redirect.

"},{"location":"dev/precommit/","title":"Enabling Pre-Commit Checks","text":"

There's a pre-commit config file available in the repository root (.pre-commit-config.yaml) that can be used to enable automatic checks upon commit - the commit will not go through if the checks don't pass.

To enable pre-commit, the following must be ran once:

pip install pre-commit\npre-commit install\n

Bypassing pre-commit checks

Enabling of pre-commit checks is not mandatory (it cannot be enforced) and even if it is enabled, it can always be bypassed with:

git commit --no-verify\n
"},{"location":"getting_help/","title":"Getting Help","text":"

The tests in this repository are a community effort to help improve the development cycle of all Ethereum execution clients.

We encourage contributions and recognize that Python is not everyone's primary language - if you stumble over issues or need help, please reach out to one of the execution-spec-tests maintainers either directly or in the #testing channel in the Ethereum R&D Discord Server.

"},{"location":"getting_help/#contact-the-maintainers","title":"Contact the Maintainers","text":"

Write to:

  • Dan on Discord or Telegram (danceratopz).
  • Spencer on Discord or Telegram (spencertaylorbrown/@spencertb).
  • Mario on Discord or Telegram (marioevz/@marioevz).

"},{"location":"getting_started/executing_tests_command_line/","title":"Executing Tests at a Prompt","text":"

The execution-spec-tests test framework uses the pytest framework for test case collection and execution. The fill command is essentially an alias for pytest, which uses several custom pytest plugins to run transition tools against test cases and generate JSON fixtures.

Options specific to execution-spec-tests

The command-line options specific to filling tests can be listed via:

fill --test-help\n

See Custom fill Command-Line Options for all options.

"},{"location":"getting_started/executing_tests_command_line/#collection-test-exploration","title":"Collection - Test Exploration","text":"

The test cases implemented in the ./tests sub-directory can be listed in the console using:

fill --collect-only\n

and can be filtered (by test path, function and parameter substring):

fill --collect-only -k warm_coinbase\n

Docstrings are additionally displayed when ran verbosely:

fill --collect-only -k warm_coinbase -vv\n
"},{"location":"getting_started/executing_tests_command_line/#execution","title":"Execution","text":"

By default, test cases are executed for all forks already deployed to mainnet, but not for forks still under active development, i.e., as of time of writing, Q2 2023:

fill\n

will generate fixtures for test cases from Frontier to Shanghai.

To generate all the test fixtures defined in the ./tests/shanghai sub-directory and write them to the ./fixtures-shanghai directory, run fill in the top-level directory as:

fill ./tests/shanghai --output=\"fixtures-shanghai\"\n

Test case verification

Note, that the (limited set of) test post conditions are tested against the output of the evm t8n command during test generation.

To generate all the test fixtures in the tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase.py module, for example, run:

fill tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase.py\n

To generate specific test fixtures from a specific test function or even test function and parameter set, obtain the corresponding test ID using:

fill --collect-only -q -k test_warm_coinbase\n

This filters the tests by test_warm_coinbase. Then find the relevant test ID in the console output and provide it to fill, for example, for a test function:

fill tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase.py::test_warm_coinbase_gas_usage\n

or, for a test function and specific parameter combination:

fill tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase.py::test_warm_coinbase_gas_usage[fork=Merge-DELEGATECALL]\n
"},{"location":"getting_started/executing_tests_command_line/#execution-for-development-forks","title":"Execution for Development Forks","text":"

By default, test cases are not executed with upcoming Ethereum forks so that they can be readily executed against the evm tool from the latest geth release.

In order to execute test cases for an upcoming fork, ensure that the evm tool used supports that fork and features under test and use the --until or --fork flag.

For example, as of Q2 2023, the current fork under active development is Cancun:

fill --until Cancun\n

See: Executing Tests for Features under Development.

"},{"location":"getting_started/executing_tests_command_line/#other-useful-pytest-command-line-options","title":"Other Useful Pytest Command-Line Options","text":"
fill -vv            # More verbose output\nfill -x             # Exit instantly on first error or failed test case\nfill --pdb          # Drop into the debugger upon error in a test case\n
"},{"location":"getting_started/executing_tests_command_line/#custom-fill-command-line-options","title":"Custom fill Command-Line Options","text":"

Options added by the execution-spec-tests pytest plugins can be listed with:

fill --test-help\n

Output:

usage: fill [-h] [--evm-bin EVM_BIN] [--traces TRACES] [--solc-bin SOLC_BIN]\n            [--filler-path FILLER_PATH] [--output OUTPUT]\n            [--flat-output FLAT_OUTPUT] [--forks FORKS] [--fork FORK]\n            [--from FROM] [--until UNTIL] [--test-help TEST_HELP]\n\noptions:\n  -h, --help            show this help message and exit\n\nArguments defining evm executable behavior:\n  --evm-bin EVM_BIN     Path to an evm executable that provides `t8n` and\n                        `b11r.` Default: First 'evm' entry in PATH\n  --traces TRACES       Collect traces of the execution information from the\n                        transition tool\n\nArguments defining the solc executable:\n  --solc-bin SOLC_BIN   Path to a solc executable (for Yul source compilation).\n                        Default: First 'solc' entry in PATH\n\nArguments defining filler location and output:\n  --filler-path FILLER_PATH\n                        Path to filler directives\n  --output OUTPUT       Directory to store the generated test fixtures. Can be\n                        deleted.\n  --flat-output FLAT_OUTPUT\n                        Output each test case in the directory without the\n                        folder structure.\n\nSpecify the fork range to generate fixtures for:\n  --forks FORKS         Display forks supported by the test framework and exit.\n  --fork FORK           Only fill tests for the specified fork.\n  --from FROM           Fill tests from and including the specified fork.\n  --until UNTIL         Fill tests until and including the specified fork.\n\nArguments related to running execution-spec-tests:\n  --test-help TEST_HELP\n                        Only show help options specific to execution-spec-tests\n                        and exit.\n\nExit: After displaying help.\n
"},{"location":"getting_started/executing_tests_dev_fork/","title":"Executing Tests for Features under Development","text":""},{"location":"getting_started/executing_tests_dev_fork/#requirements","title":"Requirements","text":"

By default, execution-spec-tests only generates fixtures for forks that have been deployed to mainnet. In order to generate fixtures for evm features that are actively under development:

  1. A version of the evm and solc tools that implement the feature must be available (although, typically only a developer version of the evm tool is required, usually the latest stable release of solc is adequate), and,
  2. The development fork to test must be explicitly specified on the command-line:

    via the --fork flagvia the --from flagvia the --until flag
    fill -k 4844 --fork=Cancun -v\n
    fill -k 4844 --from=Cancun -v\n
    fill -k 4844 --until=Cancun -v\n

Specifying the evm binary via evm-bin

It is possible to explicitly specify the evm binary used to generate fixtures via the --evm-bin flag, for example,

fill --fork=Cancun --evm-bin=/opt/bin/evm -v\n

"},{"location":"getting_started/executing_tests_dev_fork/#further-help","title":"Further Help","text":"
  1. geth/evm build documentation.
  2. solc build documentation.

Verifying evm and solc versions used

The versions used to generate fixtures are displayed in the console output:

"},{"location":"getting_started/executing_tests_dev_fork/#vs-code-setup","title":"VS Code Setup","text":"

By default, VS Code's Testing View will only show tests for stable forks. To show tests for development forks, uncomment the relevant line in the python.testing.pytestArgs configuration section of included settings file (.vscode/settings.json) to enable the --until=FORK flag. See VS Code Setup for help finding the settings files.

"},{"location":"getting_started/executing_tests_vs_code/","title":"Executing Tests in VS Code","text":"

Prerequisite: VS Code Setup.

"},{"location":"getting_started/executing_tests_vs_code/#exploring-test-cases","title":"Exploring Test Cases","text":"

Implemented test cases can be explored in VS Code's \"Testing\" View; click on the conical flask highlighted in the screenshot below.

Testing EVM Features Under Active Development

See the VS Code section in Executing Tests for Features under Development to explore tests targeting EVM features under development.

"},{"location":"getting_started/executing_tests_vs_code/#executing-and-debugging-test-cases","title":"Executing and Debugging Test Cases","text":""},{"location":"getting_started/quick_start/","title":"Quick Start","text":"

Testing features under active development

The EVM features under test must be implemented in the evm tool and solc executables that are used by the execution-spec-tests framework. The following guide installs stable versions of these tools.

To test features under active development, start with this base configuration and then follow the steps in executing tests for features under development.

The following requires a Python 3.10 or Python 3.11 installation.

  1. Ensure go-ethereum's evm tool and solc are in your path. Either build the required versions, or alternatively:

    UbuntumacosWindows

    sudo add-apt-repository -y ppa:ethereum/ethereum\nsudo apt-get update\nsudo apt-get install ethereum solc\n
    More help:

    • geth installation doc.
    • solc installation doc.

    brew update\nbrew upgrade\nbrew tap ethereum/ethereum\nbrew install ethereum solidity\n
    More help:

    • geth installation doc.
    • solc installation doc.

    Binaries available here:

    • geth (binary or installer).
    • solc.

    More help:

    • geth installation doc.
    • solc static binaries doc.
  2. Clone the execution-spec-tests repo and install its and dependencies (it's recommended to use a virtual environment for the installation):

    git clone https://github.com/ethereum/execution-spec-tests\ncd execution-spec-tests\npython3 -m venv ./venv/\nsource ./venv/bin/activate\npip install -e .[docs,lint,test]\n

  3. Verify installation:

    1. Explore test cases:
    2. console fill --collect-only

    Expected console output: 3. Execute the test cases (verbosely) in the ./tests/berlin/eip2930_access_list/test_acl.py module:

    fill -v tests/berlin/eip2930_access_list/test_acl.py\n
    Expected console output:

    Check:

    1. The versions of the evm and solc tools are as expected (your versions may differ from those in the highlighted box).
    2. The corresponding fixture file has been generated:

      head fixtures/berlin/eip2930_access_list/acl/access_list.json\n
"},{"location":"getting_started/quick_start/#next-steps","title":"Next Steps","text":"
  1. Learn useful command-line flags.
  2. Execute tests for features under development via the --fork flag.
  3. Optional: Configure VS Code to auto-format Python code and execute tests within VS Code.
  4. Implement a new test case, see Writing Tests.
"},{"location":"getting_started/repository_overview/","title":"Repository Overview","text":"

The most relevant folders and file in the repo are:

\ud83d\udcc1 execution-test-specs/\n\u251c\u2500\u2574\ud83d\udcc1 tests/                     # test cases\n\u2502   \u251c\u2500\u2500 \ud83d\udcc1 eips/\n\u2502   \u251c\u2500\u2500 \ud83d\udcc1 vm/\n\u2502   \u2514\u2500\u2500 \ud83d\udcc1 ...\n\u251c\u2500\u2574\ud83d\udcc1 fixtures/                  # default fixture output dir\n\u2502   \u251c\u2500\u2500 \ud83d\udcc1 eips/\n\u2502   \u251c\u2500\u2500 \ud83d\udcc1 vm/\n\u2502   \u2514\u2500\u2500 \ud83d\udcc1 ...\n\u251c\u2500\u2574\ud83d\udcc1 src/                       # library & framework packages\n\u2502   \u251c\u2500\u2500 \ud83d\udcc1 ethereum_test_fork/\n\u2502   \u251c\u2500\u2500 \ud83d\udcc1 ethereum_test_tools/\n\u2502   \u2514\u2500\u2500 \ud83d\udcc1 ...\n\u251c\u2500\u2574\ud83d\udcc1 docs/                      # markdown documentation\n\u2502   \u251c\u2500\u2500 \ud83d\udcc1 getting_started\n\u2502   \u251c\u2500\u2500 \ud83d\udcc1 dev\n\u2502   \u2514\u2500\u2500 \ud83d\udcc1 ...\n\u251c\u2500\u2574\ud83d\udcc1 .vscode/                   # visual studio code config\n\u2502   \u251c\u2500\u2500 \ud83d\udcc4 settings.recommended.json # copy to settings.json\n\u2502   \u251c\u2500\u2500 \ud83d\udcc4 launch.recommended.json\n\u2502   \u2514\u2500\u2500 \ud83d\udcc4 extensions.json\n\u2514\u2500\u2500 \ud83d\udcc4 whitelist.txt             # spellcheck dictionary\n

"},{"location":"getting_started/repository_overview/#tests","title":"tests/","text":"

Contains the implementation of the Ethereum consensus tests available in this repository.

"},{"location":"getting_started/repository_overview/#src","title":"src/","text":"

Contains various packages that help to define test cases and to interface with the evm t8n command. Additionally, it contains some packages that enable test case execution by customizing pytest which acts as the test framework.

"},{"location":"getting_started/repository_overview/#docs","title":"docs/","text":"

Contains documentation configuration and source files.

"},{"location":"getting_started/repository_overview/#vscode","title":".vscode/","text":"

See VS Code Setup.

"},{"location":"getting_started/setup_vs_code/","title":"VS Code Setup","text":"

VS Code setup is optional, but does offer the following advantages:

  • Auto-format your Python code to conform to the repository's code standards (black).
  • Inline linting and auto-completion (thanks to Python type hints).
  • Spell-check your code and docs.
  • Graphical exploration of test cases and easy test execution/debug.
"},{"location":"getting_started/setup_vs_code/#installation","title":"Installation","text":"

Please refer to the Visual Studio Code docs for help with installation.

"},{"location":"getting_started/setup_vs_code/#vs-code-settings-file","title":"VS Code Settings file","text":"

The ethereum/execution-spec-tests repo includes configuration files for VS Code in the .vscode/ sub-directory:

\ud83d\udcc1 execution-test-specs/\n\u2514\u2500\u2500\ud83d\udcc1 .vscode/\n    \u251c\u2500\u2500 \ud83d\udcc4 settings.recommended.json\n    \u251c\u2500\u2500 \ud83d\udcc4 extensions.json\n    \u2514\u2500\u2500 \ud83d\udcc4 launch.recommended.json\n

To enable the recommended settings, copy the settings file to the expected location:

cp .vscode/settings.recommended.json .vscode/settings.json\n

To additionally enable the recommended launch configurations:

cp .vscode/launch.recommended.json .vscode/launch.json\n
"},{"location":"getting_started/setup_vs_code/#additional-vs-code-extensions","title":"Additional VS Code Extensions","text":"

Open the folder in VS Code where execution-spec-tests is cloned: VS Code should prompt to install the repository's required extensions from .vscode/extensions.json:

  • ms-python.python
  • ms-python.isort
  • ms-python.flake8
  • ms-python.black-formatter
  • esbenp.prettier-vscode
  • streetsidesoftware.code-spell-checker
  • tamasfe.even-better-toml

Workspace Trust

Trust the execution-specs-test repository when opening in VS Code to be prompted to install the plugins recommended via the extensions.json file.

"},{"location":"getting_started/setup_vs_code/#configuration-for-testing-evm-features-under-active-development","title":"Configuration for Testing EVM Features Under Active Development","text":"

An additional step is required to enable fixture generations for features from forks that are under active development and have not been deployed to mainnet, see Executing Tests for Features under Development.

"},{"location":"library/","title":"Library (Tools) Reference Documentation","text":"

Execution spec tests consists of several packages that implement helper classes and tools that enable and simplify test case implementation. This section contains their reference documentation:

  • evm_transition_tool - a wrapper for the transition (t8n) tool.
  • ethereum_test_tools - provides primitives and helpers to test Ethereum execution clients.
  • ethereum_test_forks - provides definitions for supported forks used in tests.
  • pytest_plugins - contains pytest customizations that provide additional functionality for generating test fixtures.
"},{"location":"library/ethereum_test_forks/","title":"Ethereum Test Forks package","text":"

Ethereum test fork definitions.

"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.Frontier","title":"Frontier","text":"

Bases: BaseFork

Frontier fork

Source code in src/ethereum_test_forks/forks/forks.py
class Frontier(BaseFork):\n\"\"\"\n    Frontier fork\n    \"\"\"\n\n    @classmethod\n    def header_base_fee_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n        At genesis, header must not contain base fee\n        \"\"\"\n        return False\n\n    @classmethod\n    def header_prev_randao_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n        At genesis, header must not contain Prev Randao value\n        \"\"\"\n        return False\n\n    @classmethod\n    def header_zero_difficulty_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n        At genesis, header must not have difficulty zero\n        \"\"\"\n        return False\n\n    @classmethod\n    def header_withdrawals_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n        At genesis, header must not contain withdrawals\n        \"\"\"\n        return False\n\n    @classmethod\n    def header_excess_data_gas_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n        At genesis, header must not contain excess data gas\n        \"\"\"\n        return False\n\n    @classmethod\n    def header_data_gas_used_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n        At genesis, header must not contain data gas used\n        \"\"\"\n        return False\n\n    @classmethod\n    def engine_new_payload_version(cls, block_number: int, timestamp: int) -> Optional[int]:\n\"\"\"\n        At genesis, payloads cannot be sent through the engine API\n        \"\"\"\n        return None\n\n    @classmethod\n    def engine_new_payload_blob_hashes(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n        At genesis, payloads do not have blob hashes.\n        \"\"\"\n        return False\n\n    @classmethod\n    def get_reward(cls, block_number: int, timestamp: int) -> int:\n\"\"\"\n        At Genesis the expected reward amount in wei is\n        5_000_000_000_000_000_000\n        \"\"\"\n        return 5_000_000_000_000_000_000\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.Frontier.header_base_fee_required","title":"header_base_fee_required(block_number, timestamp) classmethod","text":"

At genesis, header must not contain base fee

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef header_base_fee_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n    At genesis, header must not contain base fee\n    \"\"\"\n    return False\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.Frontier.header_prev_randao_required","title":"header_prev_randao_required(block_number, timestamp) classmethod","text":"

At genesis, header must not contain Prev Randao value

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef header_prev_randao_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n    At genesis, header must not contain Prev Randao value\n    \"\"\"\n    return False\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.Frontier.header_zero_difficulty_required","title":"header_zero_difficulty_required(block_number, timestamp) classmethod","text":"

At genesis, header must not have difficulty zero

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef header_zero_difficulty_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n    At genesis, header must not have difficulty zero\n    \"\"\"\n    return False\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.Frontier.header_withdrawals_required","title":"header_withdrawals_required(block_number, timestamp) classmethod","text":"

At genesis, header must not contain withdrawals

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef header_withdrawals_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n    At genesis, header must not contain withdrawals\n    \"\"\"\n    return False\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.Frontier.header_excess_data_gas_required","title":"header_excess_data_gas_required(block_number, timestamp) classmethod","text":"

At genesis, header must not contain excess data gas

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef header_excess_data_gas_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n    At genesis, header must not contain excess data gas\n    \"\"\"\n    return False\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.Frontier.header_data_gas_used_required","title":"header_data_gas_used_required(block_number, timestamp) classmethod","text":"

At genesis, header must not contain data gas used

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef header_data_gas_used_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n    At genesis, header must not contain data gas used\n    \"\"\"\n    return False\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.Frontier.engine_new_payload_version","title":"engine_new_payload_version(block_number, timestamp) classmethod","text":"

At genesis, payloads cannot be sent through the engine API

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef engine_new_payload_version(cls, block_number: int, timestamp: int) -> Optional[int]:\n\"\"\"\n    At genesis, payloads cannot be sent through the engine API\n    \"\"\"\n    return None\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.Frontier.engine_new_payload_blob_hashes","title":"engine_new_payload_blob_hashes(block_number, timestamp) classmethod","text":"

At genesis, payloads do not have blob hashes.

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef engine_new_payload_blob_hashes(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n    At genesis, payloads do not have blob hashes.\n    \"\"\"\n    return False\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.Frontier.get_reward","title":"get_reward(block_number, timestamp) classmethod","text":"

At Genesis the expected reward amount in wei is 5_000_000_000_000_000_000

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef get_reward(cls, block_number: int, timestamp: int) -> int:\n\"\"\"\n    At Genesis the expected reward amount in wei is\n    5_000_000_000_000_000_000\n    \"\"\"\n    return 5_000_000_000_000_000_000\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.BerlinToLondonAt5","title":"BerlinToLondonAt5","text":"

Bases: Berlin

Berlin to London transition at Block 5 fork

Source code in src/ethereum_test_forks/forks/transition.py
@transition_fork(to_fork=London)\nclass BerlinToLondonAt5(Berlin):\n\"\"\"\n    Berlin to London transition at Block 5 fork\n    \"\"\"\n\n    @classmethod\n    def header_base_fee_required(cls, block_number: int, _: int) -> bool:\n\"\"\"\n        Base Fee is required starting from London.\n        \"\"\"\n        return block_number >= 5\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.transition.BerlinToLondonAt5.header_base_fee_required","title":"header_base_fee_required(block_number, _) classmethod","text":"

Base Fee is required starting from London.

Source code in src/ethereum_test_forks/forks/transition.py
@classmethod\ndef header_base_fee_required(cls, block_number: int, _: int) -> bool:\n\"\"\"\n    Base Fee is required starting from London.\n    \"\"\"\n    return block_number >= 5\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.InvalidForkError","title":"InvalidForkError","text":"

Bases: Exception

Invalid fork error raised when the fork specified by command-line option --latest-fork is not found.

Source code in src/ethereum_test_forks/helpers.py
class InvalidForkError(Exception):\n\"\"\"\n    Invalid fork error raised when the fork specified by command-line option\n    --latest-fork is not found.\n    \"\"\"\n\n    def __init__(self, message):\n        super().__init__(message)\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.get_forks","title":"get_forks()","text":"

Returns a list of all the fork classes implemented by ethereum_test_forks ordered chronologically by deployment.

Source code in src/ethereum_test_forks/helpers.py
def get_forks() -> List[Fork]:\n\"\"\"\n    Returns a list of all the fork classes implemented by\n    `ethereum_test_forks` ordered chronologically by deployment.\n    \"\"\"\n    all_forks: List[Fork] = []\n    for fork_name in forks.__dict__:\n        fork = forks.__dict__[fork_name]\n        if not isinstance(fork, type):\n            continue\n        if issubclass(fork, BaseFork) and fork is not BaseFork:\n            all_forks.append(fork)\n    return all_forks\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.MergeToShanghaiAtTime15k","title":"MergeToShanghaiAtTime15k","text":"

Bases: Merge

Merge to Shanghai transition at Timestamp 15k fork

Source code in src/ethereum_test_forks/forks/transition.py
@transition_fork(to_fork=Shanghai)\nclass MergeToShanghaiAtTime15k(Merge):\n\"\"\"\n    Merge to Shanghai transition at Timestamp 15k fork\n    \"\"\"\n\n    @classmethod\n    def header_withdrawals_required(cls, _: int, timestamp: int) -> bool:\n\"\"\"\n        Withdrawals are required starting from Shanghai.\n        \"\"\"\n        return timestamp >= 15_000\n\n    @classmethod\n    def engine_new_payload_version(cls, block_number: int, timestamp: int) -> Optional[int]:\n\"\"\"\n        Starting at Shanghai, new payload calls must use version 2\n        \"\"\"\n        return 2 if timestamp >= 15_000 else 1\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.transition.MergeToShanghaiAtTime15k.header_withdrawals_required","title":"header_withdrawals_required(_, timestamp) classmethod","text":"

Withdrawals are required starting from Shanghai.

Source code in src/ethereum_test_forks/forks/transition.py
@classmethod\ndef header_withdrawals_required(cls, _: int, timestamp: int) -> bool:\n\"\"\"\n    Withdrawals are required starting from Shanghai.\n    \"\"\"\n    return timestamp >= 15_000\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.transition.MergeToShanghaiAtTime15k.engine_new_payload_version","title":"engine_new_payload_version(block_number, timestamp) classmethod","text":"

Starting at Shanghai, new payload calls must use version 2

Source code in src/ethereum_test_forks/forks/transition.py
@classmethod\ndef engine_new_payload_version(cls, block_number: int, timestamp: int) -> Optional[int]:\n\"\"\"\n    Starting at Shanghai, new payload calls must use version 2\n    \"\"\"\n    return 2 if timestamp >= 15_000 else 1\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.get_deployed_forks","title":"get_deployed_forks()","text":"

Returns a list of all the fork classes implemented by ethereum_test_forks that have been deployed to mainnet, chronologically ordered by deployment.

Source code in src/ethereum_test_forks/helpers.py
def get_deployed_forks():\n\"\"\"\n    Returns a list of all the fork classes implemented by `ethereum_test_forks`\n    that have been deployed to mainnet, chronologically ordered by deployment.\n    \"\"\"\n    return [fork for fork in get_forks() if fork.is_deployed()]\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.get_development_forks","title":"get_development_forks()","text":"

Returns a list of all the fork classes implemented by ethereum_test_forks that have been not yet deployed to mainnet and are currently under development. The list is ordered by their planned deployment date.

Source code in src/ethereum_test_forks/helpers.py
def get_development_forks():\n\"\"\"\n    Returns a list of all the fork classes implemented by `ethereum_test_forks`\n    that have been not yet deployed to mainnet and are currently under\n    development. The list is ordered by their planned deployment date.\n    \"\"\"\n    return [fork for fork in get_forks() if not fork.is_deployed()]\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.ShanghaiToCancunAtTime15k","title":"ShanghaiToCancunAtTime15k","text":"

Bases: Shanghai

Shanghai to Cancun transition at Timestamp 15k

Source code in src/ethereum_test_forks/forks/transition.py
@transition_fork(to_fork=Cancun)\nclass ShanghaiToCancunAtTime15k(Shanghai):\n\"\"\"\n    Shanghai to Cancun transition at Timestamp 15k\n    \"\"\"\n\n    @classmethod\n    def header_excess_data_gas_required(cls, _: int, timestamp: int) -> bool:\n\"\"\"\n        Excess data gas is required if transitioning to Cancun.\n        \"\"\"\n        return timestamp >= 15_000\n\n    @classmethod\n    def engine_new_payload_version(cls, block_number: int, timestamp: int) -> Optional[int]:\n\"\"\"\n        Starting at Cancun, new payload calls must use version 3\n        \"\"\"\n        return 3 if timestamp >= 15_000 else 2\n\n    @classmethod\n    def engine_new_payload_blob_hashes(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n        Starting at Cancun, payloads must have blob hashes.\n        \"\"\"\n        return timestamp >= 15_000\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.transition.ShanghaiToCancunAtTime15k.header_excess_data_gas_required","title":"header_excess_data_gas_required(_, timestamp) classmethod","text":"

Excess data gas is required if transitioning to Cancun.

Source code in src/ethereum_test_forks/forks/transition.py
@classmethod\ndef header_excess_data_gas_required(cls, _: int, timestamp: int) -> bool:\n\"\"\"\n    Excess data gas is required if transitioning to Cancun.\n    \"\"\"\n    return timestamp >= 15_000\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.transition.ShanghaiToCancunAtTime15k.engine_new_payload_version","title":"engine_new_payload_version(block_number, timestamp) classmethod","text":"

Starting at Cancun, new payload calls must use version 3

Source code in src/ethereum_test_forks/forks/transition.py
@classmethod\ndef engine_new_payload_version(cls, block_number: int, timestamp: int) -> Optional[int]:\n\"\"\"\n    Starting at Cancun, new payload calls must use version 3\n    \"\"\"\n    return 3 if timestamp >= 15_000 else 2\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.transition.ShanghaiToCancunAtTime15k.engine_new_payload_blob_hashes","title":"engine_new_payload_blob_hashes(block_number, timestamp) classmethod","text":"

Starting at Cancun, payloads must have blob hashes.

Source code in src/ethereum_test_forks/forks/transition.py
@classmethod\ndef engine_new_payload_blob_hashes(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n    Starting at Cancun, payloads must have blob hashes.\n    \"\"\"\n    return timestamp >= 15_000\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.get_transition_forks","title":"get_transition_forks()","text":"

Returns all the transition forks

Source code in src/ethereum_test_forks/helpers.py
def get_transition_forks() -> List[Fork]:\n\"\"\"\n    Returns all the transition forks\n    \"\"\"\n    transition_forks: List[Fork] = []\n\n    for fork_name in transition.__dict__:\n        fork = transition.__dict__[fork_name]\n        if not isinstance(fork, type):\n            continue\n        if issubclass(fork, TransitionBaseClass) and issubclass(fork, BaseFork):\n            transition_forks.append(fork)\n\n    return transition_forks\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.transition_fork_from_to","title":"transition_fork_from_to(fork_from, fork_to)","text":"

Returns the transition fork that transitions to and from the specified forks.

Source code in src/ethereum_test_forks/helpers.py
def transition_fork_from_to(fork_from: Fork, fork_to: Fork) -> Fork | None:\n\"\"\"\n    Returns the transition fork that transitions to and from the specified\n    forks.\n    \"\"\"\n    for transition_fork in get_transition_forks():\n        if not issubclass(transition_fork, TransitionBaseClass):\n            continue\n        if (\n            transition_fork.transitions_to() == fork_to\n            and transition_fork.transitions_from() == fork_from\n        ):\n            return transition_fork\n\n    return None\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.Homestead","title":"Homestead","text":"

Bases: Frontier

Homestead fork

Source code in src/ethereum_test_forks/forks/forks.py
class Homestead(Frontier):\n\"\"\"\n    Homestead fork\n    \"\"\"\n\n    pass\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.Byzantium","title":"Byzantium","text":"

Bases: Homestead

Byzantium fork

Source code in src/ethereum_test_forks/forks/forks.py
class Byzantium(Homestead):\n\"\"\"\n    Byzantium fork\n    \"\"\"\n\n    @classmethod\n    def get_reward(cls, block_number: int, timestamp: int) -> int:\n\"\"\"\n        At Byzantium, the block reward is reduced to\n        3_000_000_000_000_000_000 wei\n        \"\"\"\n        return 3_000_000_000_000_000_000\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.Byzantium.get_reward","title":"get_reward(block_number, timestamp) classmethod","text":"

At Byzantium, the block reward is reduced to 3_000_000_000_000_000_000 wei

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef get_reward(cls, block_number: int, timestamp: int) -> int:\n\"\"\"\n    At Byzantium, the block reward is reduced to\n    3_000_000_000_000_000_000 wei\n    \"\"\"\n    return 3_000_000_000_000_000_000\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.transition_fork_to","title":"transition_fork_to(fork_to)","text":"

Returns the transition fork that transitions to the specified fork.

Source code in src/ethereum_test_forks/helpers.py
def transition_fork_to(fork_to: Fork) -> List[Fork]:\n\"\"\"\n    Returns the transition fork that transitions to the specified fork.\n    \"\"\"\n    transition_forks: List[Fork] = []\n    for transition_fork in get_transition_forks():\n        if not issubclass(transition_fork, TransitionBaseClass):\n            continue\n        if transition_fork.transitions_to() == fork_to:\n            transition_forks.append(transition_fork)\n\n    return transition_forks\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.Constantinople","title":"Constantinople","text":"

Bases: Byzantium

Constantinople fork

Source code in src/ethereum_test_forks/forks/forks.py
class Constantinople(Byzantium):\n\"\"\"\n    Constantinople fork\n    \"\"\"\n\n    @classmethod\n    def get_reward(cls, block_number: int, timestamp: int) -> int:\n\"\"\"\n        At Constantinople, the block reward is reduced to\n        2_000_000_000_000_000_000 wei\n        \"\"\"\n        return 2_000_000_000_000_000_000\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.Constantinople.get_reward","title":"get_reward(block_number, timestamp) classmethod","text":"

At Constantinople, the block reward is reduced to 2_000_000_000_000_000_000 wei

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef get_reward(cls, block_number: int, timestamp: int) -> int:\n\"\"\"\n    At Constantinople, the block reward is reduced to\n    2_000_000_000_000_000_000 wei\n    \"\"\"\n    return 2_000_000_000_000_000_000\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks_from_until","title":"forks_from_until(fork_from, fork_until)","text":"

Returns the specified fork and all forks after it until and including the second specified fork

Source code in src/ethereum_test_forks/helpers.py
def forks_from_until(fork_from: Fork, fork_until: Fork) -> List[Fork]:\n\"\"\"\n    Returns the specified fork and all forks after it until and including the\n    second specified fork\n    \"\"\"\n    prev_fork = fork_until\n\n    forks: List[Fork] = []\n\n    while prev_fork != BaseFork and prev_fork != fork_from:\n        forks.insert(0, prev_fork)\n\n        prev_fork = prev_fork.__base__\n\n    if prev_fork == BaseFork:\n        return []\n\n    forks.insert(0, fork_from)\n\n    return forks\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.ConstantinopleFix","title":"ConstantinopleFix","text":"

Bases: Constantinople

Constantinople Fix fork

Source code in src/ethereum_test_forks/forks/forks.py
class ConstantinopleFix(Constantinople):\n\"\"\"\n    Constantinople Fix fork\n    \"\"\"\n\n    pass\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.Istanbul","title":"Istanbul","text":"

Bases: ConstantinopleFix

Istanbul fork

Source code in src/ethereum_test_forks/forks/forks.py
class Istanbul(ConstantinopleFix):\n\"\"\"\n    Istanbul fork\n    \"\"\"\n\n    pass\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks_from","title":"forks_from(fork, deployed_only=True)","text":"

Returns the specified fork and all forks after it.

Source code in src/ethereum_test_forks/helpers.py
def forks_from(fork: Fork, deployed_only: bool = True) -> List[Fork]:\n\"\"\"\n    Returns the specified fork and all forks after it.\n    \"\"\"\n    if deployed_only:\n        latest_fork = get_deployed_forks()[-1]\n    else:\n        latest_fork = get_forks()[-1]\n    return forks_from_until(fork, latest_fork)\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.MuirGlacier","title":"MuirGlacier","text":"

Bases: Istanbul

Muir Glacier fork

Source code in src/ethereum_test_forks/forks/forks.py
class MuirGlacier(Istanbul):\n\"\"\"\n    Muir Glacier fork\n    \"\"\"\n\n    pass\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.is_fork","title":"is_fork(fork, which)","text":"

Returns True if fork is which or beyond, `False otherwise.

Source code in src/ethereum_test_forks/helpers.py
def is_fork(fork: Fork, which: Fork) -> bool:\n\"\"\"\n    Returns `True` if `fork` is `which` or beyond, `False otherwise.\n    \"\"\"\n    prev_fork = fork\n\n    while prev_fork != BaseFork:\n        if prev_fork == which:\n            return True\n\n        prev_fork = prev_fork.__base__\n\n    return False\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.Berlin","title":"Berlin","text":"

Bases: Istanbul

Berlin fork

Source code in src/ethereum_test_forks/forks/forks.py
class Berlin(Istanbul):\n\"\"\"\n    Berlin fork\n    \"\"\"\n\n    pass\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.London","title":"London","text":"

Bases: Berlin

London fork

Source code in src/ethereum_test_forks/forks/forks.py
class London(Berlin):\n\"\"\"\n    London fork\n    \"\"\"\n\n    @classmethod\n    def header_base_fee_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n        Base Fee is required starting from London.\n        \"\"\"\n        return True\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.London.header_base_fee_required","title":"header_base_fee_required(block_number, timestamp) classmethod","text":"

Base Fee is required starting from London.

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef header_base_fee_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n    Base Fee is required starting from London.\n    \"\"\"\n    return True\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.ArrowGlacier","title":"ArrowGlacier","text":"

Bases: London

Arrow Glacier fork

Source code in src/ethereum_test_forks/forks/forks.py
class ArrowGlacier(London):\n\"\"\"\n    Arrow Glacier fork\n    \"\"\"\n\n    pass\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.GrayGlacier","title":"GrayGlacier","text":"

Bases: ArrowGlacier

Gray Glacier fork

Source code in src/ethereum_test_forks/forks/forks.py
class GrayGlacier(ArrowGlacier):\n\"\"\"\n    Gray Glacier fork\n    \"\"\"\n\n    pass\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.Merge","title":"Merge","text":"

Bases: London

Merge fork

Source code in src/ethereum_test_forks/forks/forks.py
class Merge(London):\n\"\"\"\n    Merge fork\n    \"\"\"\n\n    @classmethod\n    def header_prev_randao_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n        Prev Randao is required starting from Merge.\n        \"\"\"\n        return True\n\n    @classmethod\n    def header_zero_difficulty_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n        Zero difficulty is required starting from Merge.\n        \"\"\"\n        return True\n\n    @classmethod\n    def get_reward(cls, block_number: int, timestamp: int) -> int:\n\"\"\"\n        Merge updates the reward to 0.\n        \"\"\"\n        return 0\n\n    @classmethod\n    def engine_new_payload_version(cls, block_number: int, timestamp: int) -> Optional[int]:\n\"\"\"\n        Starting at the merge, payloads can be sent through the engine API\n        \"\"\"\n        return 1\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.Merge.header_prev_randao_required","title":"header_prev_randao_required(block_number, timestamp) classmethod","text":"

Prev Randao is required starting from Merge.

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef header_prev_randao_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n    Prev Randao is required starting from Merge.\n    \"\"\"\n    return True\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.Merge.header_zero_difficulty_required","title":"header_zero_difficulty_required(block_number, timestamp) classmethod","text":"

Zero difficulty is required starting from Merge.

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef header_zero_difficulty_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n    Zero difficulty is required starting from Merge.\n    \"\"\"\n    return True\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.Merge.get_reward","title":"get_reward(block_number, timestamp) classmethod","text":"

Merge updates the reward to 0.

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef get_reward(cls, block_number: int, timestamp: int) -> int:\n\"\"\"\n    Merge updates the reward to 0.\n    \"\"\"\n    return 0\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.Merge.engine_new_payload_version","title":"engine_new_payload_version(block_number, timestamp) classmethod","text":"

Starting at the merge, payloads can be sent through the engine API

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef engine_new_payload_version(cls, block_number: int, timestamp: int) -> Optional[int]:\n\"\"\"\n    Starting at the merge, payloads can be sent through the engine API\n    \"\"\"\n    return 1\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.Shanghai","title":"Shanghai","text":"

Bases: Merge

Shanghai fork

Source code in src/ethereum_test_forks/forks/forks.py
class Shanghai(Merge):\n\"\"\"\n    Shanghai fork\n    \"\"\"\n\n    @classmethod\n    def header_withdrawals_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n        Withdrawals are required starting from Shanghai.\n        \"\"\"\n        return True\n\n    @classmethod\n    def engine_new_payload_version(cls, block_number: int, timestamp: int) -> Optional[int]:\n\"\"\"\n        Starting at Shanghai, new payload calls must use version 2\n        \"\"\"\n        return 2\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.Shanghai.header_withdrawals_required","title":"header_withdrawals_required(block_number, timestamp) classmethod","text":"

Withdrawals are required starting from Shanghai.

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef header_withdrawals_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n    Withdrawals are required starting from Shanghai.\n    \"\"\"\n    return True\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.Shanghai.engine_new_payload_version","title":"engine_new_payload_version(block_number, timestamp) classmethod","text":"

Starting at Shanghai, new payload calls must use version 2

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef engine_new_payload_version(cls, block_number: int, timestamp: int) -> Optional[int]:\n\"\"\"\n    Starting at Shanghai, new payload calls must use version 2\n    \"\"\"\n    return 2\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.Cancun","title":"Cancun","text":"

Bases: Shanghai

Cancun fork

Source code in src/ethereum_test_forks/forks/forks.py
class Cancun(Shanghai):\n\"\"\"\n    Cancun fork\n    \"\"\"\n\n    @classmethod\n    def is_deployed(cls):\n\"\"\"\n        Flags that Cancun has not been deployed to mainnet; it is under active\n        development.\n        \"\"\"\n        return False\n\n    @classmethod\n    def header_excess_data_gas_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n        Excess data gas is required starting from Cancun.\n        \"\"\"\n        return True\n\n    @classmethod\n    def header_data_gas_used_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n        Data gas used is required starting from Cancun.\n        \"\"\"\n        return True\n\n    @classmethod\n    def engine_new_payload_version(cls, block_number: int, timestamp: int) -> Optional[int]:\n\"\"\"\n        Starting at Cancun, new payload calls must use version 3\n        \"\"\"\n        return 3\n\n    @classmethod\n    def engine_new_payload_blob_hashes(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n        Starting at Cancun, payloads must have blob hashes.\n        \"\"\"\n        return True\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.Cancun.is_deployed","title":"is_deployed() classmethod","text":"

Flags that Cancun has not been deployed to mainnet; it is under active development.

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef is_deployed(cls):\n\"\"\"\n    Flags that Cancun has not been deployed to mainnet; it is under active\n    development.\n    \"\"\"\n    return False\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.Cancun.header_excess_data_gas_required","title":"header_excess_data_gas_required(block_number, timestamp) classmethod","text":"

Excess data gas is required starting from Cancun.

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef header_excess_data_gas_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n    Excess data gas is required starting from Cancun.\n    \"\"\"\n    return True\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.Cancun.header_data_gas_used_required","title":"header_data_gas_used_required(block_number, timestamp) classmethod","text":"

Data gas used is required starting from Cancun.

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef header_data_gas_used_required(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n    Data gas used is required starting from Cancun.\n    \"\"\"\n    return True\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.Cancun.engine_new_payload_version","title":"engine_new_payload_version(block_number, timestamp) classmethod","text":"

Starting at Cancun, new payload calls must use version 3

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef engine_new_payload_version(cls, block_number: int, timestamp: int) -> Optional[int]:\n\"\"\"\n    Starting at Cancun, new payload calls must use version 3\n    \"\"\"\n    return 3\n
"},{"location":"library/ethereum_test_forks/#ethereum_test_forks.forks.forks.Cancun.engine_new_payload_blob_hashes","title":"engine_new_payload_blob_hashes(block_number, timestamp) classmethod","text":"

Starting at Cancun, payloads must have blob hashes.

Source code in src/ethereum_test_forks/forks/forks.py
@classmethod\ndef engine_new_payload_blob_hashes(cls, block_number: int, timestamp: int) -> bool:\n\"\"\"\n    Starting at Cancun, payloads must have blob hashes.\n    \"\"\"\n    return True\n
"},{"location":"library/ethereum_test_tools/","title":"Ethereum Test Tools Package","text":"

Module containing tools for generating cross-client Ethereum execution layer tests.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.Code","title":"Code dataclass","text":"

Generic code object.

Source code in src/ethereum_test_tools/code/code.py
@dataclass(kw_only=True)\nclass Code:\n\"\"\"\n    Generic code object.\n    \"\"\"\n\n    bytecode: Optional[bytes] = None\n\"\"\"\n    bytes array that represents the bytecode of this object.\n    \"\"\"\n    name: Optional[str] = None\n\"\"\"\n    Name used to describe this code.\n    Usually used to add extra information to a test case.\n    \"\"\"\n\n    def assemble(self) -> bytes:\n\"\"\"\n        Transform the Code object into bytes.\n        Normally will be overriden by the classes that inherit this class.\n        \"\"\"\n        if self.bytecode is None:\n            return bytes()\n        else:\n            return self.bytecode\n\n    def __add__(self, other: Union[str, bytes, \"Code\"]) -> \"Code\":\n\"\"\"\n        Adds two code objects together, by converting both to bytes first.\n        \"\"\"\n        return Code(bytecode=(code_to_bytes(self) + code_to_bytes(other)))\n\n    def __radd__(self, other: Union[str, bytes, \"Code\"]) -> \"Code\":\n\"\"\"\n        Adds two code objects together, by converting both to bytes first.\n        \"\"\"\n        return Code(bytecode=(code_to_bytes(other) + code_to_bytes(self)))\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.code.code.Code.bytecode","title":"bytecode: Optional[bytes] = None instance-attribute class-attribute","text":"

bytes array that represents the bytecode of this object.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.code.code.Code.name","title":"name: Optional[str] = None instance-attribute class-attribute","text":"

Name used to describe this code. Usually used to add extra information to a test case.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.code.code.Code.assemble","title":"assemble()","text":"

Transform the Code object into bytes. Normally will be overriden by the classes that inherit this class.

Source code in src/ethereum_test_tools/code/code.py
def assemble(self) -> bytes:\n\"\"\"\n    Transform the Code object into bytes.\n    Normally will be overriden by the classes that inherit this class.\n    \"\"\"\n    if self.bytecode is None:\n        return bytes()\n    else:\n        return self.bytecode\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.code.code.Code.__add__","title":"__add__(other)","text":"

Adds two code objects together, by converting both to bytes first.

Source code in src/ethereum_test_tools/code/code.py
def __add__(self, other: Union[str, bytes, \"Code\"]) -> \"Code\":\n\"\"\"\n    Adds two code objects together, by converting both to bytes first.\n    \"\"\"\n    return Code(bytecode=(code_to_bytes(self) + code_to_bytes(other)))\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.code.code.Code.__radd__","title":"__radd__(other)","text":"

Adds two code objects together, by converting both to bytes first.

Source code in src/ethereum_test_tools/code/code.py
def __radd__(self, other: Union[str, bytes, \"Code\"]) -> \"Code\":\n\"\"\"\n    Adds two code objects together, by converting both to bytes first.\n    \"\"\"\n    return Code(bytecode=(code_to_bytes(other) + code_to_bytes(self)))\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.Initcode","title":"Initcode","text":"

Bases: Code

Helper class used to generate initcode for the specified deployment code.

The execution gas cost of the initcode is calculated, and also the deployment gas costs for the deployed code.

The initcode can be padded to a certain length if necessary, which does not affect the deployed code.

Other costs such as the CREATE2 hashing costs or the initcode_word_cost of EIP-3860 are not taken into account by any of these calculated costs.

Source code in src/ethereum_test_tools/code/generators.py
class Initcode(Code):\n\"\"\"\n    Helper class used to generate initcode for the specified deployment code.\n\n    The execution gas cost of the initcode is calculated, and also the\n    deployment gas costs for the deployed code.\n\n    The initcode can be padded to a certain length if necessary, which\n    does not affect the deployed code.\n\n    Other costs such as the CREATE2 hashing costs or the initcode_word_cost\n    of EIP-3860 are *not* taken into account by any of these calculated\n    costs.\n    \"\"\"\n\n    deploy_code: bytes | str | Code\n\"\"\"\n    Bytecode to be deployed by the initcode.\n    \"\"\"\n    execution_gas: int\n\"\"\"\n    Gas cost of executing the initcode, without considering deployment gas\n    costs.\n    \"\"\"\n    deployment_gas: int\n\"\"\"\n    Gas cost of deploying the cost, subtracted after initcode execution,\n    \"\"\"\n\n    def __init__(\n        self,\n        *,\n        deploy_code: str | bytes | Code,\n        initcode_length: Optional[int] = None,\n        padding_byte: int = 0x00,\n        name: Optional[str] = None,\n    ):\n\"\"\"\n        Generate legacy initcode that inits a contract with the specified code.\n        The initcode can be padded to a specified length for testing purposes.\n        \"\"\"\n        self.execution_gas = 0\n        self.deploy_code = deploy_code\n        deploy_code_bytes = code_to_bytes(self.deploy_code)\n        code_length = len(deploy_code_bytes)\n\n        initcode = bytearray()\n\n        # PUSH2: length=<bytecode length>\n        initcode.append(0x61)\n        initcode += code_length.to_bytes(length=2, byteorder=\"big\")\n        self.execution_gas += 3\n\n        # PUSH1: offset=0\n        initcode.append(0x60)\n        initcode.append(0x00)\n        self.execution_gas += 3\n\n        # DUP2\n        initcode.append(0x81)\n        self.execution_gas += 3\n\n        # PUSH1: initcode_length=11 (constant)\n        initcode.append(0x60)\n        initcode.append(0x0B)\n        self.execution_gas += 3\n\n        # DUP3\n        initcode.append(0x82)\n        self.execution_gas += 3\n\n        # CODECOPY: destinationOffset=0, offset=0, length\n        initcode.append(0x39)\n        self.execution_gas += (\n            3\n            + (3 * ceiling_division(code_length, 32))\n            + (3 * code_length)\n            + ((code_length * code_length) // 512)\n        )\n\n        # RETURN: offset=0, length\n        initcode.append(0xF3)\n        self.execution_gas += 0\n\n        pre_padding_bytes = bytes(initcode) + deploy_code_bytes\n\n        if initcode_length is not None:\n            if len(pre_padding_bytes) > initcode_length:\n                raise Exception(\"Invalid specified length for initcode\")\n\n            padding_bytes = bytes([padding_byte] * (initcode_length - len(pre_padding_bytes)))\n        else:\n            padding_bytes = bytes()\n\n        self.deployment_gas = GAS_PER_DEPLOYED_CODE_BYTE * len(deploy_code_bytes)\n\n        super().__init__(bytecode=pre_padding_bytes + padding_bytes, name=name)\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.code.generators.Initcode.__init__","title":"__init__(*, deploy_code, initcode_length=None, padding_byte=0, name=None)","text":"

Generate legacy initcode that inits a contract with the specified code. The initcode can be padded to a specified length for testing purposes.

Source code in src/ethereum_test_tools/code/generators.py
def __init__(\n    self,\n    *,\n    deploy_code: str | bytes | Code,\n    initcode_length: Optional[int] = None,\n    padding_byte: int = 0x00,\n    name: Optional[str] = None,\n):\n\"\"\"\n    Generate legacy initcode that inits a contract with the specified code.\n    The initcode can be padded to a specified length for testing purposes.\n    \"\"\"\n    self.execution_gas = 0\n    self.deploy_code = deploy_code\n    deploy_code_bytes = code_to_bytes(self.deploy_code)\n    code_length = len(deploy_code_bytes)\n\n    initcode = bytearray()\n\n    # PUSH2: length=<bytecode length>\n    initcode.append(0x61)\n    initcode += code_length.to_bytes(length=2, byteorder=\"big\")\n    self.execution_gas += 3\n\n    # PUSH1: offset=0\n    initcode.append(0x60)\n    initcode.append(0x00)\n    self.execution_gas += 3\n\n    # DUP2\n    initcode.append(0x81)\n    self.execution_gas += 3\n\n    # PUSH1: initcode_length=11 (constant)\n    initcode.append(0x60)\n    initcode.append(0x0B)\n    self.execution_gas += 3\n\n    # DUP3\n    initcode.append(0x82)\n    self.execution_gas += 3\n\n    # CODECOPY: destinationOffset=0, offset=0, length\n    initcode.append(0x39)\n    self.execution_gas += (\n        3\n        + (3 * ceiling_division(code_length, 32))\n        + (3 * code_length)\n        + ((code_length * code_length) // 512)\n    )\n\n    # RETURN: offset=0, length\n    initcode.append(0xF3)\n    self.execution_gas += 0\n\n    pre_padding_bytes = bytes(initcode) + deploy_code_bytes\n\n    if initcode_length is not None:\n        if len(pre_padding_bytes) > initcode_length:\n            raise Exception(\"Invalid specified length for initcode\")\n\n        padding_bytes = bytes([padding_byte] * (initcode_length - len(pre_padding_bytes)))\n    else:\n        padding_bytes = bytes()\n\n    self.deployment_gas = GAS_PER_DEPLOYED_CODE_BYTE * len(deploy_code_bytes)\n\n    super().__init__(bytecode=pre_padding_bytes + padding_bytes, name=name)\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.code.generators.Initcode.execution_gas","title":"execution_gas: int = 0 instance-attribute","text":"

Gas cost of executing the initcode, without considering deployment gas costs.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.code.generators.Initcode.deploy_code","title":"deploy_code: bytes | str | Code = deploy_code instance-attribute","text":"

Bytecode to be deployed by the initcode.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.code.generators.Initcode.deployment_gas","title":"deployment_gas: int = GAS_PER_DEPLOYED_CODE_BYTE * len(deploy_code_bytes) instance-attribute","text":"

Gas cost of deploying the cost, subtracted after initcode execution,

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.ceiling_division","title":"ceiling_division(a, b)","text":"

Calculates the ceil without using floating point. Used by many of the EVM's formulas

Source code in src/ethereum_test_tools/common/helpers.py
def ceiling_division(a: int, b: int) -> int:\n\"\"\"\n    Calculates the ceil without using floating point.\n    Used by many of the EVM's formulas\n    \"\"\"\n    return -(a // -b)\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.fill_test","title":"fill_test(t8n, test_spec, fork, engine, spec, eips=None)","text":"

Fills fixtures for the specified fork.

Source code in src/ethereum_test_tools/filling/fill.py
def fill_test(\n    t8n: TransitionTool,\n    test_spec: BaseTest,\n    fork: Fork,\n    engine: str,\n    spec: ReferenceSpec | None,\n    eips: Optional[List[int]] = None,\n) -> Fixture:\n\"\"\"\n    Fills fixtures for the specified fork.\n    \"\"\"\n    t8n.reset_traces()\n\n    genesis_rlp, genesis = test_spec.make_genesis(t8n, fork)\n\n    (blocks, head, alloc) = test_spec.make_blocks(\n        t8n,\n        genesis,\n        fork,\n        eips=eips,\n    )\n\n    fork_name = fork.name()\n    fixture = Fixture(\n        blocks=blocks,\n        genesis=genesis,\n        genesis_rlp=genesis_rlp,\n        head=head,\n        fork=\"+\".join([fork_name] + [str(eip) for eip in eips]) if eips is not None else fork_name,\n        pre_state=copy(test_spec.pre),\n        post_state=alloc_to_accounts(alloc),\n        seal_engine=engine,\n        name=test_spec.tag,\n    )\n    fixture.fill_info(t8n, spec)\n\n    return fixture\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.compute_create_address","title":"compute_create_address(address, nonce)","text":"

Compute address of the resulting contract created using a transaction or the CREATE opcode.

Source code in src/ethereum_test_tools/common/helpers.py
def compute_create_address(address: str | int, nonce: int) -> str:\n\"\"\"\n    Compute address of the resulting contract created using a transaction\n    or the `CREATE` opcode.\n    \"\"\"\n    if type(address) is str:\n        if address.startswith(\"0x\"):\n            address = address[2:]\n        address_bytes = bytes.fromhex(address)\n    elif type(address) is int:\n        address_bytes = address.to_bytes(length=20, byteorder=\"big\")\n    if nonce == 0:\n        nonce_bytes = bytes()\n    else:\n        nonce_bytes = nonce.to_bytes(length=1, byteorder=\"big\")\n    hash = keccak256(encode([address_bytes, nonce_bytes]))\n    return \"0x\" + hash[-20:].hex()\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.EngineAPIError","title":"EngineAPIError","text":"

Bases: IntEnum

List of Engine API errors

Source code in src/ethereum_test_tools/common/constants.py
class EngineAPIError(IntEnum):\n\"\"\"\n    List of Engine API errors\n    \"\"\"\n\n    ParseError = -32700\n    InvalidRequest = -32600\n    MethodNotFound = -32601\n    InvalidParams = -32602\n    InternalError = -32603\n    ServerError = -32000\n    UnknownPayload = -38001\n    InvalidForkchoiceState = -38002\n    InvalidPayloadAttributes = -38003\n    TooLargeRequest = -38004\n    UnsupportedFork = -38005\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.Opcode","title":"Opcode","text":"

Bases: bytes

Represents a single Opcode instruction in the EVM, with extra metadata useful to parametrize tests.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.Opcode--parameters","title":"Parameters","text":"
  • popped_stack_items: number of items the opcode pops from the stack
  • pushed_stack_items: number of items the opcode pushes to the stack
  • min_stack_height: minimum stack height required by the opcode
  • data_portion_length: number of bytes after the opcode in the bytecode that represent data
Source code in src/ethereum_test_tools/vm/opcode.py
class Opcode(bytes):\n\"\"\"\n    Represents a single Opcode instruction in the EVM, with extra\n    metadata useful to parametrize tests.\n\n    Parameters\n    ----------\n    - popped_stack_items: number of items the opcode pops from the stack\n    - pushed_stack_items: number of items the opcode pushes to the stack\n    - min_stack_height: minimum stack height required by the opcode\n    - data_portion_length: number of bytes after the opcode in the bytecode\n        that represent data\n    \"\"\"\n\n    popped_stack_items: int\n    pushed_stack_items: int\n    min_stack_height: int\n    data_portion_length: int\n    _name_: str\n\n    def __new__(\n        cls,\n        opcode_or_byte: Union[int, \"Opcode\"],\n        *,\n        popped_stack_items: int = 0,\n        pushed_stack_items: int = 0,\n        min_stack_height: int = 0,\n        data_portion_length: int = 0,\n    ):\n\"\"\"\n        Creates a new opcode instance.\n        \"\"\"\n        if type(opcode_or_byte) is Opcode:\n            # Required because Enum class calls the base class with the\n            # instantiated object as parameter.\n            return opcode_or_byte\n        elif isinstance(opcode_or_byte, int):\n            obj = super().__new__(cls, [opcode_or_byte])\n            obj.popped_stack_items = popped_stack_items\n            obj.pushed_stack_items = pushed_stack_items\n            obj.min_stack_height = min_stack_height\n            obj.data_portion_length = data_portion_length\n            return obj\n\n    def __call__(self, *args_t: Union[int, bytes, \"Opcode\"]) -> bytes:\n\"\"\"\n        Makes all opcode instances callable to return formatted bytecode,\n        which constitutes a data portion, that is located after the opcode\n        byte, and pre-opcode bytecode, which is normally used to set up the\n        stack.\n\n        This useful to automatically format, e.g., push opcodes and their\n        data sections as `Opcodes.PUSH1(0x00)`.\n\n        Data sign is automatically detected but for this reason the range\n        of the input must be:\n        `[-2^(data_portion_bits-1), 2^(data_portion_bits)]`\n        where:\n        `data_portion_bits == data_portion_length * 8`\n\n        For the stack, the arguments are set up in the opposite order they are\n        given, so the first argument is the last item pushed to the stack.\n\n        The resulting stack arrangement does not take into account opcode stack\n        element consumption, so the stack height is not guaranteed to be\n        correct and the user must take this into consideration.\n\n        Integers can also be used as stack elements, in which case they are\n        automatically converted to PUSH operations, and negative numbers always\n        use a PUSH32 operation.\n\n\n        \"\"\"\n        args: List[Union[int, bytes, \"Opcode\"]] = list(args_t)\n        pre_opcode_bytecode = bytes()\n        data_portion = bytes()\n\n        if self.data_portion_length > 0:\n            # For opcodes with a data portion, the first argument is the data\n            # and the rest of the arguments form the stack.\n            if len(args) == 0:\n                raise ValueError(\"Opcode with data portion requires at least one argument\")\n            data = args.pop(0)\n            if isinstance(data, bytes):\n                data_portion = data\n            elif isinstance(data, int):\n                signed = data < 0\n                data_portion = data.to_bytes(\n                    length=self.data_portion_length,\n                    byteorder=\"big\",\n                    signed=signed,\n                )\n            else:\n                raise TypeError(\"Opcode data portion must be either an int or a bytes\")\n\n        # The rest of the arguments conform the stack.\n        while len(args) > 0:\n            data = args.pop()\n            if isinstance(data, bytes):\n                pre_opcode_bytecode += data\n            elif isinstance(data, int):\n                # We are going to push a constant to the stack.\n                signed = data < 0\n                data_size = _get_int_size(data)\n                if data_size > 32:\n                    raise ValueError(\"Opcode stack data must be less than 32 bytes\")\n                elif data_size == 0:\n                    # Pushing 0 is done with the PUSH1 opcode for compatibility\n                    # reasons.\n                    data_size = 1\n\n                pre_opcode_bytecode += _push_opcodes_byte_list[data_size]\n                pre_opcode_bytecode += data.to_bytes(\n                    length=data_size,\n                    byteorder=\"big\",\n                    signed=signed,\n                )\n\n            else:\n                raise TypeError(\"Opcode stack data must be either an int or a bytes\")\n\n        return pre_opcode_bytecode + self + data_portion\n\n    def __len__(self) -> int:\n\"\"\"\n        Returns the total bytecode length of the opcode, taking into account\n        its data portion.\n        \"\"\"\n        return self.data_portion_length + 1\n\n    def int(self) -> int:\n\"\"\"\n        Returns the integer representation of the opcode.\n        \"\"\"\n        return int.from_bytes(bytes=self, byteorder=\"big\")\n\n    def __str__(self) -> str:\n\"\"\"\n        Return the name of the opcode, assigned at Enum creation.\n        \"\"\"\n        return self._name_\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.vm.opcode.Opcode.__new__","title":"__new__(opcode_or_byte, *, popped_stack_items=0, pushed_stack_items=0, min_stack_height=0, data_portion_length=0)","text":"

Creates a new opcode instance.

Source code in src/ethereum_test_tools/vm/opcode.py
def __new__(\n    cls,\n    opcode_or_byte: Union[int, \"Opcode\"],\n    *,\n    popped_stack_items: int = 0,\n    pushed_stack_items: int = 0,\n    min_stack_height: int = 0,\n    data_portion_length: int = 0,\n):\n\"\"\"\n    Creates a new opcode instance.\n    \"\"\"\n    if type(opcode_or_byte) is Opcode:\n        # Required because Enum class calls the base class with the\n        # instantiated object as parameter.\n        return opcode_or_byte\n    elif isinstance(opcode_or_byte, int):\n        obj = super().__new__(cls, [opcode_or_byte])\n        obj.popped_stack_items = popped_stack_items\n        obj.pushed_stack_items = pushed_stack_items\n        obj.min_stack_height = min_stack_height\n        obj.data_portion_length = data_portion_length\n        return obj\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.vm.opcode.Opcode.__call__","title":"__call__(*args_t)","text":"

Makes all opcode instances callable to return formatted bytecode, which constitutes a data portion, that is located after the opcode byte, and pre-opcode bytecode, which is normally used to set up the stack.

This useful to automatically format, e.g., push opcodes and their data sections as Opcodes.PUSH1(0x00).

Data sign is automatically detected but for this reason the range of the input must be: [-2^(data_portion_bits-1), 2^(data_portion_bits)] where: data_portion_bits == data_portion_length * 8

For the stack, the arguments are set up in the opposite order they are given, so the first argument is the last item pushed to the stack.

The resulting stack arrangement does not take into account opcode stack element consumption, so the stack height is not guaranteed to be correct and the user must take this into consideration.

Integers can also be used as stack elements, in which case they are automatically converted to PUSH operations, and negative numbers always use a PUSH32 operation.

Source code in src/ethereum_test_tools/vm/opcode.py
def __call__(self, *args_t: Union[int, bytes, \"Opcode\"]) -> bytes:\n\"\"\"\n    Makes all opcode instances callable to return formatted bytecode,\n    which constitutes a data portion, that is located after the opcode\n    byte, and pre-opcode bytecode, which is normally used to set up the\n    stack.\n\n    This useful to automatically format, e.g., push opcodes and their\n    data sections as `Opcodes.PUSH1(0x00)`.\n\n    Data sign is automatically detected but for this reason the range\n    of the input must be:\n    `[-2^(data_portion_bits-1), 2^(data_portion_bits)]`\n    where:\n    `data_portion_bits == data_portion_length * 8`\n\n    For the stack, the arguments are set up in the opposite order they are\n    given, so the first argument is the last item pushed to the stack.\n\n    The resulting stack arrangement does not take into account opcode stack\n    element consumption, so the stack height is not guaranteed to be\n    correct and the user must take this into consideration.\n\n    Integers can also be used as stack elements, in which case they are\n    automatically converted to PUSH operations, and negative numbers always\n    use a PUSH32 operation.\n\n\n    \"\"\"\n    args: List[Union[int, bytes, \"Opcode\"]] = list(args_t)\n    pre_opcode_bytecode = bytes()\n    data_portion = bytes()\n\n    if self.data_portion_length > 0:\n        # For opcodes with a data portion, the first argument is the data\n        # and the rest of the arguments form the stack.\n        if len(args) == 0:\n            raise ValueError(\"Opcode with data portion requires at least one argument\")\n        data = args.pop(0)\n        if isinstance(data, bytes):\n            data_portion = data\n        elif isinstance(data, int):\n            signed = data < 0\n            data_portion = data.to_bytes(\n                length=self.data_portion_length,\n                byteorder=\"big\",\n                signed=signed,\n            )\n        else:\n            raise TypeError(\"Opcode data portion must be either an int or a bytes\")\n\n    # The rest of the arguments conform the stack.\n    while len(args) > 0:\n        data = args.pop()\n        if isinstance(data, bytes):\n            pre_opcode_bytecode += data\n        elif isinstance(data, int):\n            # We are going to push a constant to the stack.\n            signed = data < 0\n            data_size = _get_int_size(data)\n            if data_size > 32:\n                raise ValueError(\"Opcode stack data must be less than 32 bytes\")\n            elif data_size == 0:\n                # Pushing 0 is done with the PUSH1 opcode for compatibility\n                # reasons.\n                data_size = 1\n\n            pre_opcode_bytecode += _push_opcodes_byte_list[data_size]\n            pre_opcode_bytecode += data.to_bytes(\n                length=data_size,\n                byteorder=\"big\",\n                signed=signed,\n            )\n\n        else:\n            raise TypeError(\"Opcode stack data must be either an int or a bytes\")\n\n    return pre_opcode_bytecode + self + data_portion\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.vm.opcode.Opcode.__len__","title":"__len__()","text":"

Returns the total bytecode length of the opcode, taking into account its data portion.

Source code in src/ethereum_test_tools/vm/opcode.py
def __len__(self) -> int:\n\"\"\"\n    Returns the total bytecode length of the opcode, taking into account\n    its data portion.\n    \"\"\"\n    return self.data_portion_length + 1\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.vm.opcode.Opcode.int","title":"int()","text":"

Returns the integer representation of the opcode.

Source code in src/ethereum_test_tools/vm/opcode.py
def int(self) -> int:\n\"\"\"\n    Returns the integer representation of the opcode.\n    \"\"\"\n    return int.from_bytes(bytes=self, byteorder=\"big\")\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.vm.opcode.Opcode.__str__","title":"__str__()","text":"

Return the name of the opcode, assigned at Enum creation.

Source code in src/ethereum_test_tools/vm/opcode.py
def __str__(self) -> str:\n\"\"\"\n    Return the name of the opcode, assigned at Enum creation.\n    \"\"\"\n    return self._name_\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.BlockchainTest","title":"BlockchainTest dataclass","text":"

Bases: BaseTest

Filler type that tests multiple blocks (valid or invalid) in a chain.

Source code in src/ethereum_test_tools/spec/blockchain_test.py
@dataclass(kw_only=True)\nclass BlockchainTest(BaseTest):\n\"\"\"\n    Filler type that tests multiple blocks (valid or invalid) in a chain.\n    \"\"\"\n\n    pre: Mapping[str, Account]\n    post: Mapping[str, Account]\n    blocks: List[Block]\n    genesis_environment: Environment = field(default_factory=Environment)\n    tag: str = \"\"\n\n    @classmethod\n    def pytest_parameter_name(cls) -> str:\n\"\"\"\n        Returns the parameter name used to identify this filler in a test.\n        \"\"\"\n        return \"blockchain_test\"\n\n    def make_genesis(\n        self,\n        t8n: TransitionTool,\n        fork: Fork,\n    ) -> Tuple[bytes, FixtureHeader]:\n\"\"\"\n        Create a genesis block from the state test definition.\n        \"\"\"\n        env = self.genesis_environment.set_fork_requirements(fork)\n\n        genesis = FixtureHeader(\n            parent_hash=EmptyHash,\n            ommers_hash=EmptyOmmersRoot,\n            coinbase=ZeroAddress,\n            state_root=t8n.calc_state_root(\n                to_json(self.pre),\n                fork,\n            ),\n            transactions_root=EmptyTrieRoot,\n            receipt_root=EmptyTrieRoot,\n            bloom=EmptyBloom,\n            difficulty=0x20000 if env.difficulty is None else env.difficulty,\n            number=0,\n            gas_limit=env.gas_limit,\n            gas_used=0,\n            timestamp=0,\n            extra_data=bytes([0]),\n            mix_digest=EmptyHash,\n            nonce=EmptyNonce,\n            base_fee=env.base_fee,\n            data_gas_used=env.data_gas_used,\n            excess_data_gas=env.excess_data_gas,\n            withdrawals_root=t8n.calc_withdrawals_root(env.withdrawals, fork)\n            if env.withdrawals is not None\n            else None,\n        )\n\n        genesis_rlp, genesis.hash = genesis.build(\n            txs=[],\n            ommers=[],\n            withdrawals=env.withdrawals,\n        )\n\n        return genesis_rlp, genesis\n\n    def make_block(\n        self,\n        t8n: TransitionTool,\n        fork: Fork,\n        block: Block,\n        previous_env: Environment,\n        previous_alloc: Dict[str, Any],\n        previous_head: bytes,\n        chain_id=1,\n        eips: Optional[List[int]] = None,\n    ) -> Tuple[FixtureBlock, Environment, Dict[str, Any], bytes]:\n\"\"\"\n        Produces a block based on the previous environment and allocation.\n        If the block is an invalid block, the environment and allocation\n        returned are the same as passed as parameters.\n        Raises exception on invalid test behavior.\n\n        Returns\n        -------\n            FixtureBlock: Block to be appended to the fixture.\n            Environment: Environment for the next block to produce.\n                If the produced block is invalid, this is exactly the same\n                environment as the one passed as parameter.\n            Dict[str, Any]: Allocation for the next block to produce.\n                If the produced block is invalid, this is exactly the same\n                allocation as the one passed as parameter.\n            str: Hash of the head of the chain, only updated if the produced\n                block is not invalid.\n\n        \"\"\"\n        if block.rlp and block.exception is not None:\n            raise Exception(\n                \"test correctness: post-state cannot be verified if the \"\n                + \"block's rlp is supplied and the block is not supposed \"\n                + \"to produce an exception\"\n            )\n\n        if block.rlp is None:\n            # This is the most common case, the RLP needs to be constructed\n            # based on the transactions to be included in the block.\n            # Set the environment according to the block to execute.\n            env = block.set_environment(previous_env)\n            env = env.set_fork_requirements(fork)\n\n            txs = (\n                [tx.with_signature_and_sender() for tx in block.txs]\n                if block.txs is not None\n                else []\n            )\n\n            next_alloc, result = t8n.evaluate(\n                alloc=previous_alloc,\n                txs=to_json_or_none(txs),\n                env=to_json(env),\n                fork=fork,\n                chain_id=chain_id,\n                reward=fork.get_reward(env.number, env.timestamp),\n                eips=eips,\n            )\n            try:\n                rejected_txs = verify_transactions(txs, result)\n            except Exception as e:\n                print_traces(t8n.get_traces())\n                pprint(result)\n                pprint(previous_alloc)\n                pprint(next_alloc)\n                raise e\n\n            if len(rejected_txs) > 0 and block.exception is None:\n                print_traces(t8n.get_traces())\n                raise Exception(\n                    \"one or more transactions in `BlockchainTest` are \"\n                    + \"intrinsically invalid, but the block was not expected \"\n                    + \"to be invalid. Please verify whether the transaction \"\n                    + \"was indeed expected to fail and add the proper \"\n                    + \"`block.exception`\"\n                )\n\n            header = FixtureHeader.from_dict(\n                result\n                | {\n                    \"parentHash\": env.parent_hash(),\n                    \"miner\": env.coinbase,\n                    \"transactionsRoot\": result.get(\"txRoot\"),\n                    \"difficulty\": str_or_none(result.get(\"currentDifficulty\"), \"0\"),\n                    \"number\": str(env.number),\n                    \"gasLimit\": str(env.gas_limit),\n                    \"timestamp\": str(env.timestamp),\n                    \"extraData\": block.extra_data\n                    if block.extra_data is not None and len(block.extra_data) != 0\n                    else \"0x\",\n                    \"sha3Uncles\": \"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",  # noqa: E501\n                    \"mixHash\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",  # noqa: E501\n                    \"nonce\": \"0x0000000000000000\",\n                    \"baseFeePerGas\": result.get(\"currentBaseFee\"),\n                    \"excessDataGas\": result.get(\"currentExcessDataGas\"),\n                }\n            )\n\n            assert len(header.state_root) == 32\n\n            if block.rlp_modifier is not None:\n                # Modify any parameter specified in the `rlp_modifier` after\n                # transition tool processing.\n                header = header.join(block.rlp_modifier)\n\n            rlp, header.hash = header.build(\n                txs=txs,\n                ommers=[],\n                withdrawals=env.withdrawals,\n            )\n\n            new_payload = FixtureEngineNewPayload.from_fixture_header(\n                fork=fork,\n                header=header,\n                transactions=txs,\n                withdrawals=env.withdrawals,\n                error_code=block.engine_api_error_code,\n            )\n\n            if block.exception is None:\n                # Return environment and allocation of the following block\n                return (\n                    FixtureBlock(\n                        rlp=rlp,\n                        new_payload=new_payload,\n                        block_header=header,\n                        block_number=header.number,\n                        txs=txs,\n                        ommers=[],\n                        withdrawals=env.withdrawals,\n                    ),\n                    env.apply_new_parent(header),\n                    next_alloc,\n                    header.hash,\n                )\n            else:\n                return (\n                    FixtureBlock(\n                        rlp=rlp,\n                        new_payload=new_payload,\n                        expected_exception=block.exception,\n                        block_number=header.number,\n                    ),\n                    previous_env,\n                    previous_alloc,\n                    previous_head,\n                )\n        else:\n            return (\n                FixtureBlock(\n                    rlp=block.rlp,\n                    expected_exception=block.exception,\n                ),\n                previous_env,\n                previous_alloc,\n                previous_head,\n            )\n\n    def make_blocks(\n        self,\n        t8n: TransitionTool,\n        genesis: FixtureHeader,\n        fork: Fork,\n        chain_id=1,\n        eips: Optional[List[int]] = None,\n    ) -> Tuple[List[FixtureBlock], bytes, Dict[str, Any]]:\n\"\"\"\n        Create a block list from the blockchain test definition.\n        Performs checks against the expected behavior of the test.\n        Raises exception on invalid test behavior.\n        \"\"\"\n        alloc = to_json(self.pre)\n        env = Environment.from_parent_header(genesis)\n        blocks: List[FixtureBlock] = []\n        head = genesis.hash if genesis.hash is not None else bytes([0] * 32)\n        for block in self.blocks:\n            fixture_block, env, alloc, head = self.make_block(\n                t8n=t8n,\n                fork=fork,\n                block=block,\n                previous_env=env,\n                previous_alloc=alloc,\n                previous_head=head,\n                chain_id=chain_id,\n                eips=eips,\n            )\n            blocks.append(fixture_block)\n\n        try:\n            verify_post_alloc(self.post, alloc)\n        except Exception as e:\n            print_traces(t8n.get_traces())\n            raise e\n\n        return (blocks, head, alloc)\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.spec.blockchain_test.BlockchainTest.pytest_parameter_name","title":"pytest_parameter_name() classmethod","text":"

Returns the parameter name used to identify this filler in a test.

Source code in src/ethereum_test_tools/spec/blockchain_test.py
@classmethod\ndef pytest_parameter_name(cls) -> str:\n\"\"\"\n    Returns the parameter name used to identify this filler in a test.\n    \"\"\"\n    return \"blockchain_test\"\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.spec.blockchain_test.BlockchainTest.make_genesis","title":"make_genesis(t8n, fork)","text":"

Create a genesis block from the state test definition.

Source code in src/ethereum_test_tools/spec/blockchain_test.py
def make_genesis(\n    self,\n    t8n: TransitionTool,\n    fork: Fork,\n) -> Tuple[bytes, FixtureHeader]:\n\"\"\"\n    Create a genesis block from the state test definition.\n    \"\"\"\n    env = self.genesis_environment.set_fork_requirements(fork)\n\n    genesis = FixtureHeader(\n        parent_hash=EmptyHash,\n        ommers_hash=EmptyOmmersRoot,\n        coinbase=ZeroAddress,\n        state_root=t8n.calc_state_root(\n            to_json(self.pre),\n            fork,\n        ),\n        transactions_root=EmptyTrieRoot,\n        receipt_root=EmptyTrieRoot,\n        bloom=EmptyBloom,\n        difficulty=0x20000 if env.difficulty is None else env.difficulty,\n        number=0,\n        gas_limit=env.gas_limit,\n        gas_used=0,\n        timestamp=0,\n        extra_data=bytes([0]),\n        mix_digest=EmptyHash,\n        nonce=EmptyNonce,\n        base_fee=env.base_fee,\n        data_gas_used=env.data_gas_used,\n        excess_data_gas=env.excess_data_gas,\n        withdrawals_root=t8n.calc_withdrawals_root(env.withdrawals, fork)\n        if env.withdrawals is not None\n        else None,\n    )\n\n    genesis_rlp, genesis.hash = genesis.build(\n        txs=[],\n        ommers=[],\n        withdrawals=env.withdrawals,\n    )\n\n    return genesis_rlp, genesis\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.spec.blockchain_test.BlockchainTest.make_block","title":"make_block(t8n, fork, block, previous_env, previous_alloc, previous_head, chain_id=1, eips=None)","text":"

Produces a block based on the previous environment and allocation. If the block is an invalid block, the environment and allocation returned are the same as passed as parameters. Raises exception on invalid test behavior.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.spec.blockchain_test.BlockchainTest.make_block--returns","title":"Returns","text":"
FixtureBlock: Block to be appended to the fixture.\nEnvironment: Environment for the next block to produce.\n    If the produced block is invalid, this is exactly the same\n    environment as the one passed as parameter.\nDict[str, Any]: Allocation for the next block to produce.\n    If the produced block is invalid, this is exactly the same\n    allocation as the one passed as parameter.\nstr: Hash of the head of the chain, only updated if the produced\n    block is not invalid.\n
Source code in src/ethereum_test_tools/spec/blockchain_test.py
def make_block(\n    self,\n    t8n: TransitionTool,\n    fork: Fork,\n    block: Block,\n    previous_env: Environment,\n    previous_alloc: Dict[str, Any],\n    previous_head: bytes,\n    chain_id=1,\n    eips: Optional[List[int]] = None,\n) -> Tuple[FixtureBlock, Environment, Dict[str, Any], bytes]:\n\"\"\"\n    Produces a block based on the previous environment and allocation.\n    If the block is an invalid block, the environment and allocation\n    returned are the same as passed as parameters.\n    Raises exception on invalid test behavior.\n\n    Returns\n    -------\n        FixtureBlock: Block to be appended to the fixture.\n        Environment: Environment for the next block to produce.\n            If the produced block is invalid, this is exactly the same\n            environment as the one passed as parameter.\n        Dict[str, Any]: Allocation for the next block to produce.\n            If the produced block is invalid, this is exactly the same\n            allocation as the one passed as parameter.\n        str: Hash of the head of the chain, only updated if the produced\n            block is not invalid.\n\n    \"\"\"\n    if block.rlp and block.exception is not None:\n        raise Exception(\n            \"test correctness: post-state cannot be verified if the \"\n            + \"block's rlp is supplied and the block is not supposed \"\n            + \"to produce an exception\"\n        )\n\n    if block.rlp is None:\n        # This is the most common case, the RLP needs to be constructed\n        # based on the transactions to be included in the block.\n        # Set the environment according to the block to execute.\n        env = block.set_environment(previous_env)\n        env = env.set_fork_requirements(fork)\n\n        txs = (\n            [tx.with_signature_and_sender() for tx in block.txs]\n            if block.txs is not None\n            else []\n        )\n\n        next_alloc, result = t8n.evaluate(\n            alloc=previous_alloc,\n            txs=to_json_or_none(txs),\n            env=to_json(env),\n            fork=fork,\n            chain_id=chain_id,\n            reward=fork.get_reward(env.number, env.timestamp),\n            eips=eips,\n        )\n        try:\n            rejected_txs = verify_transactions(txs, result)\n        except Exception as e:\n            print_traces(t8n.get_traces())\n            pprint(result)\n            pprint(previous_alloc)\n            pprint(next_alloc)\n            raise e\n\n        if len(rejected_txs) > 0 and block.exception is None:\n            print_traces(t8n.get_traces())\n            raise Exception(\n                \"one or more transactions in `BlockchainTest` are \"\n                + \"intrinsically invalid, but the block was not expected \"\n                + \"to be invalid. Please verify whether the transaction \"\n                + \"was indeed expected to fail and add the proper \"\n                + \"`block.exception`\"\n            )\n\n        header = FixtureHeader.from_dict(\n            result\n            | {\n                \"parentHash\": env.parent_hash(),\n                \"miner\": env.coinbase,\n                \"transactionsRoot\": result.get(\"txRoot\"),\n                \"difficulty\": str_or_none(result.get(\"currentDifficulty\"), \"0\"),\n                \"number\": str(env.number),\n                \"gasLimit\": str(env.gas_limit),\n                \"timestamp\": str(env.timestamp),\n                \"extraData\": block.extra_data\n                if block.extra_data is not None and len(block.extra_data) != 0\n                else \"0x\",\n                \"sha3Uncles\": \"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",  # noqa: E501\n                \"mixHash\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",  # noqa: E501\n                \"nonce\": \"0x0000000000000000\",\n                \"baseFeePerGas\": result.get(\"currentBaseFee\"),\n                \"excessDataGas\": result.get(\"currentExcessDataGas\"),\n            }\n        )\n\n        assert len(header.state_root) == 32\n\n        if block.rlp_modifier is not None:\n            # Modify any parameter specified in the `rlp_modifier` after\n            # transition tool processing.\n            header = header.join(block.rlp_modifier)\n\n        rlp, header.hash = header.build(\n            txs=txs,\n            ommers=[],\n            withdrawals=env.withdrawals,\n        )\n\n        new_payload = FixtureEngineNewPayload.from_fixture_header(\n            fork=fork,\n            header=header,\n            transactions=txs,\n            withdrawals=env.withdrawals,\n            error_code=block.engine_api_error_code,\n        )\n\n        if block.exception is None:\n            # Return environment and allocation of the following block\n            return (\n                FixtureBlock(\n                    rlp=rlp,\n                    new_payload=new_payload,\n                    block_header=header,\n                    block_number=header.number,\n                    txs=txs,\n                    ommers=[],\n                    withdrawals=env.withdrawals,\n                ),\n                env.apply_new_parent(header),\n                next_alloc,\n                header.hash,\n            )\n        else:\n            return (\n                FixtureBlock(\n                    rlp=rlp,\n                    new_payload=new_payload,\n                    expected_exception=block.exception,\n                    block_number=header.number,\n                ),\n                previous_env,\n                previous_alloc,\n                previous_head,\n            )\n    else:\n        return (\n            FixtureBlock(\n                rlp=block.rlp,\n                expected_exception=block.exception,\n            ),\n            previous_env,\n            previous_alloc,\n            previous_head,\n        )\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.spec.blockchain_test.BlockchainTest.make_blocks","title":"make_blocks(t8n, genesis, fork, chain_id=1, eips=None)","text":"

Create a block list from the blockchain test definition. Performs checks against the expected behavior of the test. Raises exception on invalid test behavior.

Source code in src/ethereum_test_tools/spec/blockchain_test.py
def make_blocks(\n    self,\n    t8n: TransitionTool,\n    genesis: FixtureHeader,\n    fork: Fork,\n    chain_id=1,\n    eips: Optional[List[int]] = None,\n) -> Tuple[List[FixtureBlock], bytes, Dict[str, Any]]:\n\"\"\"\n    Create a block list from the blockchain test definition.\n    Performs checks against the expected behavior of the test.\n    Raises exception on invalid test behavior.\n    \"\"\"\n    alloc = to_json(self.pre)\n    env = Environment.from_parent_header(genesis)\n    blocks: List[FixtureBlock] = []\n    head = genesis.hash if genesis.hash is not None else bytes([0] * 32)\n    for block in self.blocks:\n        fixture_block, env, alloc, head = self.make_block(\n            t8n=t8n,\n            fork=fork,\n            block=block,\n            previous_env=env,\n            previous_alloc=alloc,\n            previous_head=head,\n            chain_id=chain_id,\n            eips=eips,\n        )\n        blocks.append(fixture_block)\n\n    try:\n        verify_post_alloc(self.post, alloc)\n    except Exception as e:\n        print_traces(t8n.get_traces())\n        raise e\n\n    return (blocks, head, alloc)\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.ReferenceSpec","title":"ReferenceSpec","text":"

Reference Specification Description Abstract Class.

Source code in src/ethereum_test_tools/reference_spec/reference_spec.py
class ReferenceSpec:\n\"\"\"\n    Reference Specification Description Abstract Class.\n    \"\"\"\n\n    @abstractmethod\n    def name(self) -> str:\n\"\"\"\n        Returns the name of the spec.\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def has_known_version(self) -> bool:\n\"\"\"\n        Returns true if the reference spec object is hard-coded with a latest\n        known version.\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def known_version(self) -> str:\n\"\"\"\n        Returns the latest known version in the reference.\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def api_url(self) -> str:\n\"\"\"\n        Returns the URL required to poll the version from an API, if needed.\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def latest_version(self) -> str:\n\"\"\"\n        Returns a digest that points to the latest version of the spec.\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def is_outdated(self) -> bool:\n\"\"\"\n        Checks whether the reference specification has been updated since the\n        test was last updated.\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def write_info(self, info: Dict[str, str]):\n\"\"\"\n        Writes info about the reference specification used into the output\n        fixture.\n        \"\"\"\n        pass\n\n    @staticmethod\n    @abstractmethod\n    def parseable_from_module(module_dict: Dict[str, Any]) -> bool:\n\"\"\"\n        Checks whether the module's dict contains required reference spec\n        information.\n        \"\"\"\n        pass\n\n    @staticmethod\n    @abstractmethod\n    def parse_from_module(module_dict: Dict[str, Any]) -> \"ReferenceSpec\":\n\"\"\"\n        Parses the module's dict into a reference spec.\n        \"\"\"\n        pass\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.reference_spec.reference_spec.ReferenceSpec.name","title":"name() abstractmethod","text":"

Returns the name of the spec.

Source code in src/ethereum_test_tools/reference_spec/reference_spec.py
@abstractmethod\ndef name(self) -> str:\n\"\"\"\n    Returns the name of the spec.\n    \"\"\"\n    pass\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.reference_spec.reference_spec.ReferenceSpec.has_known_version","title":"has_known_version() abstractmethod","text":"

Returns true if the reference spec object is hard-coded with a latest known version.

Source code in src/ethereum_test_tools/reference_spec/reference_spec.py
@abstractmethod\ndef has_known_version(self) -> bool:\n\"\"\"\n    Returns true if the reference spec object is hard-coded with a latest\n    known version.\n    \"\"\"\n    pass\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.reference_spec.reference_spec.ReferenceSpec.known_version","title":"known_version() abstractmethod","text":"

Returns the latest known version in the reference.

Source code in src/ethereum_test_tools/reference_spec/reference_spec.py
@abstractmethod\ndef known_version(self) -> str:\n\"\"\"\n    Returns the latest known version in the reference.\n    \"\"\"\n    pass\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.reference_spec.reference_spec.ReferenceSpec.api_url","title":"api_url() abstractmethod","text":"

Returns the URL required to poll the version from an API, if needed.

Source code in src/ethereum_test_tools/reference_spec/reference_spec.py
@abstractmethod\ndef api_url(self) -> str:\n\"\"\"\n    Returns the URL required to poll the version from an API, if needed.\n    \"\"\"\n    pass\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.reference_spec.reference_spec.ReferenceSpec.latest_version","title":"latest_version() abstractmethod","text":"

Returns a digest that points to the latest version of the spec.

Source code in src/ethereum_test_tools/reference_spec/reference_spec.py
@abstractmethod\ndef latest_version(self) -> str:\n\"\"\"\n    Returns a digest that points to the latest version of the spec.\n    \"\"\"\n    pass\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.reference_spec.reference_spec.ReferenceSpec.is_outdated","title":"is_outdated() abstractmethod","text":"

Checks whether the reference specification has been updated since the test was last updated.

Source code in src/ethereum_test_tools/reference_spec/reference_spec.py
@abstractmethod\ndef is_outdated(self) -> bool:\n\"\"\"\n    Checks whether the reference specification has been updated since the\n    test was last updated.\n    \"\"\"\n    pass\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.reference_spec.reference_spec.ReferenceSpec.write_info","title":"write_info(info) abstractmethod","text":"

Writes info about the reference specification used into the output fixture.

Source code in src/ethereum_test_tools/reference_spec/reference_spec.py
@abstractmethod\ndef write_info(self, info: Dict[str, str]):\n\"\"\"\n    Writes info about the reference specification used into the output\n    fixture.\n    \"\"\"\n    pass\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.reference_spec.reference_spec.ReferenceSpec.parseable_from_module","title":"parseable_from_module(module_dict) staticmethod abstractmethod","text":"

Checks whether the module's dict contains required reference spec information.

Source code in src/ethereum_test_tools/reference_spec/reference_spec.py
@staticmethod\n@abstractmethod\ndef parseable_from_module(module_dict: Dict[str, Any]) -> bool:\n\"\"\"\n    Checks whether the module's dict contains required reference spec\n    information.\n    \"\"\"\n    pass\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.reference_spec.reference_spec.ReferenceSpec.parse_from_module","title":"parse_from_module(module_dict) staticmethod abstractmethod","text":"

Parses the module's dict into a reference spec.

Source code in src/ethereum_test_tools/reference_spec/reference_spec.py
@staticmethod\n@abstractmethod\ndef parse_from_module(module_dict: Dict[str, Any]) -> \"ReferenceSpec\":\n\"\"\"\n    Parses the module's dict into a reference spec.\n    \"\"\"\n    pass\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.StateTest","title":"StateTest dataclass","text":"

Bases: BaseTest

Filler type that tests transactions over the period of a single block.

Source code in src/ethereum_test_tools/spec/state_test.py
@dataclass(kw_only=True)\nclass StateTest(BaseTest):\n\"\"\"\n    Filler type that tests transactions over the period of a single block.\n    \"\"\"\n\n    env: Environment\n    pre: Mapping[str, Account]\n    post: Mapping[str, Account]\n    txs: List[Transaction]\n    engine_api_error_code: Optional[EngineAPIError] = None\n    tag: str = \"\"\n\n    @classmethod\n    def pytest_parameter_name(cls) -> str:\n\"\"\"\n        Returns the parameter name used to identify this filler in a test.\n        \"\"\"\n        return \"state_test\"\n\n    def make_genesis(\n        self,\n        t8n: TransitionTool,\n        fork: Fork,\n    ) -> Tuple[bytes, FixtureHeader]:\n\"\"\"\n        Create a genesis block from the state test definition.\n        \"\"\"\n        env = self.env.set_fork_requirements(fork)\n\n        genesis = FixtureHeader(\n            parent_hash=EmptyHash,\n            ommers_hash=EmptyOmmersRoot,\n            coinbase=ZeroAddress,\n            state_root=t8n.calc_state_root(\n                to_json(self.pre),\n                fork,\n            ),\n            transactions_root=EmptyTrieRoot,\n            receipt_root=EmptyTrieRoot,\n            bloom=EmptyBloom,\n            difficulty=0x20000 if env.difficulty is None else env.difficulty,\n            number=env.number - 1,\n            gas_limit=env.gas_limit,\n            gas_used=0,\n            timestamp=0,\n            extra_data=bytes([0]),\n            mix_digest=EmptyHash,\n            nonce=EmptyNonce,\n            base_fee=env.base_fee,\n            data_gas_used=env.data_gas_used,\n            excess_data_gas=env.excess_data_gas,\n            withdrawals_root=t8n.calc_withdrawals_root(env.withdrawals, fork)\n            if env.withdrawals is not None\n            else None,\n        )\n\n        genesis_rlp, genesis.hash = genesis.build(\n            txs=[],\n            ommers=[],\n            withdrawals=env.withdrawals,\n        )\n\n        return genesis_rlp, genesis\n\n    def make_blocks(\n        self,\n        t8n: TransitionTool,\n        genesis: FixtureHeader,\n        fork: Fork,\n        chain_id=1,\n        eips: Optional[List[int]] = None,\n    ) -> Tuple[List[FixtureBlock], bytes, Dict[str, Any]]:\n\"\"\"\n        Create a block from the state test definition.\n        Performs checks against the expected behavior of the test.\n        Raises exception on invalid test behavior.\n        \"\"\"\n        env = self.env.apply_new_parent(genesis)\n        env = env.set_fork_requirements(fork)\n\n        txs = [tx.with_signature_and_sender() for tx in self.txs] if self.txs is not None else []\n\n        alloc, result = t8n.evaluate(\n            alloc=to_json(self.pre),\n            txs=to_json(txs),\n            env=to_json(env),\n            fork=fork,\n            chain_id=chain_id,\n            reward=fork.get_reward(env.number, env.timestamp),\n            eips=eips,\n        )\n\n        rejected_txs = verify_transactions(txs, result)\n        if len(rejected_txs) > 0:\n            raise Exception(\n                \"one or more transactions in `StateTest` are \"\n                + \"intrinsically invalid, which are not allowed. \"\n                + \"Use `BlockchainTest` to verify rejection of blocks \"\n                + \"that include invalid transactions.\"\n            )\n\n        try:\n            verify_post_alloc(self.post, alloc)\n        except Exception as e:\n            print_traces(traces=t8n.get_traces())\n            raise e\n\n        header = FixtureHeader.from_dict(\n            result\n            | {\n                \"parentHash\": genesis.hash,\n                \"miner\": env.coinbase,\n                \"transactionsRoot\": result.get(\"txRoot\"),\n                \"difficulty\": str_or_none(env.difficulty, result.get(\"currentDifficulty\")),\n                \"number\": str(env.number),\n                \"gasLimit\": str(env.gas_limit),\n                \"timestamp\": str(env.timestamp),\n                \"extraData\": \"0x00\",\n                \"sha3Uncles\": \"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\n                \"mixHash\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n                \"nonce\": \"0x0000000000000000\",\n                \"baseFeePerGas\": result.get(\"currentBaseFee\"),\n                \"excessDataGas\": result.get(\"currentExcessDataGas\"),\n            }\n        )\n\n        block, header.hash = header.build(\n            txs=txs,\n            ommers=[],\n            withdrawals=env.withdrawals,\n        )\n\n        new_payload = FixtureEngineNewPayload.from_fixture_header(\n            fork=fork,\n            header=header,\n            transactions=txs,\n            withdrawals=env.withdrawals,\n            error_code=self.engine_api_error_code,\n        )\n\n        return (\n            [\n                FixtureBlock(\n                    rlp=block,\n                    new_payload=new_payload,\n                    block_header=header,\n                    txs=txs,\n                    ommers=[],\n                    withdrawals=env.withdrawals,\n                )\n            ],\n            header.hash,\n            alloc,\n        )\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.spec.state_test.StateTest.pytest_parameter_name","title":"pytest_parameter_name() classmethod","text":"

Returns the parameter name used to identify this filler in a test.

Source code in src/ethereum_test_tools/spec/state_test.py
@classmethod\ndef pytest_parameter_name(cls) -> str:\n\"\"\"\n    Returns the parameter name used to identify this filler in a test.\n    \"\"\"\n    return \"state_test\"\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.spec.state_test.StateTest.make_genesis","title":"make_genesis(t8n, fork)","text":"

Create a genesis block from the state test definition.

Source code in src/ethereum_test_tools/spec/state_test.py
def make_genesis(\n    self,\n    t8n: TransitionTool,\n    fork: Fork,\n) -> Tuple[bytes, FixtureHeader]:\n\"\"\"\n    Create a genesis block from the state test definition.\n    \"\"\"\n    env = self.env.set_fork_requirements(fork)\n\n    genesis = FixtureHeader(\n        parent_hash=EmptyHash,\n        ommers_hash=EmptyOmmersRoot,\n        coinbase=ZeroAddress,\n        state_root=t8n.calc_state_root(\n            to_json(self.pre),\n            fork,\n        ),\n        transactions_root=EmptyTrieRoot,\n        receipt_root=EmptyTrieRoot,\n        bloom=EmptyBloom,\n        difficulty=0x20000 if env.difficulty is None else env.difficulty,\n        number=env.number - 1,\n        gas_limit=env.gas_limit,\n        gas_used=0,\n        timestamp=0,\n        extra_data=bytes([0]),\n        mix_digest=EmptyHash,\n        nonce=EmptyNonce,\n        base_fee=env.base_fee,\n        data_gas_used=env.data_gas_used,\n        excess_data_gas=env.excess_data_gas,\n        withdrawals_root=t8n.calc_withdrawals_root(env.withdrawals, fork)\n        if env.withdrawals is not None\n        else None,\n    )\n\n    genesis_rlp, genesis.hash = genesis.build(\n        txs=[],\n        ommers=[],\n        withdrawals=env.withdrawals,\n    )\n\n    return genesis_rlp, genesis\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.spec.state_test.StateTest.make_blocks","title":"make_blocks(t8n, genesis, fork, chain_id=1, eips=None)","text":"

Create a block from the state test definition. Performs checks against the expected behavior of the test. Raises exception on invalid test behavior.

Source code in src/ethereum_test_tools/spec/state_test.py
def make_blocks(\n    self,\n    t8n: TransitionTool,\n    genesis: FixtureHeader,\n    fork: Fork,\n    chain_id=1,\n    eips: Optional[List[int]] = None,\n) -> Tuple[List[FixtureBlock], bytes, Dict[str, Any]]:\n\"\"\"\n    Create a block from the state test definition.\n    Performs checks against the expected behavior of the test.\n    Raises exception on invalid test behavior.\n    \"\"\"\n    env = self.env.apply_new_parent(genesis)\n    env = env.set_fork_requirements(fork)\n\n    txs = [tx.with_signature_and_sender() for tx in self.txs] if self.txs is not None else []\n\n    alloc, result = t8n.evaluate(\n        alloc=to_json(self.pre),\n        txs=to_json(txs),\n        env=to_json(env),\n        fork=fork,\n        chain_id=chain_id,\n        reward=fork.get_reward(env.number, env.timestamp),\n        eips=eips,\n    )\n\n    rejected_txs = verify_transactions(txs, result)\n    if len(rejected_txs) > 0:\n        raise Exception(\n            \"one or more transactions in `StateTest` are \"\n            + \"intrinsically invalid, which are not allowed. \"\n            + \"Use `BlockchainTest` to verify rejection of blocks \"\n            + \"that include invalid transactions.\"\n        )\n\n    try:\n        verify_post_alloc(self.post, alloc)\n    except Exception as e:\n        print_traces(traces=t8n.get_traces())\n        raise e\n\n    header = FixtureHeader.from_dict(\n        result\n        | {\n            \"parentHash\": genesis.hash,\n            \"miner\": env.coinbase,\n            \"transactionsRoot\": result.get(\"txRoot\"),\n            \"difficulty\": str_or_none(env.difficulty, result.get(\"currentDifficulty\")),\n            \"number\": str(env.number),\n            \"gasLimit\": str(env.gas_limit),\n            \"timestamp\": str(env.timestamp),\n            \"extraData\": \"0x00\",\n            \"sha3Uncles\": \"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\n            \"mixHash\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n            \"nonce\": \"0x0000000000000000\",\n            \"baseFeePerGas\": result.get(\"currentBaseFee\"),\n            \"excessDataGas\": result.get(\"currentExcessDataGas\"),\n        }\n    )\n\n    block, header.hash = header.build(\n        txs=txs,\n        ommers=[],\n        withdrawals=env.withdrawals,\n    )\n\n    new_payload = FixtureEngineNewPayload.from_fixture_header(\n        fork=fork,\n        header=header,\n        transactions=txs,\n        withdrawals=env.withdrawals,\n        error_code=self.engine_api_error_code,\n    )\n\n    return (\n        [\n            FixtureBlock(\n                rlp=block,\n                new_payload=new_payload,\n                block_header=header,\n                txs=txs,\n                ommers=[],\n                withdrawals=env.withdrawals,\n            )\n        ],\n        header.hash,\n        alloc,\n    )\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.Yul","title":"Yul","text":"

Bases: Code

Yul compiler. Compiles Yul source code into bytecode.

Source code in src/ethereum_test_tools/code/yul.py
class Yul(Code):\n\"\"\"\n    Yul compiler.\n    Compiles Yul source code into bytecode.\n    \"\"\"\n\n    source: str\n    compiled: Optional[bytes] = None\n\n    def __init__(\n        self,\n        source: str,\n        fork: Optional[Fork] = None,\n        binary: Optional[Path | str] = None,\n    ):\n        self.source = source\n        self.evm_version = get_evm_version_from_fork(fork)\n        if binary is None:\n            which_path = which(\"solc\")\n            if which_path is not None:\n                binary = Path(which_path)\n        if binary is None or not Path(binary).exists():\n            raise Exception(\n\"\"\"`solc` binary executable not found, please refer to\n                https://docs.soliditylang.org/en/latest/installing-solidity.html\n                for help downloading and installing `solc`\"\"\"\n            )\n        self.binary = Path(binary)\n\n    def assemble(self) -> bytes:\n\"\"\"\n        Assembles using `solc --assemble`.\n        \"\"\"\n        if not self.compiled:\n            solc_args: Tuple[Union[Path, str], ...] = ()\n            if self.evm_version:\n                solc_args = (\n                    self.binary,\n                    \"--evm-version\",\n                    self.evm_version,\n                    *DEFAULT_SOLC_ARGS,\n                )\n            else:\n                solc_args = (self.binary, *DEFAULT_SOLC_ARGS)\n            result = run(\n                solc_args,\n                input=str.encode(self.source),\n                stdout=PIPE,\n                stderr=PIPE,\n            )\n\n            if result.returncode != 0:\n                stderr_lines = result.stderr.decode().split(\"\\n\")\n                stderr_message = \"\\n\".join(line.strip() for line in stderr_lines)\n                raise Exception(f\"failed to compile yul source:\\n{stderr_message[7:]}\")\n\n            lines = result.stdout.decode().split(\"\\n\")\n\n            hex_str = lines[lines.index(\"Binary representation:\") + 1]\n\n            self.compiled = bytes.fromhex(hex_str)\n        return self.compiled\n\n    def version(self) -> str:\n\"\"\"\n        Return solc's version string\n        \"\"\"\n        result = run(\n            [self.binary, \"--version\"],\n            stdout=PIPE,\n            stderr=PIPE,\n        )\n        solc_output = result.stdout.decode().split(\"\\n\")\n        version_pattern = r\"0\\.\\d+\\.\\d+\\+\\S+\"\n        solc_version_string = None\n        for line in solc_output:\n            match = re.search(version_pattern, line)\n            if match:\n                solc_version_string = match.group(0)\n                break\n        if not solc_version_string:\n            warnings.warn(\"Unable to determine solc version.\")\n            solc_version_string = \"unknown\"\n        return solc_version_string\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.code.yul.Yul.assemble","title":"assemble()","text":"

Assembles using solc --assemble.

Source code in src/ethereum_test_tools/code/yul.py
def assemble(self) -> bytes:\n\"\"\"\n    Assembles using `solc --assemble`.\n    \"\"\"\n    if not self.compiled:\n        solc_args: Tuple[Union[Path, str], ...] = ()\n        if self.evm_version:\n            solc_args = (\n                self.binary,\n                \"--evm-version\",\n                self.evm_version,\n                *DEFAULT_SOLC_ARGS,\n            )\n        else:\n            solc_args = (self.binary, *DEFAULT_SOLC_ARGS)\n        result = run(\n            solc_args,\n            input=str.encode(self.source),\n            stdout=PIPE,\n            stderr=PIPE,\n        )\n\n        if result.returncode != 0:\n            stderr_lines = result.stderr.decode().split(\"\\n\")\n            stderr_message = \"\\n\".join(line.strip() for line in stderr_lines)\n            raise Exception(f\"failed to compile yul source:\\n{stderr_message[7:]}\")\n\n        lines = result.stdout.decode().split(\"\\n\")\n\n        hex_str = lines[lines.index(\"Binary representation:\") + 1]\n\n        self.compiled = bytes.fromhex(hex_str)\n    return self.compiled\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.code.yul.Yul.version","title":"version()","text":"

Return solc's version string

Source code in src/ethereum_test_tools/code/yul.py
def version(self) -> str:\n\"\"\"\n    Return solc's version string\n    \"\"\"\n    result = run(\n        [self.binary, \"--version\"],\n        stdout=PIPE,\n        stderr=PIPE,\n    )\n    solc_output = result.stdout.decode().split(\"\\n\")\n    version_pattern = r\"0\\.\\d+\\.\\d+\\+\\S+\"\n    solc_version_string = None\n    for line in solc_output:\n        match = re.search(version_pattern, line)\n        if match:\n            solc_version_string = match.group(0)\n            break\n    if not solc_version_string:\n        warnings.warn(\"Unable to determine solc version.\")\n        solc_version_string = \"unknown\"\n    return solc_version_string\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.compute_create2_address","title":"compute_create2_address(address, salt, initcode)","text":"

Compute address of the resulting contract created using the CREATE2 opcode.

Source code in src/ethereum_test_tools/common/helpers.py
def compute_create2_address(address: str | int, salt: int, initcode: bytes) -> str:\n\"\"\"\n    Compute address of the resulting contract created using the `CREATE2`\n    opcode.\n    \"\"\"\n    ff = bytes([0xFF])\n    if type(address) is str:\n        if address.startswith(\"0x\"):\n            address = address[2:]\n        address_bytes = bytes.fromhex(address)\n    elif type(address) is int:\n        address_bytes = address.to_bytes(length=20, byteorder=\"big\")\n    salt_bytes = salt.to_bytes(length=32, byteorder=\"big\")\n    initcode_hash = keccak256(initcode)\n    hash = keccak256(ff + address_bytes + salt_bytes + initcode_hash)\n    return \"0x\" + hash[-20:].hex()\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.cost_memory_bytes","title":"cost_memory_bytes(new_bytes, previous_bytes)","text":"

Calculates the cost of memory expansion, based on the costs specified in the yellow paper: https://ethereum.github.io/yellowpaper/paper.pdf

Source code in src/ethereum_test_tools/common/helpers.py
def cost_memory_bytes(new_bytes: int, previous_bytes: int) -> int:\n\"\"\"\n    Calculates the cost of memory expansion, based on the costs specified in\n    the yellow paper: https://ethereum.github.io/yellowpaper/paper.pdf\n    \"\"\"\n    if new_bytes <= previous_bytes:\n        return 0\n    new_words = ceiling_division(new_bytes, 32)\n    previous_words = ceiling_division(previous_bytes, 32)\n\n    def c(w: int) -> int:\n        g_memory = 3\n        return (g_memory * w) + ((w * w) // 512)\n\n    return c(new_words) - c(previous_words)\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.Auto","title":"Auto","text":"

Class to use as a sentinel value for parameters that should be automatically calculated.

Source code in src/ethereum_test_tools/common/types.py
class Auto:\n\"\"\"\n    Class to use as a sentinel value for parameters that should be\n    automatically calculated.\n    \"\"\"\n\n    def __repr__(self) -> str:\n\"\"\"Print the correct test id.\"\"\"\n        return \"auto\"\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Auto.__repr__","title":"__repr__()","text":"

Print the correct test id.

Source code in src/ethereum_test_tools/common/types.py
def __repr__(self) -> str:\n\"\"\"Print the correct test id.\"\"\"\n    return \"auto\"\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.BaseTest","title":"BaseTest","text":"

Represents a base Ethereum test which must return a genesis and a blockchain.

Source code in src/ethereum_test_tools/spec/base_test.py
class BaseTest:\n\"\"\"\n    Represents a base Ethereum test which must return a genesis and a\n    blockchain.\n    \"\"\"\n\n    pre: Mapping[str, Account]\n    tag: str = \"\"\n\n    @abstractmethod\n    def make_genesis(\n        self,\n        t8n: TransitionTool,\n        fork: Fork,\n    ) -> Tuple[bytes, FixtureHeader]:\n\"\"\"\n        Create a genesis block from the test definition.\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def make_blocks(\n        self,\n        t8n: TransitionTool,\n        genesis: FixtureHeader,\n        fork: Fork,\n        chain_id: int = 1,\n        eips: Optional[List[int]] = None,\n    ) -> Tuple[List[FixtureBlock], bytes, Dict[str, Any]]:\n\"\"\"\n        Generate the blockchain that must be executed sequentially during test.\n        \"\"\"\n        pass\n\n    @classmethod\n    @abstractmethod\n    def pytest_parameter_name(cls) -> str:\n\"\"\"\n        Must return the name of the parameter used in pytest to select this\n        spec type as filler for the test.\n        \"\"\"\n        pass\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.spec.base_test.BaseTest.make_genesis","title":"make_genesis(t8n, fork) abstractmethod","text":"

Create a genesis block from the test definition.

Source code in src/ethereum_test_tools/spec/base_test.py
@abstractmethod\ndef make_genesis(\n    self,\n    t8n: TransitionTool,\n    fork: Fork,\n) -> Tuple[bytes, FixtureHeader]:\n\"\"\"\n    Create a genesis block from the test definition.\n    \"\"\"\n    pass\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.spec.base_test.BaseTest.make_blocks","title":"make_blocks(t8n, genesis, fork, chain_id=1, eips=None) abstractmethod","text":"

Generate the blockchain that must be executed sequentially during test.

Source code in src/ethereum_test_tools/spec/base_test.py
@abstractmethod\ndef make_blocks(\n    self,\n    t8n: TransitionTool,\n    genesis: FixtureHeader,\n    fork: Fork,\n    chain_id: int = 1,\n    eips: Optional[List[int]] = None,\n) -> Tuple[List[FixtureBlock], bytes, Dict[str, Any]]:\n\"\"\"\n    Generate the blockchain that must be executed sequentially during test.\n    \"\"\"\n    pass\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.spec.base_test.BaseTest.pytest_parameter_name","title":"pytest_parameter_name() classmethod abstractmethod","text":"

Must return the name of the parameter used in pytest to select this spec type as filler for the test.

Source code in src/ethereum_test_tools/spec/base_test.py
@classmethod\n@abstractmethod\ndef pytest_parameter_name(cls) -> str:\n\"\"\"\n    Must return the name of the parameter used in pytest to select this\n    spec type as filler for the test.\n    \"\"\"\n    pass\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.copy_opcode_cost","title":"copy_opcode_cost(length)","text":"

Calculates the cost of the COPY opcodes, assuming memory expansion from empty memory, based on the costs specified in the yellow paper: https://ethereum.github.io/yellowpaper/paper.pdf

Source code in src/ethereum_test_tools/common/helpers.py
def copy_opcode_cost(length: int) -> int:\n\"\"\"\n    Calculates the cost of the COPY opcodes, assuming memory expansion from\n    empty memory, based on the costs specified in the yellow paper:\n    https://ethereum.github.io/yellowpaper/paper.pdf\n    \"\"\"\n    return 3 + (ceiling_division(length, 32) * 3) + cost_memory_bytes(length, 0)\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.Storage","title":"Storage","text":"

Definition of a storage in pre or post state of a test

Source code in src/ethereum_test_tools/common/types.py
class Storage:\n\"\"\"\n    Definition of a storage in pre or post state of a test\n    \"\"\"\n\n    data: Dict[int, int]\n\n    StorageDictType: ClassVar[TypeAlias] = Dict[str | int | bytes, str | int | bytes]\n\"\"\"\n    Dictionary type to be used when defining an input to initialize a storage.\n    \"\"\"\n\n    class InvalidType(Exception):\n\"\"\"\n        Invalid type used when describing test's expected storage key or value.\n        \"\"\"\n\n        key_or_value: Any\n\n        def __init__(self, key_or_value: Any, *args):\n            super().__init__(args)\n            self.key_or_value = key_or_value\n\n        def __str__(self):\n\"\"\"Print exception string\"\"\"\n            return f\"invalid type for key/value: {self.key_or_value}\"\n\n    class InvalidValue(Exception):\n\"\"\"\n        Invalid value used when describing test's expected storage key or\n        value.\n        \"\"\"\n\n        key_or_value: Any\n\n        def __init__(self, key_or_value: Any, *args):\n            super().__init__(args)\n            self.key_or_value = key_or_value\n\n        def __str__(self):\n\"\"\"Print exception string\"\"\"\n            return f\"invalid value for key/value: {self.key_or_value}\"\n\n    class AmbiguousKeyValue(Exception):\n\"\"\"\n        Key is represented twice in the storage.\n        \"\"\"\n\n        key_1: str | int\n        val_1: str | int\n        key_2: str | int\n        val_2: str | int\n\n        def __init__(\n            self,\n            key_1: str | int,\n            val_1: str | int,\n            key_2: str | int,\n            val_2: str | int,\n            *args,\n        ):\n            super().__init__(args)\n            self.key_1 = key_1\n            self.val_1 = val_1\n            self.key_2 = key_2\n            self.val_2 = val_2\n\n        def __str__(self):\n\"\"\"Print exception string\"\"\"\n            return f\"\"\"\n            Key is represented twice (due to negative numbers) with different\n            values in storage:\n            s[{self.key_1}] = {self.val_1} and s[{self.key_2}] = {self.val_2}\n            \"\"\"\n\n    class MissingKey(Exception):\n\"\"\"\n        Test expected to find a storage key set but key was missing.\n        \"\"\"\n\n        key: int\n\n        def __init__(self, key: int, *args):\n            super().__init__(args)\n            self.key = key\n\n        def __str__(self):\n\"\"\"Print exception string\"\"\"\n            return \"key {0} not found in storage\".format(Storage.key_value_to_string(self.key))\n\n    class KeyValueMismatch(Exception):\n\"\"\"\n        Test expected a certain value in a storage key but value found\n        was different.\n        \"\"\"\n\n        key: int\n        want: int\n        got: int\n\n        def __init__(self, key: int, want: int, got: int, *args):\n            super().__init__(args)\n            self.key = key\n            self.want = want\n            self.got = got\n\n        def __str__(self):\n\"\"\"Print exception string\"\"\"\n            return (\n                \"incorrect value for key {0}: want {1} (dec:{2}),\" + \" got {3} (dec:{4})\"\n            ).format(\n                Storage.key_value_to_string(self.key),\n                Storage.key_value_to_string(self.want),\n                self.want,\n                Storage.key_value_to_string(self.got),\n                self.got,\n            )\n\n    @staticmethod\n    def parse_key_value(input: str | int | bytes) -> int:\n\"\"\"\n        Parses a key or value to a valid int key for storage.\n        \"\"\"\n        if type(input) is str:\n            input = int(input, 0)\n        elif type(input) is int:\n            pass\n        elif type(input) is bytes:\n            input = int.from_bytes(input, \"big\")\n        else:\n            raise Storage.InvalidType(input)\n\n        if input > MAX_STORAGE_KEY_VALUE or input < MIN_STORAGE_KEY_VALUE:\n            raise Storage.InvalidValue(input)\n        return input\n\n    @staticmethod\n    def key_value_to_string(value: int) -> str:\n\"\"\"\n        Transforms a key or value into an hex string.\n        \"\"\"\n        hex_str = value.to_bytes(32, \"big\", signed=(value < 0)).hex().lstrip(\"0\")\n        if hex_str == \"\":\n            hex_str = \"00\"\n        if len(hex_str) % 2 != 0:\n            hex_str = \"0\" + hex_str\n        return \"0x\" + hex_str\n\n    def __init__(self, input: StorageDictType):\n\"\"\"\n        Initializes the storage using a given mapping which can have\n        keys and values either as string or int.\n        Strings must be valid decimal or hexadecimal (starting with 0x)\n        numbers.\n        \"\"\"\n        self.data = {}\n        for key in input:\n            value = Storage.parse_key_value(input[key])\n            key = Storage.parse_key_value(key)\n            self.data[key] = value\n        pass\n\n    def __len__(self) -> int:\n\"\"\"Returns number of elements in the storage\"\"\"\n        return len(self.data)\n\n    def __contains__(self, key: str | int) -> bool:\n\"\"\"Checks for an item in the storage\"\"\"\n        key = Storage.parse_key_value(key)\n        return key in self.data\n\n    def __getitem__(self, key: str | int) -> int:\n\"\"\"Returns an item from the storage\"\"\"\n        key = Storage.parse_key_value(key)\n        if key not in self.data:\n            raise KeyError()\n        return self.data[key]\n\n    def __setitem__(self, key: str | int, value: str | int):  # noqa: SC200\n\"\"\"Sets an item in the storage\"\"\"\n        self.data[Storage.parse_key_value(key)] = Storage.parse_key_value(value)\n\n    def __delitem__(self, key: str | int):\n\"\"\"Deletes an item from the storage\"\"\"\n        del self.data[Storage.parse_key_value(key)]\n\n    def to_dict(self) -> Mapping[str, str]:\n\"\"\"\n        Converts the storage into a string dict with appropriate 32-byte\n        hex string formatting.\n        \"\"\"\n        res: Dict[str, str] = {}\n        for key in self.data:\n            key_repr = Storage.key_value_to_string(key)\n            val_repr = Storage.key_value_to_string(self.data[key])\n            if key_repr in res and val_repr != res[key_repr]:\n                raise Storage.AmbiguousKeyValue(key_repr, res[key_repr], key, val_repr)\n            res[key_repr] = val_repr\n        return res\n\n    def contains(self, other: \"Storage\") -> bool:\n\"\"\"\n        Returns True if self contains all keys with equal value as\n        contained by second storage.\n        Used for comparison with test expected post state and alloc returned\n        by the transition tool.\n        \"\"\"\n        for key in other.data:\n            if key not in self.data:\n                return False\n            if self.data[key] != other.data[key]:\n                return False\n        return True\n\n    def must_contain(self, other: \"Storage\"):\n\"\"\"\n        Succeeds only if self contains all keys with equal value as\n        contained by second storage.\n        Used for comparison with test expected post state and alloc returned\n        by the transition tool.\n        Raises detailed exception when a difference is found.\n        \"\"\"\n        for key in other.data:\n            if key not in self.data:\n                # storage[key]==0 is equal to missing storage\n                if other[key] != 0:\n                    raise Storage.MissingKey(key)\n            elif self.data[key] != other.data[key]:\n                raise Storage.KeyValueMismatch(key, self.data[key], other.data[key])\n\n    def must_be_equal(self, other: \"Storage\"):\n\"\"\"\n        Succeeds only if \"self\" is equal to \"other\" storage.\n        \"\"\"\n        # Test keys contained in both storage objects\n        for key in self.data.keys() & other.data.keys():\n            if self.data[key] != other.data[key]:\n                raise Storage.KeyValueMismatch(key, self.data[key], other.data[key])\n\n        # Test keys contained in either one of the storage objects\n        for key in self.data.keys() ^ other.data.keys():\n            if key in self.data:\n                if self.data[key] != 0:\n                    raise Storage.KeyValueMismatch(key, self.data[key], 0)\n\n            elif other.data[key] != 0:\n                raise Storage.KeyValueMismatch(key, 0, other.data[key])\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.StorageDictType","title":"StorageDictType: TypeAlias = Dict[str | int | bytes, str | int | bytes] class-attribute","text":"

Dictionary type to be used when defining an input to initialize a storage.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.InvalidType","title":"InvalidType","text":"

Bases: Exception

Invalid type used when describing test's expected storage key or value.

Source code in src/ethereum_test_tools/common/types.py
class InvalidType(Exception):\n\"\"\"\n    Invalid type used when describing test's expected storage key or value.\n    \"\"\"\n\n    key_or_value: Any\n\n    def __init__(self, key_or_value: Any, *args):\n        super().__init__(args)\n        self.key_or_value = key_or_value\n\n    def __str__(self):\n\"\"\"Print exception string\"\"\"\n        return f\"invalid type for key/value: {self.key_or_value}\"\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.InvalidType.__str__","title":"__str__()","text":"

Print exception string

Source code in src/ethereum_test_tools/common/types.py
def __str__(self):\n\"\"\"Print exception string\"\"\"\n    return f\"invalid type for key/value: {self.key_or_value}\"\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.InvalidValue","title":"InvalidValue","text":"

Bases: Exception

Invalid value used when describing test's expected storage key or value.

Source code in src/ethereum_test_tools/common/types.py
class InvalidValue(Exception):\n\"\"\"\n    Invalid value used when describing test's expected storage key or\n    value.\n    \"\"\"\n\n    key_or_value: Any\n\n    def __init__(self, key_or_value: Any, *args):\n        super().__init__(args)\n        self.key_or_value = key_or_value\n\n    def __str__(self):\n\"\"\"Print exception string\"\"\"\n        return f\"invalid value for key/value: {self.key_or_value}\"\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.InvalidValue.__str__","title":"__str__()","text":"

Print exception string

Source code in src/ethereum_test_tools/common/types.py
def __str__(self):\n\"\"\"Print exception string\"\"\"\n    return f\"invalid value for key/value: {self.key_or_value}\"\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.AmbiguousKeyValue","title":"AmbiguousKeyValue","text":"

Bases: Exception

Key is represented twice in the storage.

Source code in src/ethereum_test_tools/common/types.py
class AmbiguousKeyValue(Exception):\n\"\"\"\n    Key is represented twice in the storage.\n    \"\"\"\n\n    key_1: str | int\n    val_1: str | int\n    key_2: str | int\n    val_2: str | int\n\n    def __init__(\n        self,\n        key_1: str | int,\n        val_1: str | int,\n        key_2: str | int,\n        val_2: str | int,\n        *args,\n    ):\n        super().__init__(args)\n        self.key_1 = key_1\n        self.val_1 = val_1\n        self.key_2 = key_2\n        self.val_2 = val_2\n\n    def __str__(self):\n\"\"\"Print exception string\"\"\"\n        return f\"\"\"\n        Key is represented twice (due to negative numbers) with different\n        values in storage:\n        s[{self.key_1}] = {self.val_1} and s[{self.key_2}] = {self.val_2}\n        \"\"\"\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.AmbiguousKeyValue.__str__","title":"__str__()","text":"

Print exception string

Source code in src/ethereum_test_tools/common/types.py
def __str__(self):\n\"\"\"Print exception string\"\"\"\n    return f\"\"\"\n    Key is represented twice (due to negative numbers) with different\n    values in storage:\n    s[{self.key_1}] = {self.val_1} and s[{self.key_2}] = {self.val_2}\n    \"\"\"\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.MissingKey","title":"MissingKey","text":"

Bases: Exception

Test expected to find a storage key set but key was missing.

Source code in src/ethereum_test_tools/common/types.py
class MissingKey(Exception):\n\"\"\"\n    Test expected to find a storage key set but key was missing.\n    \"\"\"\n\n    key: int\n\n    def __init__(self, key: int, *args):\n        super().__init__(args)\n        self.key = key\n\n    def __str__(self):\n\"\"\"Print exception string\"\"\"\n        return \"key {0} not found in storage\".format(Storage.key_value_to_string(self.key))\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.MissingKey.__str__","title":"__str__()","text":"

Print exception string

Source code in src/ethereum_test_tools/common/types.py
def __str__(self):\n\"\"\"Print exception string\"\"\"\n    return \"key {0} not found in storage\".format(Storage.key_value_to_string(self.key))\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.KeyValueMismatch","title":"KeyValueMismatch","text":"

Bases: Exception

Test expected a certain value in a storage key but value found was different.

Source code in src/ethereum_test_tools/common/types.py
class KeyValueMismatch(Exception):\n\"\"\"\n    Test expected a certain value in a storage key but value found\n    was different.\n    \"\"\"\n\n    key: int\n    want: int\n    got: int\n\n    def __init__(self, key: int, want: int, got: int, *args):\n        super().__init__(args)\n        self.key = key\n        self.want = want\n        self.got = got\n\n    def __str__(self):\n\"\"\"Print exception string\"\"\"\n        return (\n            \"incorrect value for key {0}: want {1} (dec:{2}),\" + \" got {3} (dec:{4})\"\n        ).format(\n            Storage.key_value_to_string(self.key),\n            Storage.key_value_to_string(self.want),\n            self.want,\n            Storage.key_value_to_string(self.got),\n            self.got,\n        )\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.KeyValueMismatch.__str__","title":"__str__()","text":"

Print exception string

Source code in src/ethereum_test_tools/common/types.py
def __str__(self):\n\"\"\"Print exception string\"\"\"\n    return (\n        \"incorrect value for key {0}: want {1} (dec:{2}),\" + \" got {3} (dec:{4})\"\n    ).format(\n        Storage.key_value_to_string(self.key),\n        Storage.key_value_to_string(self.want),\n        self.want,\n        Storage.key_value_to_string(self.got),\n        self.got,\n    )\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.parse_key_value","title":"parse_key_value(input) staticmethod","text":"

Parses a key or value to a valid int key for storage.

Source code in src/ethereum_test_tools/common/types.py
@staticmethod\ndef parse_key_value(input: str | int | bytes) -> int:\n\"\"\"\n    Parses a key or value to a valid int key for storage.\n    \"\"\"\n    if type(input) is str:\n        input = int(input, 0)\n    elif type(input) is int:\n        pass\n    elif type(input) is bytes:\n        input = int.from_bytes(input, \"big\")\n    else:\n        raise Storage.InvalidType(input)\n\n    if input > MAX_STORAGE_KEY_VALUE or input < MIN_STORAGE_KEY_VALUE:\n        raise Storage.InvalidValue(input)\n    return input\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.key_value_to_string","title":"key_value_to_string(value) staticmethod","text":"

Transforms a key or value into an hex string.

Source code in src/ethereum_test_tools/common/types.py
@staticmethod\ndef key_value_to_string(value: int) -> str:\n\"\"\"\n    Transforms a key or value into an hex string.\n    \"\"\"\n    hex_str = value.to_bytes(32, \"big\", signed=(value < 0)).hex().lstrip(\"0\")\n    if hex_str == \"\":\n        hex_str = \"00\"\n    if len(hex_str) % 2 != 0:\n        hex_str = \"0\" + hex_str\n    return \"0x\" + hex_str\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.__init__","title":"__init__(input)","text":"

Initializes the storage using a given mapping which can have keys and values either as string or int. Strings must be valid decimal or hexadecimal (starting with 0x) numbers.

Source code in src/ethereum_test_tools/common/types.py
def __init__(self, input: StorageDictType):\n\"\"\"\n    Initializes the storage using a given mapping which can have\n    keys and values either as string or int.\n    Strings must be valid decimal or hexadecimal (starting with 0x)\n    numbers.\n    \"\"\"\n    self.data = {}\n    for key in input:\n        value = Storage.parse_key_value(input[key])\n        key = Storage.parse_key_value(key)\n        self.data[key] = value\n    pass\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.__len__","title":"__len__()","text":"

Returns number of elements in the storage

Source code in src/ethereum_test_tools/common/types.py
def __len__(self) -> int:\n\"\"\"Returns number of elements in the storage\"\"\"\n    return len(self.data)\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.__contains__","title":"__contains__(key)","text":"

Checks for an item in the storage

Source code in src/ethereum_test_tools/common/types.py
def __contains__(self, key: str | int) -> bool:\n\"\"\"Checks for an item in the storage\"\"\"\n    key = Storage.parse_key_value(key)\n    return key in self.data\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.__getitem__","title":"__getitem__(key)","text":"

Returns an item from the storage

Source code in src/ethereum_test_tools/common/types.py
def __getitem__(self, key: str | int) -> int:\n\"\"\"Returns an item from the storage\"\"\"\n    key = Storage.parse_key_value(key)\n    if key not in self.data:\n        raise KeyError()\n    return self.data[key]\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.__setitem__","title":"__setitem__(key, value)","text":"

Sets an item in the storage

Source code in src/ethereum_test_tools/common/types.py
def __setitem__(self, key: str | int, value: str | int):  # noqa: SC200\n\"\"\"Sets an item in the storage\"\"\"\n    self.data[Storage.parse_key_value(key)] = Storage.parse_key_value(value)\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.__delitem__","title":"__delitem__(key)","text":"

Deletes an item from the storage

Source code in src/ethereum_test_tools/common/types.py
def __delitem__(self, key: str | int):\n\"\"\"Deletes an item from the storage\"\"\"\n    del self.data[Storage.parse_key_value(key)]\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.to_dict","title":"to_dict()","text":"

Converts the storage into a string dict with appropriate 32-byte hex string formatting.

Source code in src/ethereum_test_tools/common/types.py
def to_dict(self) -> Mapping[str, str]:\n\"\"\"\n    Converts the storage into a string dict with appropriate 32-byte\n    hex string formatting.\n    \"\"\"\n    res: Dict[str, str] = {}\n    for key in self.data:\n        key_repr = Storage.key_value_to_string(key)\n        val_repr = Storage.key_value_to_string(self.data[key])\n        if key_repr in res and val_repr != res[key_repr]:\n            raise Storage.AmbiguousKeyValue(key_repr, res[key_repr], key, val_repr)\n        res[key_repr] = val_repr\n    return res\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.contains","title":"contains(other)","text":"

Returns True if self contains all keys with equal value as contained by second storage. Used for comparison with test expected post state and alloc returned by the transition tool.

Source code in src/ethereum_test_tools/common/types.py
def contains(self, other: \"Storage\") -> bool:\n\"\"\"\n    Returns True if self contains all keys with equal value as\n    contained by second storage.\n    Used for comparison with test expected post state and alloc returned\n    by the transition tool.\n    \"\"\"\n    for key in other.data:\n        if key not in self.data:\n            return False\n        if self.data[key] != other.data[key]:\n            return False\n    return True\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.must_contain","title":"must_contain(other)","text":"

Succeeds only if self contains all keys with equal value as contained by second storage. Used for comparison with test expected post state and alloc returned by the transition tool. Raises detailed exception when a difference is found.

Source code in src/ethereum_test_tools/common/types.py
def must_contain(self, other: \"Storage\"):\n\"\"\"\n    Succeeds only if self contains all keys with equal value as\n    contained by second storage.\n    Used for comparison with test expected post state and alloc returned\n    by the transition tool.\n    Raises detailed exception when a difference is found.\n    \"\"\"\n    for key in other.data:\n        if key not in self.data:\n            # storage[key]==0 is equal to missing storage\n            if other[key] != 0:\n                raise Storage.MissingKey(key)\n        elif self.data[key] != other.data[key]:\n            raise Storage.KeyValueMismatch(key, self.data[key], other.data[key])\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Storage.must_be_equal","title":"must_be_equal(other)","text":"

Succeeds only if \"self\" is equal to \"other\" storage.

Source code in src/ethereum_test_tools/common/types.py
def must_be_equal(self, other: \"Storage\"):\n\"\"\"\n    Succeeds only if \"self\" is equal to \"other\" storage.\n    \"\"\"\n    # Test keys contained in both storage objects\n    for key in self.data.keys() & other.data.keys():\n        if self.data[key] != other.data[key]:\n            raise Storage.KeyValueMismatch(key, self.data[key], other.data[key])\n\n    # Test keys contained in either one of the storage objects\n    for key in self.data.keys() ^ other.data.keys():\n        if key in self.data:\n            if self.data[key] != 0:\n                raise Storage.KeyValueMismatch(key, self.data[key], 0)\n\n        elif other.data[key] != 0:\n            raise Storage.KeyValueMismatch(key, 0, other.data[key])\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.eip_2028_transaction_data_cost","title":"eip_2028_transaction_data_cost(data)","text":"

Calculates the cost of a given data as part of a transaction, based on the costs specified in EIP-2028: https://eips.ethereum.org/EIPS/eip-2028

Source code in src/ethereum_test_tools/common/helpers.py
def eip_2028_transaction_data_cost(data: bytes | str) -> int:\n\"\"\"\n    Calculates the cost of a given data as part of a transaction, based on the\n    costs specified in EIP-2028: https://eips.ethereum.org/EIPS/eip-2028\n    \"\"\"\n    if type(data) is str:\n        if data.startswith(\"0x\"):\n            data = data[2:]\n        data = bytes.fromhex(data)\n    cost = 0\n    for b in data:\n        if b == 0:\n            cost += 4\n        else:\n            cost += 16\n    return cost\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.to_address","title":"to_address(input)","text":"

Converts an int or str into proper address 20-byte hex string.

Source code in src/ethereum_test_tools/common/helpers.py
def to_address(input: int | str) -> str:\n\"\"\"\n    Converts an int or str into proper address 20-byte hex string.\n    \"\"\"\n    if type(input) is str:\n        # Convert to int\n        input = int(input, 0)\n    if type(input) is int:\n        return \"0x\" + input.to_bytes(20, \"big\").hex()\n    raise Exception(\"invalid type to convert to account address\")\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.CodeGasMeasure","title":"CodeGasMeasure dataclass","text":"

Bases: Code

Helper class used to generate bytecode that measures gas usage of a bytecode, taking into account and subtracting any extra overhead gas costs required to execute. By default, the result gas calculation is saved to storage key 0.

Source code in src/ethereum_test_tools/code/generators.py
@dataclass(kw_only=True)\nclass CodeGasMeasure(Code):\n\"\"\"\n    Helper class used to generate bytecode that measures gas usage of a\n    bytecode, taking into account and subtracting any extra overhead gas costs\n    required to execute.\n    By default, the result gas calculation is saved to storage key 0.\n    \"\"\"\n\n    code: bytes | str | Code\n\"\"\"\n    Bytecode to be executed to measure the gas usage.\n    \"\"\"\n    overhead_cost: int = 0\n\"\"\"\n    Extra gas cost to be subtracted from extra operations.\n    \"\"\"\n    extra_stack_items: int = 0\n\"\"\"\n    Extra stack items that remain at the end of the execution.\n    To be considered when subtracting the value of the previous GAS operation,\n    and to be popped at the end of the execution.\n    \"\"\"\n    sstore_key: int = 0\n\"\"\"\n    Storage key to save the gas used.\n    \"\"\"\n\n    def assemble(self) -> bytes:\n\"\"\"\n        Assemble the bytecode that measures gas usage.\n        \"\"\"\n        res = bytes()\n        res += bytes(\n            [\n                0x5A,  # GAS\n            ]\n        )\n        res += code_to_bytes(self.code)  # Execute code to measure its gas cost\n        res += bytes(\n            [\n                0x5A,  # GAS\n            ]\n        )\n        # We need to swap and pop for each extra stack item that remained from\n        # the execution of the code\n        res += (\n            bytes(\n                [\n                    0x90,  # SWAP1\n                    0x50,  # POP\n                ]\n            )\n            * self.extra_stack_items\n        )\n        res += bytes(\n            [\n                0x90,  # SWAP1\n                0x03,  # SUB\n                0x60,  # PUSH1\n                self.overhead_cost + 2,  # Overhead cost + GAS opcode price\n                0x90,  # SWAP1\n                0x03,  # SUB\n                0x60,  # PUSH1\n                self.sstore_key,  # -> SSTORE key\n                0x55,  # SSTORE\n                0x00,  # STOP\n            ]\n        )\n        return res\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.code.generators.CodeGasMeasure.code","title":"code: bytes | str | Code instance-attribute","text":"

Bytecode to be executed to measure the gas usage.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.code.generators.CodeGasMeasure.overhead_cost","title":"overhead_cost: int = 0 instance-attribute class-attribute","text":"

Extra gas cost to be subtracted from extra operations.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.code.generators.CodeGasMeasure.extra_stack_items","title":"extra_stack_items: int = 0 instance-attribute class-attribute","text":"

Extra stack items that remain at the end of the execution. To be considered when subtracting the value of the previous GAS operation, and to be popped at the end of the execution.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.code.generators.CodeGasMeasure.sstore_key","title":"sstore_key: int = 0 instance-attribute class-attribute","text":"

Storage key to save the gas used.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.code.generators.CodeGasMeasure.assemble","title":"assemble()","text":"

Assemble the bytecode that measures gas usage.

Source code in src/ethereum_test_tools/code/generators.py
def assemble(self) -> bytes:\n\"\"\"\n    Assemble the bytecode that measures gas usage.\n    \"\"\"\n    res = bytes()\n    res += bytes(\n        [\n            0x5A,  # GAS\n        ]\n    )\n    res += code_to_bytes(self.code)  # Execute code to measure its gas cost\n    res += bytes(\n        [\n            0x5A,  # GAS\n        ]\n    )\n    # We need to swap and pop for each extra stack item that remained from\n    # the execution of the code\n    res += (\n        bytes(\n            [\n                0x90,  # SWAP1\n                0x50,  # POP\n            ]\n        )\n        * self.extra_stack_items\n    )\n    res += bytes(\n        [\n            0x90,  # SWAP1\n            0x03,  # SUB\n            0x60,  # PUSH1\n            self.overhead_cost + 2,  # Overhead cost + GAS opcode price\n            0x90,  # SWAP1\n            0x03,  # SUB\n            0x60,  # PUSH1\n            self.sstore_key,  # -> SSTORE key\n            0x55,  # SSTORE\n            0x00,  # STOP\n        ]\n    )\n    return res\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.to_hash_bytes","title":"to_hash_bytes(input)","text":"

Converts an int or str into proper 32-byte hash.

Source code in src/ethereum_test_tools/common/helpers.py
def to_hash_bytes(input: int | str) -> bytes:\n\"\"\"\n    Converts an int or str into proper 32-byte hash.\n    \"\"\"\n    if type(input) is str:\n        # Convert to int\n        input = int(input, 0)\n    if type(input) is int:\n        return input.to_bytes(32, \"big\")\n    raise Exception(\"invalid type to convert to hash\")\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.to_hash","title":"to_hash(input)","text":"

Converts an int or str into proper 32-byte hash hex string.

Source code in src/ethereum_test_tools/common/helpers.py
def to_hash(input: int | str) -> str:\n\"\"\"\n    Converts an int or str into proper 32-byte hash hex string.\n    \"\"\"\n    return \"0x\" + to_hash_bytes(input).hex()\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.add_kzg_version","title":"add_kzg_version(b_hashes, kzg_version)","text":"

Adds the Kzg Version to each blob hash.

Source code in src/ethereum_test_tools/common/helpers.py
def add_kzg_version(b_hashes: List[bytes | int | str], kzg_version: int) -> List[bytes]:\n\"\"\"\n    Adds the Kzg Version to each blob hash.\n    \"\"\"\n    kzg_version_hex = bytes([kzg_version])\n    kzg_versioned_hashes = []\n\n    for hash in b_hashes:\n        if isinstance(hash, int) or isinstance(hash, str):\n            kzg_versioned_hashes.append(kzg_version_hex + to_hash_bytes(hash)[1:])\n        elif isinstance(hash, bytes):\n            kzg_versioned_hashes.append(kzg_version_hex + hash[1:])\n        else:\n            raise TypeError(\"Blob hash must be either an integer, string or bytes\")\n    return kzg_versioned_hashes\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.Opcodes","title":"Opcodes","text":"

Bases: Opcode, Enum

Enum containing all known opcodes.

Contains deprecated and not yet implemented opcodes.

This enum is !! NOT !! meant to be iterated over by the tests. Instead, create a list with cherry-picked opcodes from this Enum within the test if iteration is needed.

Do !! NOT !! remove or modify existing opcodes from this list.

Source code in src/ethereum_test_tools/vm/opcode.py
class Opcodes(Opcode, Enum):\n\"\"\"\n    Enum containing all known opcodes.\n\n    Contains deprecated and not yet implemented opcodes.\n\n    This enum is !! NOT !! meant to be iterated over by the tests. Instead,\n    create a list with cherry-picked opcodes from this Enum within the test\n    if iteration is needed.\n\n    Do !! NOT !! remove or modify existing opcodes from this list.\n    \"\"\"\n\n    STOP = Opcode(0x00)\n    ADD = Opcode(0x01, popped_stack_items=2, pushed_stack_items=1)\n    MUL = Opcode(0x02, popped_stack_items=2, pushed_stack_items=1)\n    SUB = Opcode(0x03, popped_stack_items=2, pushed_stack_items=1)\n    DIV = Opcode(0x04, popped_stack_items=2, pushed_stack_items=1)\n    SDIV = Opcode(0x05, popped_stack_items=2, pushed_stack_items=1)\n    MOD = Opcode(0x06, popped_stack_items=2, pushed_stack_items=1)\n    SMOD = Opcode(0x07, popped_stack_items=2, pushed_stack_items=1)\n    ADDMOD = Opcode(0x08, popped_stack_items=3, pushed_stack_items=1)\n    MULMOD = Opcode(0x09, popped_stack_items=3, pushed_stack_items=1)\n    EXP = Opcode(0x0A, popped_stack_items=2, pushed_stack_items=1)\n    SIGNEXTEND = Opcode(0x0B, popped_stack_items=2, pushed_stack_items=1)\n\n    LT = Opcode(0x10, popped_stack_items=2, pushed_stack_items=1)\n    GT = Opcode(0x11, popped_stack_items=2, pushed_stack_items=1)\n    SLT = Opcode(0x12, popped_stack_items=2, pushed_stack_items=1)\n    SGT = Opcode(0x13, popped_stack_items=2, pushed_stack_items=1)\n    EQ = Opcode(0x14, popped_stack_items=2, pushed_stack_items=1)\n    ISZERO = Opcode(0x15, popped_stack_items=1, pushed_stack_items=1)\n    AND = Opcode(0x16, popped_stack_items=2, pushed_stack_items=1)\n    OR = Opcode(0x17, popped_stack_items=2, pushed_stack_items=1)\n    XOR = Opcode(0x18, popped_stack_items=2, pushed_stack_items=1)\n    NOT = Opcode(0x19, popped_stack_items=1, pushed_stack_items=1)\n    BYTE = Opcode(0x1A, popped_stack_items=2, pushed_stack_items=1)\n    SHL = Opcode(0x1B, popped_stack_items=2, pushed_stack_items=1)\n    SHR = Opcode(0x1C, popped_stack_items=2, pushed_stack_items=1)\n    SAR = Opcode(0x1D, popped_stack_items=2, pushed_stack_items=1)\n\n    SHA3 = Opcode(0x20, popped_stack_items=2, pushed_stack_items=1)\n\n    ADDRESS = Opcode(0x30, pushed_stack_items=1)\n    BALANCE = Opcode(0x31, popped_stack_items=1, pushed_stack_items=1)\n    ORIGIN = Opcode(0x32, pushed_stack_items=1)\n    CALLER = Opcode(0x33, pushed_stack_items=1)\n    CALLVALUE = Opcode(0x34, pushed_stack_items=1)\n    CALLDATALOAD = Opcode(0x35, popped_stack_items=1, pushed_stack_items=1)\n    CALLDATASIZE = Opcode(0x36, pushed_stack_items=1)\n    CALLDATACOPY = Opcode(0x37, popped_stack_items=3)\n    CODESIZE = Opcode(0x38, pushed_stack_items=1)\n    CODECOPY = Opcode(0x39, popped_stack_items=3)\n    GASPRICE = Opcode(0x3A, pushed_stack_items=1)\n    EXTCODESIZE = Opcode(0x3B, popped_stack_items=1, pushed_stack_items=1)\n    EXTCODECOPY = Opcode(0x3C, popped_stack_items=4)\n    RETURNDATASIZE = Opcode(0x3D, pushed_stack_items=1)\n    RETURNDATACOPY = Opcode(0x3E, popped_stack_items=3)\n    EXTCODEHASH = Opcode(0x3F, popped_stack_items=1, pushed_stack_items=1)\n\n    BLOCKHASH = Opcode(0x40, popped_stack_items=1, pushed_stack_items=1)\n    COINBASE = Opcode(0x41, pushed_stack_items=1)\n    TIMESTAMP = Opcode(0x42, pushed_stack_items=1)\n    NUMBER = Opcode(0x43, pushed_stack_items=1)\n    PREVRANDAO = Opcode(0x44, pushed_stack_items=1)\n    GASLIMIT = Opcode(0x45, pushed_stack_items=1)\n    CHAINID = Opcode(0x46, pushed_stack_items=1)\n    SELFBALANCE = Opcode(0x47, pushed_stack_items=1)\n    BASEFEE = Opcode(0x48, pushed_stack_items=1)\n    BLOBHASH = Opcode(0x49, popped_stack_items=1, pushed_stack_items=1)\n\n    POP = Opcode(0x50, popped_stack_items=1)\n    MLOAD = Opcode(0x51, popped_stack_items=1, pushed_stack_items=1)\n    MSTORE = Opcode(0x52, popped_stack_items=2)\n    MSTORE8 = Opcode(0x53, popped_stack_items=2)\n    SLOAD = Opcode(0x54, popped_stack_items=1, pushed_stack_items=1)\n    SSTORE = Opcode(0x55, popped_stack_items=2)\n    JUMP = Opcode(0x56, popped_stack_items=1)\n    JUMPI = Opcode(0x57, popped_stack_items=2)\n    PC = Opcode(0x58, pushed_stack_items=1)\n    MSIZE = Opcode(0x59, pushed_stack_items=1)\n    GAS = Opcode(0x5A, pushed_stack_items=1)\n    JUMPDEST = Opcode(0x5B)\n    RJUMP = Opcode(0x5C, data_portion_length=2)\n    RJUMPI = Opcode(0x5D, popped_stack_items=1, data_portion_length=2)\n    CALLF = Opcode(0x5E, data_portion_length=2)\n    RETF = Opcode(0x49)\n\n    PUSH0 = Opcode(0x5F, pushed_stack_items=1)\n    PUSH1 = Opcode(0x60, pushed_stack_items=1, data_portion_length=1)\n    PUSH2 = Opcode(0x61, pushed_stack_items=1, data_portion_length=2)\n    PUSH3 = Opcode(0x62, pushed_stack_items=1, data_portion_length=3)\n    PUSH4 = Opcode(0x63, pushed_stack_items=1, data_portion_length=4)\n    PUSH5 = Opcode(0x64, pushed_stack_items=1, data_portion_length=5)\n    PUSH6 = Opcode(0x65, pushed_stack_items=1, data_portion_length=6)\n    PUSH7 = Opcode(0x66, pushed_stack_items=1, data_portion_length=7)\n    PUSH8 = Opcode(0x67, pushed_stack_items=1, data_portion_length=8)\n    PUSH9 = Opcode(0x68, pushed_stack_items=1, data_portion_length=9)\n    PUSH10 = Opcode(0x69, pushed_stack_items=1, data_portion_length=10)\n    PUSH11 = Opcode(0x6A, pushed_stack_items=1, data_portion_length=11)\n    PUSH12 = Opcode(0x6B, pushed_stack_items=1, data_portion_length=12)\n    PUSH13 = Opcode(0x6C, pushed_stack_items=1, data_portion_length=13)\n    PUSH14 = Opcode(0x6D, pushed_stack_items=1, data_portion_length=14)\n    PUSH15 = Opcode(0x6E, pushed_stack_items=1, data_portion_length=15)\n    PUSH16 = Opcode(0x6F, pushed_stack_items=1, data_portion_length=16)\n    PUSH17 = Opcode(0x70, pushed_stack_items=1, data_portion_length=17)\n    PUSH18 = Opcode(0x71, pushed_stack_items=1, data_portion_length=18)\n    PUSH19 = Opcode(0x72, pushed_stack_items=1, data_portion_length=19)\n    PUSH20 = Opcode(0x73, pushed_stack_items=1, data_portion_length=20)\n    PUSH21 = Opcode(0x74, pushed_stack_items=1, data_portion_length=21)\n    PUSH22 = Opcode(0x75, pushed_stack_items=1, data_portion_length=22)\n    PUSH23 = Opcode(0x76, pushed_stack_items=1, data_portion_length=23)\n    PUSH24 = Opcode(0x77, pushed_stack_items=1, data_portion_length=24)\n    PUSH25 = Opcode(0x78, pushed_stack_items=1, data_portion_length=25)\n    PUSH26 = Opcode(0x79, pushed_stack_items=1, data_portion_length=26)\n    PUSH27 = Opcode(0x7A, pushed_stack_items=1, data_portion_length=27)\n    PUSH28 = Opcode(0x7B, pushed_stack_items=1, data_portion_length=28)\n    PUSH29 = Opcode(0x7C, pushed_stack_items=1, data_portion_length=29)\n    PUSH30 = Opcode(0x7D, pushed_stack_items=1, data_portion_length=30)\n    PUSH31 = Opcode(0x7E, pushed_stack_items=1, data_portion_length=31)\n    PUSH32 = Opcode(0x7F, pushed_stack_items=1, data_portion_length=32)\n\n    DUP1 = Opcode(0x80, pushed_stack_items=1, min_stack_height=1)\n    DUP2 = Opcode(0x81, pushed_stack_items=1, min_stack_height=2)\n    DUP3 = Opcode(0x82, pushed_stack_items=1, min_stack_height=3)\n    DUP4 = Opcode(0x83, pushed_stack_items=1, min_stack_height=4)\n    DUP5 = Opcode(0x84, pushed_stack_items=1, min_stack_height=5)\n    DUP6 = Opcode(0x85, pushed_stack_items=1, min_stack_height=6)\n    DUP7 = Opcode(0x86, pushed_stack_items=1, min_stack_height=7)\n    DUP8 = Opcode(0x87, pushed_stack_items=1, min_stack_height=8)\n    DUP9 = Opcode(0x88, pushed_stack_items=1, min_stack_height=9)\n    DUP10 = Opcode(0x89, pushed_stack_items=1, min_stack_height=10)\n    DUP11 = Opcode(0x8A, pushed_stack_items=1, min_stack_height=11)\n    DUP12 = Opcode(0x8B, pushed_stack_items=1, min_stack_height=12)\n    DUP13 = Opcode(0x8C, pushed_stack_items=1, min_stack_height=13)\n    DUP14 = Opcode(0x8D, pushed_stack_items=1, min_stack_height=14)\n    DUP15 = Opcode(0x8E, pushed_stack_items=1, min_stack_height=15)\n    DUP16 = Opcode(0x8F, pushed_stack_items=1, min_stack_height=16)\n\n    SWAP1 = Opcode(0x90, min_stack_height=2)\n    SWAP2 = Opcode(0x91, min_stack_height=3)\n    SWAP3 = Opcode(0x92, min_stack_height=4)\n    SWAP4 = Opcode(0x93, min_stack_height=5)\n    SWAP5 = Opcode(0x94, min_stack_height=6)\n    SWAP6 = Opcode(0x95, min_stack_height=7)\n    SWAP7 = Opcode(0x96, min_stack_height=8)\n    SWAP8 = Opcode(0x97, min_stack_height=9)\n    SWAP9 = Opcode(0x98, min_stack_height=10)\n    SWAP10 = Opcode(0x99, min_stack_height=11)\n    SWAP11 = Opcode(0x9A, min_stack_height=12)\n    SWAP12 = Opcode(0x9B, min_stack_height=13)\n    SWAP13 = Opcode(0x9C, min_stack_height=14)\n    SWAP14 = Opcode(0x9D, min_stack_height=15)\n    SWAP15 = Opcode(0x9E, min_stack_height=16)\n    SWAP16 = Opcode(0x9F, min_stack_height=17)\n\n    LOG0 = Opcode(0xA0, popped_stack_items=2)\n    LOG1 = Opcode(0xA1, popped_stack_items=3)\n    LOG2 = Opcode(0xA2, popped_stack_items=4)\n    LOG3 = Opcode(0xA3, popped_stack_items=5)\n    LOG4 = Opcode(0xA4, popped_stack_items=6)\n\n    TLOAD = Opcode(0xB3, popped_stack_items=1, pushed_stack_items=1)\n    TSTORE = Opcode(0xB4, popped_stack_items=2)\n\n    CREATE = Opcode(0xF0, popped_stack_items=3, pushed_stack_items=1)\n    CALL = Opcode(0xF1, popped_stack_items=7, pushed_stack_items=1)\n    CALLCODE = Opcode(0xF2, popped_stack_items=7, pushed_stack_items=1)\n    RETURN = Opcode(0xF3, popped_stack_items=2)\n    DELEGATECALL = Opcode(0xF4, popped_stack_items=6, pushed_stack_items=1)\n    CREATE2 = Opcode(0xF5, popped_stack_items=4, pushed_stack_items=1)\n\n    STATICCALL = Opcode(0xFA, popped_stack_items=6, pushed_stack_items=1)\n\n    REVERT = Opcode(0xFD, popped_stack_items=2)\n    INVALID = Opcode(0xFE)\n\n    SELFDESTRUCT = Opcode(0xFF, popped_stack_items=1)\n    SENDALL = Opcode(0xFF, popped_stack_items=1)\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.Account","title":"Account","text":"

State associated with an address.

Source code in src/ethereum_test_tools/common/types.py
class Account:\n\"\"\"\n    State associated with an address.\n    \"\"\"\n\n    nonce: int | None = None\n\"\"\"\n    The scalar value equal to a) the number of transactions sent by\n    an Externally Owned Account, b) the amount of contracts created by a\n    contract.\n    \"\"\"\n    balance: int | None = None\n\"\"\"\n    The amount of Wei (10<sup>-18</sup> Eth) the account has.\n    \"\"\"\n    code: str | bytes | Code | None = None\n\"\"\"\n    Bytecode contained by the account.\n    \"\"\"\n    storage: Storage | None = None\n\"\"\"\n    Storage within a contract.\n    \"\"\"\n\n    NONEXISTENT: ClassVar[object] = object()\n\"\"\"\n    Sentinel object used to specify when an account should not exist in the\n    state.\n    \"\"\"\n\n    class NonceMismatch(Exception):\n\"\"\"\n        Test expected a certain nonce value for an account but a different\n        value was found.\n        \"\"\"\n\n        address: str\n        want: int | None\n        got: int | None\n\n        def __init__(self, address: str, want: int | None, got: int | None, *args):\n            super().__init__(args)\n            self.address = address\n            self.want = want\n            self.got = got\n\n        def __str__(self):\n\"\"\"Print exception string\"\"\"\n            return (\n                f\"unexpected nonce for account {self.address}: \"\n                + f\"want {self.want}, got {self.got}\"\n            )\n\n    class BalanceMismatch(Exception):\n\"\"\"\n        Test expected a certain balance for an account but a different\n        value was found.\n        \"\"\"\n\n        address: str\n        want: int | None\n        got: int | None\n\n        def __init__(self, address: str, want: int | None, got: int | None, *args):\n            super().__init__(args)\n            self.address = address\n            self.want = want\n            self.got = got\n\n        def __str__(self):\n\"\"\"Print exception string\"\"\"\n            return (\n                f\"unexpected balance for account {self.address}: \"\n                + f\"want {self.want}, got {self.got}\"\n            )\n\n    class CodeMismatch(Exception):\n\"\"\"\n        Test expected a certain bytecode for an account but a different\n        one was found.\n        \"\"\"\n\n        address: str\n        want: str | None\n        got: str | None\n\n        def __init__(self, address: str, want: str | None, got: str | None, *args):\n            super().__init__(args)\n            self.address = address\n            self.want = want\n            self.got = got\n\n        def __str__(self):\n\"\"\"Print exception string\"\"\"\n            return (\n                f\"unexpected code for account {self.address}: \"\n                + f\"want {self.want}, got {self.got}\"\n            )\n\n    def __init__(\n        self,\n        *,\n        nonce: int | None = None,\n        balance: int | None = None,\n        code: str | bytes | Code | None = None,\n        storage: Storage | Dict[str | int | bytes, str | int | bytes] | None = None,\n    ) -> None:\n\"\"\"Init account members\"\"\"\n        self.nonce = nonce\n        self.balance = balance\n        self.code = code\n        if storage is not None and type(storage) is dict:\n            self.storage = Storage(storage)\n\n    def check_alloc(self: \"Account\", address: str, alloc: dict):\n\"\"\"\n        Checks the returned alloc against an expected account in post state.\n        Raises exception on failure.\n        \"\"\"\n        if self.nonce is not None:\n            actual_nonce = int_or_none(alloc.get(\"nonce\"), 0)\n            if self.nonce != actual_nonce:\n                raise Account.NonceMismatch(\n                    address=address,\n                    want=self.nonce,\n                    got=actual_nonce,\n                )\n\n        if self.balance is not None:\n            actual_balance = int_or_none(alloc.get(\"balance\"), 0)\n            if self.balance != actual_balance:\n                raise Account.BalanceMismatch(\n                    address=address,\n                    want=self.balance,\n                    got=actual_balance,\n                )\n\n        if self.code is not None:\n            expected_code = code_to_hex(self.code)\n            actual_code = str_or_none(alloc.get(\"code\"), \"0x\")\n            if expected_code != actual_code:\n                raise Account.CodeMismatch(\n                    address=address,\n                    want=expected_code,\n                    got=actual_code,\n                )\n\n        if self.storage is not None:\n            expected_storage = (\n                self.storage if isinstance(self.storage, Storage) else Storage(self.storage)\n            )\n            actual_storage = Storage(alloc[\"storage\"]) if \"storage\" in alloc else Storage({})\n            expected_storage.must_be_equal(actual_storage)\n\n    @classmethod\n    def with_code(cls: Type, code: bytes | str | Code) -> \"Account\":\n\"\"\"\n        Create account with provided `code` and nonce of `1`.\n        \"\"\"\n        return Account(nonce=1, code=code)\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Account.storage","title":"storage: Storage | None = None instance-attribute class-attribute","text":"

Storage within a contract.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Account.NONEXISTENT","title":"NONEXISTENT: object = object() class-attribute","text":"

Sentinel object used to specify when an account should not exist in the state.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Account.NonceMismatch","title":"NonceMismatch","text":"

Bases: Exception

Test expected a certain nonce value for an account but a different value was found.

Source code in src/ethereum_test_tools/common/types.py
class NonceMismatch(Exception):\n\"\"\"\n    Test expected a certain nonce value for an account but a different\n    value was found.\n    \"\"\"\n\n    address: str\n    want: int | None\n    got: int | None\n\n    def __init__(self, address: str, want: int | None, got: int | None, *args):\n        super().__init__(args)\n        self.address = address\n        self.want = want\n        self.got = got\n\n    def __str__(self):\n\"\"\"Print exception string\"\"\"\n        return (\n            f\"unexpected nonce for account {self.address}: \"\n            + f\"want {self.want}, got {self.got}\"\n        )\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Account.NonceMismatch.__str__","title":"__str__()","text":"

Print exception string

Source code in src/ethereum_test_tools/common/types.py
def __str__(self):\n\"\"\"Print exception string\"\"\"\n    return (\n        f\"unexpected nonce for account {self.address}: \"\n        + f\"want {self.want}, got {self.got}\"\n    )\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Account.BalanceMismatch","title":"BalanceMismatch","text":"

Bases: Exception

Test expected a certain balance for an account but a different value was found.

Source code in src/ethereum_test_tools/common/types.py
class BalanceMismatch(Exception):\n\"\"\"\n    Test expected a certain balance for an account but a different\n    value was found.\n    \"\"\"\n\n    address: str\n    want: int | None\n    got: int | None\n\n    def __init__(self, address: str, want: int | None, got: int | None, *args):\n        super().__init__(args)\n        self.address = address\n        self.want = want\n        self.got = got\n\n    def __str__(self):\n\"\"\"Print exception string\"\"\"\n        return (\n            f\"unexpected balance for account {self.address}: \"\n            + f\"want {self.want}, got {self.got}\"\n        )\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Account.BalanceMismatch.__str__","title":"__str__()","text":"

Print exception string

Source code in src/ethereum_test_tools/common/types.py
def __str__(self):\n\"\"\"Print exception string\"\"\"\n    return (\n        f\"unexpected balance for account {self.address}: \"\n        + f\"want {self.want}, got {self.got}\"\n    )\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Account.CodeMismatch","title":"CodeMismatch","text":"

Bases: Exception

Test expected a certain bytecode for an account but a different one was found.

Source code in src/ethereum_test_tools/common/types.py
class CodeMismatch(Exception):\n\"\"\"\n    Test expected a certain bytecode for an account but a different\n    one was found.\n    \"\"\"\n\n    address: str\n    want: str | None\n    got: str | None\n\n    def __init__(self, address: str, want: str | None, got: str | None, *args):\n        super().__init__(args)\n        self.address = address\n        self.want = want\n        self.got = got\n\n    def __str__(self):\n\"\"\"Print exception string\"\"\"\n        return (\n            f\"unexpected code for account {self.address}: \"\n            + f\"want {self.want}, got {self.got}\"\n        )\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Account.CodeMismatch.__str__","title":"__str__()","text":"

Print exception string

Source code in src/ethereum_test_tools/common/types.py
def __str__(self):\n\"\"\"Print exception string\"\"\"\n    return (\n        f\"unexpected code for account {self.address}: \"\n        + f\"want {self.want}, got {self.got}\"\n    )\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Account.__init__","title":"__init__(*, nonce=None, balance=None, code=None, storage=None)","text":"

Init account members

Source code in src/ethereum_test_tools/common/types.py
def __init__(\n    self,\n    *,\n    nonce: int | None = None,\n    balance: int | None = None,\n    code: str | bytes | Code | None = None,\n    storage: Storage | Dict[str | int | bytes, str | int | bytes] | None = None,\n) -> None:\n\"\"\"Init account members\"\"\"\n    self.nonce = nonce\n    self.balance = balance\n    self.code = code\n    if storage is not None and type(storage) is dict:\n        self.storage = Storage(storage)\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Account.nonce","title":"nonce: int | None = nonce instance-attribute class-attribute","text":"

The scalar value equal to a) the number of transactions sent by an Externally Owned Account, b) the amount of contracts created by a contract.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Account.balance","title":"balance: int | None = balance instance-attribute class-attribute","text":"

The amount of Wei (10-18 Eth) the account has.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Account.code","title":"code: str | bytes | Code | None = code instance-attribute class-attribute","text":"

Bytecode contained by the account.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Account.check_alloc","title":"check_alloc(address, alloc)","text":"

Checks the returned alloc against an expected account in post state. Raises exception on failure.

Source code in src/ethereum_test_tools/common/types.py
def check_alloc(self: \"Account\", address: str, alloc: dict):\n\"\"\"\n    Checks the returned alloc against an expected account in post state.\n    Raises exception on failure.\n    \"\"\"\n    if self.nonce is not None:\n        actual_nonce = int_or_none(alloc.get(\"nonce\"), 0)\n        if self.nonce != actual_nonce:\n            raise Account.NonceMismatch(\n                address=address,\n                want=self.nonce,\n                got=actual_nonce,\n            )\n\n    if self.balance is not None:\n        actual_balance = int_or_none(alloc.get(\"balance\"), 0)\n        if self.balance != actual_balance:\n            raise Account.BalanceMismatch(\n                address=address,\n                want=self.balance,\n                got=actual_balance,\n            )\n\n    if self.code is not None:\n        expected_code = code_to_hex(self.code)\n        actual_code = str_or_none(alloc.get(\"code\"), \"0x\")\n        if expected_code != actual_code:\n            raise Account.CodeMismatch(\n                address=address,\n                want=expected_code,\n                got=actual_code,\n            )\n\n    if self.storage is not None:\n        expected_storage = (\n            self.storage if isinstance(self.storage, Storage) else Storage(self.storage)\n        )\n        actual_storage = Storage(alloc[\"storage\"]) if \"storage\" in alloc else Storage({})\n        expected_storage.must_be_equal(actual_storage)\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Account.with_code","title":"with_code(code) classmethod","text":"

Create account with provided code and nonce of 1.

Source code in src/ethereum_test_tools/common/types.py
@classmethod\ndef with_code(cls: Type, code: bytes | str | Code) -> \"Account\":\n\"\"\"\n    Create account with provided `code` and nonce of `1`.\n    \"\"\"\n    return Account(nonce=1, code=code)\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.Withdrawal","title":"Withdrawal dataclass","text":"

Structure to represent a single withdrawal of a validator's balance from the beacon chain.

Source code in src/ethereum_test_tools/common/types.py
@dataclass(kw_only=True)\nclass Withdrawal:\n\"\"\"\n    Structure to represent a single withdrawal of a validator's balance from\n    the beacon chain.\n    \"\"\"\n\n    index: int\n    validator: int\n    address: str\n    amount: int\n\n    def to_serializable_list(self) -> List[Any]:\n\"\"\"\n        Returns a list of the withdrawal's attributes in the order they should\n        be serialized.\n        \"\"\"\n        return [\n            Uint(self.index),\n            Uint(self.validator),\n            bytes.fromhex(self.address[2:]),\n            Uint(self.amount),\n        ]\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Withdrawal.to_serializable_list","title":"to_serializable_list()","text":"

Returns a list of the withdrawal's attributes in the order they should be serialized.

Source code in src/ethereum_test_tools/common/types.py
def to_serializable_list(self) -> List[Any]:\n\"\"\"\n    Returns a list of the withdrawal's attributes in the order they should\n    be serialized.\n    \"\"\"\n    return [\n        Uint(self.index),\n        Uint(self.validator),\n        bytes.fromhex(self.address[2:]),\n        Uint(self.amount),\n    ]\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.Environment","title":"Environment dataclass","text":"

Structure used to keep track of the context in which a block must be executed.

Source code in src/ethereum_test_tools/common/types.py
@dataclass(kw_only=True)\nclass Environment:\n\"\"\"\n    Structure used to keep track of the context in which a block\n    must be executed.\n    \"\"\"\n\n    coinbase: str | bytes = \"0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba\"\n    gas_limit: int = 100000000000000000\n    number: int = 1\n    timestamp: int = 1000\n    difficulty: Optional[int] = None\n    prev_randao: Optional[int] = None\n    block_hashes: Dict[int, bytes] = field(default_factory=dict)\n    base_fee: Optional[int] = None\n    parent_difficulty: Optional[int] = None\n    parent_timestamp: Optional[int] = None\n    parent_base_fee: Optional[int] = None\n    parent_gas_used: Optional[int] = None\n    parent_gas_limit: Optional[int] = None\n    parent_ommers_hash: Optional[str | bytes] = None\n    withdrawals: Optional[List[Withdrawal]] = None\n    parent_data_gas_used: Optional[int] = None\n    parent_excess_data_gas: Optional[int] = None\n    excess_data_gas: Optional[int] = None\n    data_gas_used: Optional[int] = None\n\n    @staticmethod\n    def from_parent_header(parent: \"FixtureHeader\") -> \"Environment\":\n\"\"\"\n        Instantiates a new environment with the provided header as parent.\n        \"\"\"\n        return Environment(\n            parent_difficulty=parent.difficulty,\n            parent_timestamp=parent.timestamp,\n            parent_base_fee=parent.base_fee,\n            parent_data_gas_used=parent.data_gas_used,\n            parent_excess_data_gas=parent.excess_data_gas,\n            parent_gas_used=parent.gas_used,\n            parent_gas_limit=parent.gas_limit,\n            parent_ommers_hash=parent.ommers_hash,\n            block_hashes={\n                parent.number: parent.hash if parent.hash is not None else bytes([0] * 32)\n            },\n        )\n\n    def parent_hash(self) -> bytes:\n\"\"\"\n        Obtjains the latest hash according to the highest block number in\n        `block_hashes`.\n        \"\"\"\n        if len(self.block_hashes) == 0:\n            return bytes([0] * 32)\n\n        last_index = max(self.block_hashes.keys())\n        return self.block_hashes[last_index]\n\n    def apply_new_parent(self, new_parent: \"FixtureHeader\") -> \"Environment\":\n\"\"\"\n        Applies a header as parent to a copy of this environment.\n        \"\"\"\n        env = copy(self)\n        env.parent_difficulty = new_parent.difficulty\n        env.parent_timestamp = new_parent.timestamp\n        env.parent_base_fee = new_parent.base_fee\n        env.parent_data_gas_used = new_parent.data_gas_used\n        env.parent_excess_data_gas = new_parent.excess_data_gas\n        env.parent_gas_used = new_parent.gas_used\n        env.parent_gas_limit = new_parent.gas_limit\n        env.parent_ommers_hash = new_parent.ommers_hash\n        env.block_hashes[new_parent.number] = (\n            new_parent.hash if new_parent.hash is not None else bytes([0] * 32)\n        )\n        return env\n\n    def set_fork_requirements(self, fork: Fork) -> \"Environment\":\n\"\"\"\n        Fills the required fields in an environment depending on the fork.\n        \"\"\"\n        res = copy(self)\n\n        if (\n            fork.header_prev_randao_required(self.number, self.timestamp)\n            and res.prev_randao is None\n        ):\n            res.prev_randao = 0\n\n        if (\n            fork.header_withdrawals_required(self.number, self.timestamp)\n            and res.withdrawals is None\n        ):\n            res.withdrawals = []\n\n        if (\n            fork.header_base_fee_required(self.number, self.timestamp)\n            and res.base_fee is None\n            and res.parent_base_fee is None\n        ):\n            res.base_fee = DEFAULT_BASE_FEE\n\n        if fork.header_zero_difficulty_required(self.number, self.timestamp):\n            res.difficulty = 0\n\n        if (\n            fork.header_excess_data_gas_required(self.number, self.timestamp)\n            and res.excess_data_gas is None\n            and res.parent_excess_data_gas is None\n        ):\n            res.excess_data_gas = 0\n\n        if (\n            fork.header_data_gas_used_required(self.number, self.timestamp)\n            and res.data_gas_used is None\n            and res.parent_data_gas_used is None\n        ):\n            res.data_gas_used = 0\n\n        return res\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Environment.from_parent_header","title":"from_parent_header(parent) staticmethod","text":"

Instantiates a new environment with the provided header as parent.

Source code in src/ethereum_test_tools/common/types.py
@staticmethod\ndef from_parent_header(parent: \"FixtureHeader\") -> \"Environment\":\n\"\"\"\n    Instantiates a new environment with the provided header as parent.\n    \"\"\"\n    return Environment(\n        parent_difficulty=parent.difficulty,\n        parent_timestamp=parent.timestamp,\n        parent_base_fee=parent.base_fee,\n        parent_data_gas_used=parent.data_gas_used,\n        parent_excess_data_gas=parent.excess_data_gas,\n        parent_gas_used=parent.gas_used,\n        parent_gas_limit=parent.gas_limit,\n        parent_ommers_hash=parent.ommers_hash,\n        block_hashes={\n            parent.number: parent.hash if parent.hash is not None else bytes([0] * 32)\n        },\n    )\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Environment.parent_hash","title":"parent_hash()","text":"

Obtjains the latest hash according to the highest block number in block_hashes.

Source code in src/ethereum_test_tools/common/types.py
def parent_hash(self) -> bytes:\n\"\"\"\n    Obtjains the latest hash according to the highest block number in\n    `block_hashes`.\n    \"\"\"\n    if len(self.block_hashes) == 0:\n        return bytes([0] * 32)\n\n    last_index = max(self.block_hashes.keys())\n    return self.block_hashes[last_index]\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Environment.apply_new_parent","title":"apply_new_parent(new_parent)","text":"

Applies a header as parent to a copy of this environment.

Source code in src/ethereum_test_tools/common/types.py
def apply_new_parent(self, new_parent: \"FixtureHeader\") -> \"Environment\":\n\"\"\"\n    Applies a header as parent to a copy of this environment.\n    \"\"\"\n    env = copy(self)\n    env.parent_difficulty = new_parent.difficulty\n    env.parent_timestamp = new_parent.timestamp\n    env.parent_base_fee = new_parent.base_fee\n    env.parent_data_gas_used = new_parent.data_gas_used\n    env.parent_excess_data_gas = new_parent.excess_data_gas\n    env.parent_gas_used = new_parent.gas_used\n    env.parent_gas_limit = new_parent.gas_limit\n    env.parent_ommers_hash = new_parent.ommers_hash\n    env.block_hashes[new_parent.number] = (\n        new_parent.hash if new_parent.hash is not None else bytes([0] * 32)\n    )\n    return env\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Environment.set_fork_requirements","title":"set_fork_requirements(fork)","text":"

Fills the required fields in an environment depending on the fork.

Source code in src/ethereum_test_tools/common/types.py
def set_fork_requirements(self, fork: Fork) -> \"Environment\":\n\"\"\"\n    Fills the required fields in an environment depending on the fork.\n    \"\"\"\n    res = copy(self)\n\n    if (\n        fork.header_prev_randao_required(self.number, self.timestamp)\n        and res.prev_randao is None\n    ):\n        res.prev_randao = 0\n\n    if (\n        fork.header_withdrawals_required(self.number, self.timestamp)\n        and res.withdrawals is None\n    ):\n        res.withdrawals = []\n\n    if (\n        fork.header_base_fee_required(self.number, self.timestamp)\n        and res.base_fee is None\n        and res.parent_base_fee is None\n    ):\n        res.base_fee = DEFAULT_BASE_FEE\n\n    if fork.header_zero_difficulty_required(self.number, self.timestamp):\n        res.difficulty = 0\n\n    if (\n        fork.header_excess_data_gas_required(self.number, self.timestamp)\n        and res.excess_data_gas is None\n        and res.parent_excess_data_gas is None\n    ):\n        res.excess_data_gas = 0\n\n    if (\n        fork.header_data_gas_used_required(self.number, self.timestamp)\n        and res.data_gas_used is None\n        and res.parent_data_gas_used is None\n    ):\n        res.data_gas_used = 0\n\n    return res\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.AccessList","title":"AccessList","text":"

Access List for transactions.

Source code in src/ethereum_test_tools/common/types.py
class AccessList:\n\"\"\"\n    Access List for transactions.\n    \"\"\"\n\n    address: bytes\n    storage_keys: List[bytes]\n\n    def __init__(\n        self,\n        *,\n        address: str | int | bytes,\n        storage_keys: List[str | int | bytes],\n    ) -> None:\n\"\"\"\n        Ensures the access list has the correct byte length for each field.\n        \"\"\"\n        self.address = address_to_bytes(address)\n        self.storage_keys = [hash_to_bytes(key) for key in storage_keys]\n\n    def to_list(self) -> List[bytes | List[bytes]]:\n\"\"\"\n        Returns the access list as a list of serializable elements.\n        \"\"\"\n        return [self.address, self.storage_keys]\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.AccessList.__init__","title":"__init__(*, address, storage_keys)","text":"

Ensures the access list has the correct byte length for each field.

Source code in src/ethereum_test_tools/common/types.py
def __init__(\n    self,\n    *,\n    address: str | int | bytes,\n    storage_keys: List[str | int | bytes],\n) -> None:\n\"\"\"\n    Ensures the access list has the correct byte length for each field.\n    \"\"\"\n    self.address = address_to_bytes(address)\n    self.storage_keys = [hash_to_bytes(key) for key in storage_keys]\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.AccessList.to_list","title":"to_list()","text":"

Returns the access list as a list of serializable elements.

Source code in src/ethereum_test_tools/common/types.py
def to_list(self) -> List[bytes | List[bytes]]:\n\"\"\"\n    Returns the access list as a list of serializable elements.\n    \"\"\"\n    return [self.address, self.storage_keys]\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.Transaction","title":"Transaction dataclass","text":"

Generic object that can represent all Ethereum transaction types.

Source code in src/ethereum_test_tools/common/types.py
@dataclass(kw_only=True)\nclass Transaction:\n\"\"\"\n    Generic object that can represent all Ethereum transaction types.\n    \"\"\"\n\n    ty: Optional[int] = None\n\"\"\"\n    Transaction type value.\n    \"\"\"\n    chain_id: int = 1\n    nonce: int = 0\n    to: Optional[str | int] = AddrAA\n    value: int = 0\n    data: bytes | str | Code = bytes()\n    gas_limit: int = 21000\n    access_list: Optional[List[AccessList]] = None\n\n    gas_price: Optional[int] = None\n    max_fee_per_gas: Optional[int] = None\n    max_priority_fee_per_gas: Optional[int] = None\n\n    max_fee_per_data_gas: Optional[int] = None\n    blob_versioned_hashes: Optional[Sequence[str | bytes]] = None\n\n    wrapped_blob_transaction: bool = False\n    blobs: Optional[Sequence[bytes]] = None\n    blob_kzg_commitments: Optional[Sequence[bytes]] = None\n    blob_kzg_proofs: Optional[Sequence[bytes]] = None\n\n    signature: Optional[Tuple[int, int, int]] = None\n    secret_key: Optional[str] = None\n    sender: Optional[str | bytes] = None\n    protected: bool = True\n    error: Optional[str] = None\n\n    class InvalidFeePayment(Exception):\n\"\"\"\n        Transaction described more than one fee payment type.\n        \"\"\"\n\n        def __str__(self):\n\"\"\"Print exception string\"\"\"\n            return \"only one type of fee payment field can be used in a single tx\"\n\n    class InvalidSignaturePrivateKey(Exception):\n\"\"\"\n        Transaction describes both the signature and private key of\n        source account.\n        \"\"\"\n\n        def __str__(self):\n\"\"\"Print exception string\"\"\"\n            return \"can't define both 'signature' and 'private_key'\"\n\n    def __post_init__(self) -> None:\n\"\"\"\n        Ensures the transaction has no conflicting properties.\n        \"\"\"\n        if (\n            self.gas_price is not None\n            and self.max_fee_per_gas is not None\n            and self.max_priority_fee_per_gas is not None\n        ):\n            raise Transaction.InvalidFeePayment()\n\n        if (\n            self.gas_price is None\n            and self.max_fee_per_gas is None\n            and self.max_priority_fee_per_gas is None\n        ):\n            self.gas_price = 10\n\n        if self.signature is not None and self.secret_key is not None:\n            raise Transaction.InvalidSignaturePrivateKey()\n\n        if self.signature is None and self.secret_key is None:\n            self.secret_key = TestPrivateKey\n\n        if self.ty is None:\n            # Try to deduce transaction type from included fields\n            if self.max_fee_per_data_gas is not None:\n                self.ty = 3\n            elif self.max_fee_per_gas is not None:\n                self.ty = 2\n            elif self.access_list is not None:\n                self.ty = 1\n            else:\n                self.ty = 0\n\n    def with_error(self, error: str) -> \"Transaction\":\n\"\"\"\n        Create a copy of the transaction with an added error.\n        \"\"\"\n        tx = copy(self)\n        tx.error = error\n        return tx\n\n    def with_nonce(self, nonce: int) -> \"Transaction\":\n\"\"\"\n        Create a copy of the transaction with a modified nonce.\n        \"\"\"\n        tx = copy(self)\n        tx.nonce = nonce\n        return tx\n\n    def with_fields(self, **kwargs) -> \"Transaction\":\n\"\"\"\n        Create a deepcopy of the transaction with modified fields.\n        \"\"\"\n        tx = deepcopy(self)\n        for key, value in kwargs.items():\n            if hasattr(tx, key):\n                setattr(tx, key, value)\n            else:\n                raise ValueError(f\"Invalid field '{key}' for Transaction\")\n        return tx\n\n    def payload_body(self) -> List[Any]:\n\"\"\"\n        Returns the list of values included in the transaction body.\n        \"\"\"\n        if self.signature is None:\n            raise ValueError(\"signature must be set before serializing any tx type\")\n\n        if self.gas_limit is None:\n            raise ValueError(\"gas_limit must be set for all tx types\")\n        to = address_to_bytes(self.to)\n\n        if self.ty == 3:\n            # EIP-4844: https://eips.ethereum.org/EIPS/eip-4844\n            if self.max_priority_fee_per_gas is None:\n                raise ValueError(\"max_priority_fee_per_gas must be set for type 3 tx\")\n            if self.max_fee_per_gas is None:\n                raise ValueError(\"max_fee_per_gas must be set for type 3 tx\")\n            if self.max_fee_per_data_gas is None:\n                raise ValueError(\"max_fee_per_data_gas must be set for type 3 tx\")\n            if self.blob_versioned_hashes is None:\n                raise ValueError(\"blob_versioned_hashes must be set for type 3 tx\")\n\n            if self.wrapped_blob_transaction:\n                if self.blobs is None:\n                    raise ValueError(\"blobs must be set for network version of type 3 tx\")\n                if self.blob_kzg_commitments is None:\n                    raise ValueError(\n                        \"blob_kzg_commitments must be set for network version of type 3 tx\"\n                    )\n                if self.blob_kzg_proofs is None:\n                    raise ValueError(\n                        \"blob_kzg_proofs must be set for network version of type 3 tx\"\n                    )\n\n                return [\n                    [\n                        Uint(self.chain_id),\n                        Uint(self.nonce),\n                        Uint(self.max_priority_fee_per_gas),\n                        Uint(self.max_fee_per_gas),\n                        Uint(self.gas_limit),\n                        to,\n                        Uint(self.value),\n                        code_to_bytes(self.data),\n                        [a.to_list() for a in self.access_list]\n                        if self.access_list is not None\n                        else [],\n                        Uint(self.max_fee_per_data_gas),\n                        [hash_to_bytes(h) for h in self.blob_versioned_hashes],\n                        Uint(self.signature[0]),\n                        Uint(self.signature[1]),\n                        Uint(self.signature[2]),\n                    ],\n                    self.blobs,\n                    self.blob_kzg_commitments,\n                    self.blob_kzg_proofs,\n                ]\n            else:\n                return [\n                    Uint(self.chain_id),\n                    Uint(self.nonce),\n                    Uint(self.max_priority_fee_per_gas),\n                    Uint(self.max_fee_per_gas),\n                    Uint(self.gas_limit),\n                    to,\n                    Uint(self.value),\n                    code_to_bytes(self.data),\n                    [a.to_list() for a in self.access_list]\n                    if self.access_list is not None\n                    else [],\n                    Uint(self.max_fee_per_data_gas),\n                    [hash_to_bytes(h) for h in self.blob_versioned_hashes],\n                    Uint(self.signature[0]),\n                    Uint(self.signature[1]),\n                    Uint(self.signature[2]),\n                ]\n        elif self.ty == 2:\n            # EIP-1559: https://eips.ethereum.org/EIPS/eip-1559\n            if self.max_priority_fee_per_gas is None:\n                raise ValueError(\"max_priority_fee_per_gas must be set for type 3 tx\")\n            if self.max_fee_per_gas is None:\n                raise ValueError(\"max_fee_per_gas must be set for type 3 tx\")\n            return [\n                Uint(self.chain_id),\n                Uint(self.nonce),\n                Uint(self.max_priority_fee_per_gas),\n                Uint(self.max_fee_per_gas),\n                Uint(self.gas_limit),\n                to,\n                Uint(self.value),\n                code_to_bytes(self.data),\n                [a.to_list() for a in self.access_list] if self.access_list is not None else [],\n                Uint(self.signature[0]),\n                Uint(self.signature[1]),\n                Uint(self.signature[2]),\n            ]\n        elif self.ty == 1:\n            # EIP-2930: https://eips.ethereum.org/EIPS/eip-2930\n            if self.gas_price is None:\n                raise ValueError(\"gas_price must be set for type 1 tx\")\n\n            return [\n                Uint(self.chain_id),\n                Uint(self.nonce),\n                Uint(self.gas_price),\n                Uint(self.gas_limit),\n                to,\n                Uint(self.value),\n                code_to_bytes(self.data),\n                [a.to_list() for a in self.access_list] if self.access_list is not None else [],\n                Uint(self.signature[0]),\n                Uint(self.signature[1]),\n                Uint(self.signature[2]),\n            ]\n        elif self.ty == 0:\n            if self.gas_price is None:\n                raise ValueError(\"gas_price must be set for type 0 tx\")\n            # EIP-155: https://eips.ethereum.org/EIPS/eip-155\n            return [\n                Uint(self.nonce),\n                Uint(self.gas_price),\n                Uint(self.gas_limit),\n                to,\n                Uint(self.value),\n                code_to_bytes(self.data),\n                Uint(self.signature[0]),\n                Uint(self.signature[1]),\n                Uint(self.signature[2]),\n            ]\n\n        raise NotImplementedError(f\"serialized_bytes not implemented for tx type {self.ty}\")\n\n    def serialized_bytes(self) -> bytes:\n\"\"\"\n        Returns bytes of the serialized representation of the transaction,\n        which is almost always RLP encoding.\n        \"\"\"\n        if self.ty is None:\n            raise ValueError(\"ty must be set for all tx types\")\n\n        if self.ty > 0:\n            return bytes([self.ty]) + eth_rlp.encode(self.payload_body())\n        else:\n            return eth_rlp.encode(self.payload_body())\n\n    def signing_envelope(self) -> List[Any]:\n\"\"\"\n        Returns the list of values included in the envelope used for signing.\n        \"\"\"\n        if self.gas_limit is None:\n            raise ValueError(\"gas_limit must be set for all tx types\")\n        to = address_to_bytes(self.to)\n\n        if self.ty == 3:\n            # EIP-4844: https://eips.ethereum.org/EIPS/eip-4844\n            if self.max_priority_fee_per_gas is None:\n                raise ValueError(\"max_priority_fee_per_gas must be set for type 3 tx\")\n            if self.max_fee_per_gas is None:\n                raise ValueError(\"max_fee_per_gas must be set for type 3 tx\")\n            if self.max_fee_per_data_gas is None:\n                raise ValueError(\"max_fee_per_data_gas must be set for type 3 tx\")\n            if self.blob_versioned_hashes is None:\n                raise ValueError(\"blob_versioned_hashes must be set for type 3 tx\")\n            return [\n                Uint(self.chain_id),\n                Uint(self.nonce),\n                Uint(self.max_priority_fee_per_gas),\n                Uint(self.max_fee_per_gas),\n                Uint(self.gas_limit),\n                to,\n                Uint(self.value),\n                code_to_bytes(self.data),\n                [a.to_list() for a in self.access_list] if self.access_list is not None else [],\n                Uint(self.max_fee_per_data_gas),\n                [hash_to_bytes(h) for h in self.blob_versioned_hashes],\n            ]\n        elif self.ty == 2:\n            # EIP-1559: https://eips.ethereum.org/EIPS/eip-1559\n            if self.max_priority_fee_per_gas is None:\n                raise ValueError(\"max_priority_fee_per_gas must be set for type 3 tx\")\n            if self.max_fee_per_gas is None:\n                raise ValueError(\"max_fee_per_gas must be set for type 3 tx\")\n            return [\n                Uint(self.chain_id),\n                Uint(self.nonce),\n                Uint(self.max_priority_fee_per_gas),\n                Uint(self.max_fee_per_gas),\n                Uint(self.gas_limit),\n                to,\n                Uint(self.value),\n                code_to_bytes(self.data),\n                [a.to_list() for a in self.access_list] if self.access_list is not None else [],\n            ]\n        elif self.ty == 1:\n            # EIP-2930: https://eips.ethereum.org/EIPS/eip-2930\n            if self.gas_price is None:\n                raise ValueError(\"gas_price must be set for type 1 tx\")\n\n            return [\n                Uint(self.chain_id),\n                Uint(self.nonce),\n                Uint(self.gas_price),\n                Uint(self.gas_limit),\n                to,\n                Uint(self.value),\n                code_to_bytes(self.data),\n                [a.to_list() for a in self.access_list] if self.access_list is not None else [],\n            ]\n        elif self.ty == 0:\n            if self.gas_price is None:\n                raise ValueError(\"gas_price must be set for type 0 tx\")\n\n            if self.protected:\n                # EIP-155: https://eips.ethereum.org/EIPS/eip-155\n                return [\n                    Uint(self.nonce),\n                    Uint(self.gas_price),\n                    Uint(self.gas_limit),\n                    to,\n                    Uint(self.value),\n                    code_to_bytes(self.data),\n                    Uint(self.chain_id),\n                    Uint(0),\n                    Uint(0),\n                ]\n            else:\n                return [\n                    Uint(self.nonce),\n                    Uint(self.gas_price),\n                    Uint(self.gas_limit),\n                    to,\n                    Uint(self.value),\n                    code_to_bytes(self.data),\n                ]\n        raise NotImplementedError(\"sigining for transaction type {self.ty} not implemented\")\n\n    def signing_bytes(self) -> bytes:\n\"\"\"\n        Returns the serialized bytes of the transaction used for signing.\n        \"\"\"\n        if self.ty is None:\n            raise ValueError(\"ty must be set for all tx types\")\n\n        if self.ty > 0:\n            return bytes([self.ty]) + eth_rlp.encode(self.signing_envelope())\n        else:\n            return eth_rlp.encode(self.signing_envelope())\n\n    def with_signature_and_sender(self) -> \"Transaction\":\n\"\"\"\n        Returns a signed version of the transaction using the private key.\n        \"\"\"\n        tx = copy(self)\n\n        if tx.signature is not None:\n            # Transaction already signed\n            if tx.sender is None:\n                # TODO: We need to recover the sender from the signature\n                raise NotImplementedError(\"recovering sender from signature not implemented\")\n            return tx\n\n        if tx.secret_key is None:\n            raise ValueError(\"secret_key must be set to sign a transaction\")\n\n        # Get the signing bytes\n        signing_hash = keccak256(tx.signing_bytes())\n\n        # Sign the bytes\n        private_key = PrivateKey.from_int(hash_to_int(tx.secret_key))\n        signature_bytes = private_key.sign_recoverable(signing_hash, hasher=None)\n        public_key = PublicKey.from_signature_and_message(\n            signature_bytes, signing_hash, hasher=None\n        )\n        tx.sender = keccak256(public_key.format(compressed=False)[1:])[32 - 20 :]\n\n        v, r, s = (\n            signature_bytes[64],\n            int.from_bytes(signature_bytes[0:32], byteorder=\"big\"),\n            int.from_bytes(signature_bytes[32:64], byteorder=\"big\"),\n        )\n        if tx.ty == 0:\n            if tx.protected:\n                v += 35 + (tx.chain_id * 2)\n            else:  # not protected\n                v += 27\n\n        tx.signature = (v, r, s)\n\n        # Remove the secret key because otherwise we might attempt to sign again (?)\n        tx.secret_key = None\n        return tx\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Transaction.ty","title":"ty: Optional[int] = None instance-attribute class-attribute","text":"

Transaction type value.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Transaction.InvalidFeePayment","title":"InvalidFeePayment","text":"

Bases: Exception

Transaction described more than one fee payment type.

Source code in src/ethereum_test_tools/common/types.py
class InvalidFeePayment(Exception):\n\"\"\"\n    Transaction described more than one fee payment type.\n    \"\"\"\n\n    def __str__(self):\n\"\"\"Print exception string\"\"\"\n        return \"only one type of fee payment field can be used in a single tx\"\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Transaction.InvalidFeePayment.__str__","title":"__str__()","text":"

Print exception string

Source code in src/ethereum_test_tools/common/types.py
def __str__(self):\n\"\"\"Print exception string\"\"\"\n    return \"only one type of fee payment field can be used in a single tx\"\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Transaction.InvalidSignaturePrivateKey","title":"InvalidSignaturePrivateKey","text":"

Bases: Exception

Transaction describes both the signature and private key of source account.

Source code in src/ethereum_test_tools/common/types.py
class InvalidSignaturePrivateKey(Exception):\n\"\"\"\n    Transaction describes both the signature and private key of\n    source account.\n    \"\"\"\n\n    def __str__(self):\n\"\"\"Print exception string\"\"\"\n        return \"can't define both 'signature' and 'private_key'\"\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Transaction.InvalidSignaturePrivateKey.__str__","title":"__str__()","text":"

Print exception string

Source code in src/ethereum_test_tools/common/types.py
def __str__(self):\n\"\"\"Print exception string\"\"\"\n    return \"can't define both 'signature' and 'private_key'\"\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Transaction.__post_init__","title":"__post_init__()","text":"

Ensures the transaction has no conflicting properties.

Source code in src/ethereum_test_tools/common/types.py
def __post_init__(self) -> None:\n\"\"\"\n    Ensures the transaction has no conflicting properties.\n    \"\"\"\n    if (\n        self.gas_price is not None\n        and self.max_fee_per_gas is not None\n        and self.max_priority_fee_per_gas is not None\n    ):\n        raise Transaction.InvalidFeePayment()\n\n    if (\n        self.gas_price is None\n        and self.max_fee_per_gas is None\n        and self.max_priority_fee_per_gas is None\n    ):\n        self.gas_price = 10\n\n    if self.signature is not None and self.secret_key is not None:\n        raise Transaction.InvalidSignaturePrivateKey()\n\n    if self.signature is None and self.secret_key is None:\n        self.secret_key = TestPrivateKey\n\n    if self.ty is None:\n        # Try to deduce transaction type from included fields\n        if self.max_fee_per_data_gas is not None:\n            self.ty = 3\n        elif self.max_fee_per_gas is not None:\n            self.ty = 2\n        elif self.access_list is not None:\n            self.ty = 1\n        else:\n            self.ty = 0\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Transaction.with_error","title":"with_error(error)","text":"

Create a copy of the transaction with an added error.

Source code in src/ethereum_test_tools/common/types.py
def with_error(self, error: str) -> \"Transaction\":\n\"\"\"\n    Create a copy of the transaction with an added error.\n    \"\"\"\n    tx = copy(self)\n    tx.error = error\n    return tx\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Transaction.with_nonce","title":"with_nonce(nonce)","text":"

Create a copy of the transaction with a modified nonce.

Source code in src/ethereum_test_tools/common/types.py
def with_nonce(self, nonce: int) -> \"Transaction\":\n\"\"\"\n    Create a copy of the transaction with a modified nonce.\n    \"\"\"\n    tx = copy(self)\n    tx.nonce = nonce\n    return tx\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Transaction.with_fields","title":"with_fields(**kwargs)","text":"

Create a deepcopy of the transaction with modified fields.

Source code in src/ethereum_test_tools/common/types.py
def with_fields(self, **kwargs) -> \"Transaction\":\n\"\"\"\n    Create a deepcopy of the transaction with modified fields.\n    \"\"\"\n    tx = deepcopy(self)\n    for key, value in kwargs.items():\n        if hasattr(tx, key):\n            setattr(tx, key, value)\n        else:\n            raise ValueError(f\"Invalid field '{key}' for Transaction\")\n    return tx\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Transaction.payload_body","title":"payload_body()","text":"

Returns the list of values included in the transaction body.

Source code in src/ethereum_test_tools/common/types.py
def payload_body(self) -> List[Any]:\n\"\"\"\n    Returns the list of values included in the transaction body.\n    \"\"\"\n    if self.signature is None:\n        raise ValueError(\"signature must be set before serializing any tx type\")\n\n    if self.gas_limit is None:\n        raise ValueError(\"gas_limit must be set for all tx types\")\n    to = address_to_bytes(self.to)\n\n    if self.ty == 3:\n        # EIP-4844: https://eips.ethereum.org/EIPS/eip-4844\n        if self.max_priority_fee_per_gas is None:\n            raise ValueError(\"max_priority_fee_per_gas must be set for type 3 tx\")\n        if self.max_fee_per_gas is None:\n            raise ValueError(\"max_fee_per_gas must be set for type 3 tx\")\n        if self.max_fee_per_data_gas is None:\n            raise ValueError(\"max_fee_per_data_gas must be set for type 3 tx\")\n        if self.blob_versioned_hashes is None:\n            raise ValueError(\"blob_versioned_hashes must be set for type 3 tx\")\n\n        if self.wrapped_blob_transaction:\n            if self.blobs is None:\n                raise ValueError(\"blobs must be set for network version of type 3 tx\")\n            if self.blob_kzg_commitments is None:\n                raise ValueError(\n                    \"blob_kzg_commitments must be set for network version of type 3 tx\"\n                )\n            if self.blob_kzg_proofs is None:\n                raise ValueError(\n                    \"blob_kzg_proofs must be set for network version of type 3 tx\"\n                )\n\n            return [\n                [\n                    Uint(self.chain_id),\n                    Uint(self.nonce),\n                    Uint(self.max_priority_fee_per_gas),\n                    Uint(self.max_fee_per_gas),\n                    Uint(self.gas_limit),\n                    to,\n                    Uint(self.value),\n                    code_to_bytes(self.data),\n                    [a.to_list() for a in self.access_list]\n                    if self.access_list is not None\n                    else [],\n                    Uint(self.max_fee_per_data_gas),\n                    [hash_to_bytes(h) for h in self.blob_versioned_hashes],\n                    Uint(self.signature[0]),\n                    Uint(self.signature[1]),\n                    Uint(self.signature[2]),\n                ],\n                self.blobs,\n                self.blob_kzg_commitments,\n                self.blob_kzg_proofs,\n            ]\n        else:\n            return [\n                Uint(self.chain_id),\n                Uint(self.nonce),\n                Uint(self.max_priority_fee_per_gas),\n                Uint(self.max_fee_per_gas),\n                Uint(self.gas_limit),\n                to,\n                Uint(self.value),\n                code_to_bytes(self.data),\n                [a.to_list() for a in self.access_list]\n                if self.access_list is not None\n                else [],\n                Uint(self.max_fee_per_data_gas),\n                [hash_to_bytes(h) for h in self.blob_versioned_hashes],\n                Uint(self.signature[0]),\n                Uint(self.signature[1]),\n                Uint(self.signature[2]),\n            ]\n    elif self.ty == 2:\n        # EIP-1559: https://eips.ethereum.org/EIPS/eip-1559\n        if self.max_priority_fee_per_gas is None:\n            raise ValueError(\"max_priority_fee_per_gas must be set for type 3 tx\")\n        if self.max_fee_per_gas is None:\n            raise ValueError(\"max_fee_per_gas must be set for type 3 tx\")\n        return [\n            Uint(self.chain_id),\n            Uint(self.nonce),\n            Uint(self.max_priority_fee_per_gas),\n            Uint(self.max_fee_per_gas),\n            Uint(self.gas_limit),\n            to,\n            Uint(self.value),\n            code_to_bytes(self.data),\n            [a.to_list() for a in self.access_list] if self.access_list is not None else [],\n            Uint(self.signature[0]),\n            Uint(self.signature[1]),\n            Uint(self.signature[2]),\n        ]\n    elif self.ty == 1:\n        # EIP-2930: https://eips.ethereum.org/EIPS/eip-2930\n        if self.gas_price is None:\n            raise ValueError(\"gas_price must be set for type 1 tx\")\n\n        return [\n            Uint(self.chain_id),\n            Uint(self.nonce),\n            Uint(self.gas_price),\n            Uint(self.gas_limit),\n            to,\n            Uint(self.value),\n            code_to_bytes(self.data),\n            [a.to_list() for a in self.access_list] if self.access_list is not None else [],\n            Uint(self.signature[0]),\n            Uint(self.signature[1]),\n            Uint(self.signature[2]),\n        ]\n    elif self.ty == 0:\n        if self.gas_price is None:\n            raise ValueError(\"gas_price must be set for type 0 tx\")\n        # EIP-155: https://eips.ethereum.org/EIPS/eip-155\n        return [\n            Uint(self.nonce),\n            Uint(self.gas_price),\n            Uint(self.gas_limit),\n            to,\n            Uint(self.value),\n            code_to_bytes(self.data),\n            Uint(self.signature[0]),\n            Uint(self.signature[1]),\n            Uint(self.signature[2]),\n        ]\n\n    raise NotImplementedError(f\"serialized_bytes not implemented for tx type {self.ty}\")\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Transaction.serialized_bytes","title":"serialized_bytes()","text":"

Returns bytes of the serialized representation of the transaction, which is almost always RLP encoding.

Source code in src/ethereum_test_tools/common/types.py
def serialized_bytes(self) -> bytes:\n\"\"\"\n    Returns bytes of the serialized representation of the transaction,\n    which is almost always RLP encoding.\n    \"\"\"\n    if self.ty is None:\n        raise ValueError(\"ty must be set for all tx types\")\n\n    if self.ty > 0:\n        return bytes([self.ty]) + eth_rlp.encode(self.payload_body())\n    else:\n        return eth_rlp.encode(self.payload_body())\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Transaction.signing_envelope","title":"signing_envelope()","text":"

Returns the list of values included in the envelope used for signing.

Source code in src/ethereum_test_tools/common/types.py
def signing_envelope(self) -> List[Any]:\n\"\"\"\n    Returns the list of values included in the envelope used for signing.\n    \"\"\"\n    if self.gas_limit is None:\n        raise ValueError(\"gas_limit must be set for all tx types\")\n    to = address_to_bytes(self.to)\n\n    if self.ty == 3:\n        # EIP-4844: https://eips.ethereum.org/EIPS/eip-4844\n        if self.max_priority_fee_per_gas is None:\n            raise ValueError(\"max_priority_fee_per_gas must be set for type 3 tx\")\n        if self.max_fee_per_gas is None:\n            raise ValueError(\"max_fee_per_gas must be set for type 3 tx\")\n        if self.max_fee_per_data_gas is None:\n            raise ValueError(\"max_fee_per_data_gas must be set for type 3 tx\")\n        if self.blob_versioned_hashes is None:\n            raise ValueError(\"blob_versioned_hashes must be set for type 3 tx\")\n        return [\n            Uint(self.chain_id),\n            Uint(self.nonce),\n            Uint(self.max_priority_fee_per_gas),\n            Uint(self.max_fee_per_gas),\n            Uint(self.gas_limit),\n            to,\n            Uint(self.value),\n            code_to_bytes(self.data),\n            [a.to_list() for a in self.access_list] if self.access_list is not None else [],\n            Uint(self.max_fee_per_data_gas),\n            [hash_to_bytes(h) for h in self.blob_versioned_hashes],\n        ]\n    elif self.ty == 2:\n        # EIP-1559: https://eips.ethereum.org/EIPS/eip-1559\n        if self.max_priority_fee_per_gas is None:\n            raise ValueError(\"max_priority_fee_per_gas must be set for type 3 tx\")\n        if self.max_fee_per_gas is None:\n            raise ValueError(\"max_fee_per_gas must be set for type 3 tx\")\n        return [\n            Uint(self.chain_id),\n            Uint(self.nonce),\n            Uint(self.max_priority_fee_per_gas),\n            Uint(self.max_fee_per_gas),\n            Uint(self.gas_limit),\n            to,\n            Uint(self.value),\n            code_to_bytes(self.data),\n            [a.to_list() for a in self.access_list] if self.access_list is not None else [],\n        ]\n    elif self.ty == 1:\n        # EIP-2930: https://eips.ethereum.org/EIPS/eip-2930\n        if self.gas_price is None:\n            raise ValueError(\"gas_price must be set for type 1 tx\")\n\n        return [\n            Uint(self.chain_id),\n            Uint(self.nonce),\n            Uint(self.gas_price),\n            Uint(self.gas_limit),\n            to,\n            Uint(self.value),\n            code_to_bytes(self.data),\n            [a.to_list() for a in self.access_list] if self.access_list is not None else [],\n        ]\n    elif self.ty == 0:\n        if self.gas_price is None:\n            raise ValueError(\"gas_price must be set for type 0 tx\")\n\n        if self.protected:\n            # EIP-155: https://eips.ethereum.org/EIPS/eip-155\n            return [\n                Uint(self.nonce),\n                Uint(self.gas_price),\n                Uint(self.gas_limit),\n                to,\n                Uint(self.value),\n                code_to_bytes(self.data),\n                Uint(self.chain_id),\n                Uint(0),\n                Uint(0),\n            ]\n        else:\n            return [\n                Uint(self.nonce),\n                Uint(self.gas_price),\n                Uint(self.gas_limit),\n                to,\n                Uint(self.value),\n                code_to_bytes(self.data),\n            ]\n    raise NotImplementedError(\"sigining for transaction type {self.ty} not implemented\")\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Transaction.signing_bytes","title":"signing_bytes()","text":"

Returns the serialized bytes of the transaction used for signing.

Source code in src/ethereum_test_tools/common/types.py
def signing_bytes(self) -> bytes:\n\"\"\"\n    Returns the serialized bytes of the transaction used for signing.\n    \"\"\"\n    if self.ty is None:\n        raise ValueError(\"ty must be set for all tx types\")\n\n    if self.ty > 0:\n        return bytes([self.ty]) + eth_rlp.encode(self.signing_envelope())\n    else:\n        return eth_rlp.encode(self.signing_envelope())\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Transaction.with_signature_and_sender","title":"with_signature_and_sender()","text":"

Returns a signed version of the transaction using the private key.

Source code in src/ethereum_test_tools/common/types.py
def with_signature_and_sender(self) -> \"Transaction\":\n\"\"\"\n    Returns a signed version of the transaction using the private key.\n    \"\"\"\n    tx = copy(self)\n\n    if tx.signature is not None:\n        # Transaction already signed\n        if tx.sender is None:\n            # TODO: We need to recover the sender from the signature\n            raise NotImplementedError(\"recovering sender from signature not implemented\")\n        return tx\n\n    if tx.secret_key is None:\n        raise ValueError(\"secret_key must be set to sign a transaction\")\n\n    # Get the signing bytes\n    signing_hash = keccak256(tx.signing_bytes())\n\n    # Sign the bytes\n    private_key = PrivateKey.from_int(hash_to_int(tx.secret_key))\n    signature_bytes = private_key.sign_recoverable(signing_hash, hasher=None)\n    public_key = PublicKey.from_signature_and_message(\n        signature_bytes, signing_hash, hasher=None\n    )\n    tx.sender = keccak256(public_key.format(compressed=False)[1:])[32 - 20 :]\n\n    v, r, s = (\n        signature_bytes[64],\n        int.from_bytes(signature_bytes[0:32], byteorder=\"big\"),\n        int.from_bytes(signature_bytes[32:64], byteorder=\"big\"),\n    )\n    if tx.ty == 0:\n        if tx.protected:\n            v += 35 + (tx.chain_id * 2)\n        else:  # not protected\n            v += 27\n\n    tx.signature = (v, r, s)\n\n    # Remove the secret key because otherwise we might attempt to sign again (?)\n    tx.secret_key = None\n    return tx\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.Header","title":"Header dataclass","text":"

Header type used to describe block header properties in test specs.

Source code in src/ethereum_test_tools/common/types.py
@dataclass(kw_only=True)\nclass Header:\n\"\"\"\n    Header type used to describe block header properties in test specs.\n    \"\"\"\n\n    parent_hash: Optional[bytes] = None\n    ommers_hash: Optional[bytes] = None\n    coinbase: Optional[bytes | str] = None\n    state_root: Optional[bytes] = None\n    transactions_root: Optional[bytes] = None\n    receipt_root: Optional[bytes] = None\n    bloom: Optional[bytes] = None\n    difficulty: Optional[int] = None\n    number: Optional[int] = None\n    gas_limit: Optional[int] = None\n    gas_used: Optional[int] = None\n    timestamp: Optional[int] = None\n    extra_data: Optional[bytes] = None\n    mix_digest: Optional[bytes] = None\n    nonce: Optional[bytes] = None\n    base_fee: Optional[int | Removable] = None\n    withdrawals_root: Optional[bytes | Removable] = None\n    data_gas_used: Optional[int | Removable] = None\n    excess_data_gas: Optional[int | Removable] = None\n    hash: Optional[bytes] = None\n\n    REMOVE_FIELD: ClassVar[Removable] = Removable()\n\"\"\"\n    Sentinel object used to specify that a header field should be removed.\n    \"\"\"\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Header.REMOVE_FIELD","title":"REMOVE_FIELD: Removable = Removable() class-attribute","text":"

Sentinel object used to specify that a header field should be removed.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.Block","title":"Block dataclass","text":"

Bases: Header

Block type used to describe block properties in test specs

Source code in src/ethereum_test_tools/common/types.py
@dataclass(kw_only=True)\nclass Block(Header):\n\"\"\"\n    Block type used to describe block properties in test specs\n    \"\"\"\n\n    rlp: Optional[bytes] = None\n\"\"\"\n    If set, blockchain test will skip generating the block and will pass this value directly to\n    the Fixture.\n\n    Only meant to be used to simulate blocks with bad formats, and therefore\n    requires the block to produce an exception.\n    \"\"\"\n    rlp_modifier: Optional[Header] = None\n\"\"\"\n    An RLP modifying header which values would be used to override the ones\n    returned by the  `evm_transition_tool`.\n    \"\"\"\n    exception: Optional[str] = None\n\"\"\"\n    If set, the block is expected to be rejected by the client.\n    \"\"\"\n    engine_api_error_code: Optional[EngineAPIError] = None\n\"\"\"\n    If set, the block is expected to produce an error response from the Engine API.\n    \"\"\"\n    txs: Optional[List[Transaction]] = None\n\"\"\"\n    List of transactions included in the block.\n    \"\"\"\n    ommers: Optional[List[Header]] = None\n\"\"\"\n    List of ommer headers included in the block.\n    \"\"\"\n    withdrawals: Optional[List[Withdrawal]] = None\n\"\"\"\n    List of withdrawals to perform for this block.\n    \"\"\"\n\n    def set_environment(self, env: Environment) -> Environment:\n\"\"\"\n        Creates a copy of the environment with the characteristics of this\n        specific block.\n        \"\"\"\n        new_env = copy(env)\n\n\"\"\"\n        Values that need to be set in the environment and are `None` for\n        this block need to be set to their defaults.\n        \"\"\"\n        environment_default = Environment()\n        new_env.difficulty = self.difficulty\n        new_env.coinbase = (\n            self.coinbase if self.coinbase is not None else environment_default.coinbase\n        )\n        new_env.gas_limit = (\n            self.gas_limit if self.gas_limit is not None else environment_default.gas_limit\n        )\n        if not isinstance(self.base_fee, Removable):\n            new_env.base_fee = self.base_fee\n        new_env.withdrawals = self.withdrawals\n        if not isinstance(self.excess_data_gas, Removable):\n            new_env.excess_data_gas = self.excess_data_gas\n        if not isinstance(self.data_gas_used, Removable):\n            new_env.data_gas_used = self.data_gas_used\n\"\"\"\n        These values are required, but they depend on the previous environment,\n        so they can be calculated here.\n        \"\"\"\n        if self.number is not None:\n            new_env.number = self.number\n        else:\n            # calculate the next block number for the environment\n            if len(new_env.block_hashes) == 0:\n                new_env.number = 0\n            else:\n                new_env.number = max(new_env.block_hashes.keys()) + 1\n\n        if self.timestamp is not None:\n            new_env.timestamp = self.timestamp\n        else:\n            assert new_env.parent_timestamp is not None\n            new_env.timestamp = new_env.parent_timestamp + 12\n\n        return new_env\n\n    def copy_with_rlp(self, rlp: bytes) -> \"Block\":\n\"\"\"\n        Creates a copy of the block and adds the specified RLP.\n        \"\"\"\n        new_block = deepcopy(self)\n        new_block.rlp = rlp\n        return new_block\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Block.rlp","title":"rlp: Optional[bytes] = None instance-attribute class-attribute","text":"

If set, blockchain test will skip generating the block and will pass this value directly to the Fixture.

Only meant to be used to simulate blocks with bad formats, and therefore requires the block to produce an exception.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Block.rlp_modifier","title":"rlp_modifier: Optional[Header] = None instance-attribute class-attribute","text":"

An RLP modifying header which values would be used to override the ones returned by the evm_transition_tool.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Block.exception","title":"exception: Optional[str] = None instance-attribute class-attribute","text":"

If set, the block is expected to be rejected by the client.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Block.engine_api_error_code","title":"engine_api_error_code: Optional[EngineAPIError] = None instance-attribute class-attribute","text":"

If set, the block is expected to produce an error response from the Engine API.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Block.txs","title":"txs: Optional[List[Transaction]] = None instance-attribute class-attribute","text":"

List of transactions included in the block.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Block.ommers","title":"ommers: Optional[List[Header]] = None instance-attribute class-attribute","text":"

List of ommer headers included in the block.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Block.withdrawals","title":"withdrawals: Optional[List[Withdrawal]] = None instance-attribute class-attribute","text":"

List of withdrawals to perform for this block.

"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Block.set_environment","title":"set_environment(env)","text":"

Creates a copy of the environment with the characteristics of this specific block.

Source code in src/ethereum_test_tools/common/types.py
def set_environment(self, env: Environment) -> Environment:\n\"\"\"\n    Creates a copy of the environment with the characteristics of this\n    specific block.\n    \"\"\"\n    new_env = copy(env)\n\n\"\"\"\n    Values that need to be set in the environment and are `None` for\n    this block need to be set to their defaults.\n    \"\"\"\n    environment_default = Environment()\n    new_env.difficulty = self.difficulty\n    new_env.coinbase = (\n        self.coinbase if self.coinbase is not None else environment_default.coinbase\n    )\n    new_env.gas_limit = (\n        self.gas_limit if self.gas_limit is not None else environment_default.gas_limit\n    )\n    if not isinstance(self.base_fee, Removable):\n        new_env.base_fee = self.base_fee\n    new_env.withdrawals = self.withdrawals\n    if not isinstance(self.excess_data_gas, Removable):\n        new_env.excess_data_gas = self.excess_data_gas\n    if not isinstance(self.data_gas_used, Removable):\n        new_env.data_gas_used = self.data_gas_used\n\"\"\"\n    These values are required, but they depend on the previous environment,\n    so they can be calculated here.\n    \"\"\"\n    if self.number is not None:\n        new_env.number = self.number\n    else:\n        # calculate the next block number for the environment\n        if len(new_env.block_hashes) == 0:\n            new_env.number = 0\n        else:\n            new_env.number = max(new_env.block_hashes.keys()) + 1\n\n    if self.timestamp is not None:\n        new_env.timestamp = self.timestamp\n    else:\n        assert new_env.parent_timestamp is not None\n        new_env.timestamp = new_env.parent_timestamp + 12\n\n    return new_env\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Block.copy_with_rlp","title":"copy_with_rlp(rlp)","text":"

Creates a copy of the block and adds the specified RLP.

Source code in src/ethereum_test_tools/common/types.py
def copy_with_rlp(self, rlp: bytes) -> \"Block\":\n\"\"\"\n    Creates a copy of the block and adds the specified RLP.\n    \"\"\"\n    new_block = deepcopy(self)\n    new_block.rlp = rlp\n    return new_block\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.FixtureEngineNewPayload","title":"FixtureEngineNewPayload dataclass","text":"

Representation of the engine_newPayloadVX information to be sent using the block information.

Source code in src/ethereum_test_tools/common/types.py
@dataclass(kw_only=True)\nclass FixtureEngineNewPayload:\n\"\"\"\n    Representation of the `engine_newPayloadVX` information to be\n    sent using the block information.\n    \"\"\"\n\n    payload: FixtureExecutionPayload\n    version: int\n    blob_versioned_hashes: Optional[List[bytes]] = None\n    error_code: Optional[EngineAPIError] = None\n\n    @classmethod\n    def from_fixture_header(\n        cls,\n        fork: Fork,\n        header: FixtureHeader,\n        transactions: List[Transaction],\n        withdrawals: Optional[List[Withdrawal]],\n        error_code: Optional[EngineAPIError],\n    ) -> Optional[\"FixtureEngineNewPayload\"]:\n\"\"\"\n        Creates a `FixtureEngineNewPayload` from a `FixtureHeader`.\n        \"\"\"\n        new_payload_version = fork.engine_new_payload_version(header.number, header.timestamp)\n\n        if new_payload_version is None:\n            return None\n\n        new_payload = cls(\n            payload=FixtureExecutionPayload(\n                header=header, transactions=transactions, withdrawals=withdrawals\n            ),\n            version=new_payload_version,\n            error_code=error_code,\n        )\n\n        if fork.engine_new_payload_blob_hashes(header.number, header.timestamp):\n            new_payload.blob_versioned_hashes = blob_versioned_hashes_from_transactions(\n                transactions\n            )\n\n        return new_payload\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.FixtureEngineNewPayload.from_fixture_header","title":"from_fixture_header(fork, header, transactions, withdrawals, error_code) classmethod","text":"

Creates a FixtureEngineNewPayload from a FixtureHeader.

Source code in src/ethereum_test_tools/common/types.py
@classmethod\ndef from_fixture_header(\n    cls,\n    fork: Fork,\n    header: FixtureHeader,\n    transactions: List[Transaction],\n    withdrawals: Optional[List[Withdrawal]],\n    error_code: Optional[EngineAPIError],\n) -> Optional[\"FixtureEngineNewPayload\"]:\n\"\"\"\n    Creates a `FixtureEngineNewPayload` from a `FixtureHeader`.\n    \"\"\"\n    new_payload_version = fork.engine_new_payload_version(header.number, header.timestamp)\n\n    if new_payload_version is None:\n        return None\n\n    new_payload = cls(\n        payload=FixtureExecutionPayload(\n            header=header, transactions=transactions, withdrawals=withdrawals\n        ),\n        version=new_payload_version,\n        error_code=error_code,\n    )\n\n    if fork.engine_new_payload_blob_hashes(header.number, header.timestamp):\n        new_payload.blob_versioned_hashes = blob_versioned_hashes_from_transactions(\n            transactions\n        )\n\n    return new_payload\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.Fixture","title":"Fixture dataclass","text":"

Cross-client compatible Ethereum test fixture.

Source code in src/ethereum_test_tools/common/types.py
@dataclass(kw_only=True)\nclass Fixture:\n\"\"\"\n    Cross-client compatible Ethereum test fixture.\n    \"\"\"\n\n    blocks: List[FixtureBlock]\n    genesis: FixtureHeader\n    genesis_rlp: bytes\n    head: bytes\n    fork: str\n    pre_state: Mapping[str, Account]\n    post_state: Optional[Mapping[str, Account]]\n    seal_engine: str\n    info: Dict[str, str] = field(default_factory=dict)\n    name: str = \"\"\n\n    _json: Dict[str, Any] | None = None\n\n    def __post_init__(self):\n\"\"\"\n        Post init hook to convert to JSON after instantiation.\n        \"\"\"\n        self._json = to_json(self)\n\n    def fill_info(\n        self,\n        t8n: TransitionTool,\n        ref_spec: ReferenceSpec | None,\n    ):\n\"\"\"\n        Fill the info field for this fixture\n        \"\"\"\n        self.info[\"filling-transition-tool\"] = t8n.version()\n        if ref_spec is not None:\n            ref_spec.write_info(self.info)\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Fixture.__post_init__","title":"__post_init__()","text":"

Post init hook to convert to JSON after instantiation.

Source code in src/ethereum_test_tools/common/types.py
def __post_init__(self):\n\"\"\"\n    Post init hook to convert to JSON after instantiation.\n    \"\"\"\n    self._json = to_json(self)\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.Fixture.fill_info","title":"fill_info(t8n, ref_spec)","text":"

Fill the info field for this fixture

Source code in src/ethereum_test_tools/common/types.py
def fill_info(\n    self,\n    t8n: TransitionTool,\n    ref_spec: ReferenceSpec | None,\n):\n\"\"\"\n    Fill the info field for this fixture\n    \"\"\"\n    self.info[\"filling-transition-tool\"] = t8n.version()\n    if ref_spec is not None:\n        ref_spec.write_info(self.info)\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.JSONEncoder","title":"JSONEncoder","text":"

Bases: json.JSONEncoder

Custom JSON encoder for ethereum_test types.

Source code in src/ethereum_test_tools/common/types.py
class JSONEncoder(json.JSONEncoder):\n\"\"\"\n    Custom JSON encoder for `ethereum_test` types.\n    \"\"\"\n\n    def default(self, obj: JSONEncoderSupportedType) -> Any:\n\"\"\"\n        Enocdes types defined in this module using basic python facilities.\n        \"\"\"\n        if isinstance(obj, Storage):\n            return obj.to_dict()\n        elif isinstance(obj, Account):\n            account = {\n                \"nonce\": hex_or_none(obj.nonce, hex(0)),\n                \"balance\": hex_or_none(obj.balance, hex(0)),\n                \"code\": code_or_none(obj.code, \"0x\"),\n                \"storage\": to_json_or_none(obj.storage, {}),\n            }\n            return even_padding(account, excluded=[\"storage\"])\n        elif isinstance(obj, AccessList):\n            access_list: Dict[str, Any] = {\n                \"address\": address_or_none(obj.address, \"0x\" + ZeroAddress.hex())\n            }\n            if obj.storage_keys is not None:\n                access_list[\"storageKeys\"] = [hex_or_none(k) for k in obj.storage_keys]\n            return access_list\n        elif isinstance(obj, Transaction):\n            assert obj.ty is not None, \"Transaction type must be set\"\n            tx: Dict[str, Any] = {\n                \"type\": hex(obj.ty),\n                \"chainId\": hex(obj.chain_id),\n                \"nonce\": hex(obj.nonce),\n                \"gasPrice\": hex_or_none(obj.gas_price),\n                \"maxPriorityFeePerGas\": hex_or_none(obj.max_priority_fee_per_gas),\n                \"maxFeePerGas\": hex_or_none(obj.max_fee_per_gas),\n                \"gas\": hex(obj.gas_limit),\n                \"value\": hex(obj.value),\n                \"input\": code_to_hex(obj.data),\n                \"to\": address_or_none(obj.to),\n                \"accessList\": obj.access_list,\n                \"secretKey\": obj.secret_key,\n                \"maxFeePerDataGas\": hex_or_none(obj.max_fee_per_data_gas),\n                \"sender\": address_or_none(obj.sender),\n            }\n\n            if obj.blob_versioned_hashes is not None:\n                tx[\"blobVersionedHashes\"] = [hash_string(h) for h in obj.blob_versioned_hashes]\n\n            if obj.secret_key is None:\n                assert obj.signature is not None\n                assert len(obj.signature) == 3\n                tx[\"v\"] = hex(obj.signature[0])\n                tx[\"r\"] = hex(obj.signature[1])\n                tx[\"s\"] = hex(obj.signature[2])\n            else:\n                tx[\"v\"] = \"\"\n                tx[\"r\"] = \"\"\n                tx[\"s\"] = \"\"\n\n            return {k: v for (k, v) in tx.items() if v is not None}\n        elif isinstance(obj, Withdrawal):\n            withdrawal = {\n                \"index\": hex(obj.index),\n                \"validatorIndex\": hex(obj.validator),\n                \"address\": obj.address,\n                \"amount\": hex(obj.amount),\n            }\n            return withdrawal\n        elif isinstance(obj, Environment):\n            env: Dict[str, Any] = {\n                \"currentCoinbase\": address_or_none(obj.coinbase, \"0x\" + ZeroAddress.hex()),\n                \"currentGasLimit\": str_or_none(obj.gas_limit),\n                \"currentNumber\": str_or_none(obj.number),\n                \"currentTimestamp\": str_or_none(obj.timestamp),\n                \"currentRandom\": str_or_none(obj.prev_randao),\n                \"currentDifficulty\": str_or_none(obj.difficulty),\n                \"parentDifficulty\": str_or_none(obj.parent_difficulty),\n                \"parentBaseFee\": str_or_none(obj.parent_base_fee),\n                \"parentGasUsed\": str_or_none(obj.parent_gas_used),\n                \"parentGasLimit\": str_or_none(obj.parent_gas_limit),\n                \"parentTimestamp\": str_or_none(obj.parent_timestamp),\n                \"blockHashes\": {str(k): hex_or_none(v) for (k, v) in obj.block_hashes.items()},\n                \"ommers\": [],\n                \"withdrawals\": to_json_or_none(obj.withdrawals),\n                \"parentUncleHash\": hash_string(obj.parent_ommers_hash),\n                \"currentBaseFee\": str_or_none(obj.base_fee),\n                \"parentDataGasUsed\": str_or_none(obj.parent_data_gas_used),\n                \"parentExcessDataGas\": str_or_none(obj.parent_excess_data_gas),\n                \"currentExcessDataGas\": str_or_none(obj.excess_data_gas),\n                \"currentDataGasUsed\": str_or_none(obj.data_gas_used),\n            }\n\n            return {k: v for (k, v) in env.items() if v is not None}\n        elif isinstance(obj, FixtureHeader):\n            header = {\n                \"parentHash\": hex_or_none(obj.parent_hash),\n                \"uncleHash\": hex_or_none(obj.ommers_hash),\n                \"coinbase\": hex_or_none(obj.coinbase),\n                \"stateRoot\": hex_or_none(obj.state_root),\n                \"transactionsTrie\": hex_or_none(obj.transactions_root),\n                \"receiptTrie\": hex_or_none(obj.receipt_root),\n                \"bloom\": hex_or_none(obj.bloom),\n                \"difficulty\": hex(obj.difficulty),\n                \"number\": hex(obj.number),\n                \"gasLimit\": hex(obj.gas_limit),\n                \"gasUsed\": hex(obj.gas_used),\n                \"timestamp\": hex(obj.timestamp),\n                \"extraData\": hex_or_none(obj.extra_data),\n                \"mixHash\": hex_or_none(obj.mix_digest),\n                \"nonce\": hex_or_none(obj.nonce),\n            }\n            if obj.base_fee is not None:\n                header[\"baseFeePerGas\"] = hex(obj.base_fee)\n            if obj.hash is not None:\n                header[\"hash\"] = \"0x\" + obj.hash.hex()\n            if obj.withdrawals_root is not None:\n                header[\"withdrawalsRoot\"] = hex_or_none(obj.withdrawals_root)\n            if obj.data_gas_used is not None:\n                header[\"dataGasUsed\"] = hex(obj.data_gas_used)\n            if obj.excess_data_gas is not None:\n                header[\"excessDataGas\"] = hex(obj.excess_data_gas)\n            return even_padding(\n                header,\n                excluded=[\n                    \"parentHash\",\n                    \"uncleHash\",\n                    \"stateRoot\",\n                    \"coinbase\",\n                    \"transactionsTrie\",\n                    \"receiptTrie\",\n                    \"bloom\",\n                    \"nonce\",\n                    \"mixHash\",\n                    \"hash\",\n                    \"withdrawalsRoot\",\n                    \"extraData\",\n                ],\n            )\n        elif isinstance(obj, FixtureTransaction):\n            json_tx = to_json(obj.tx)\n            if json_tx[\"v\"] == \"\":\n                del json_tx[\"v\"]\n                del json_tx[\"r\"]\n                del json_tx[\"s\"]\n            if \"input\" in json_tx:\n                json_tx[\"data\"] = json_tx[\"input\"]\n                del json_tx[\"input\"]\n            if \"gas\" in json_tx:\n                json_tx[\"gasLimit\"] = json_tx[\"gas\"]\n                del json_tx[\"gas\"]\n            if \"to\" not in json_tx:\n                json_tx[\"to\"] = \"\"\n            return even_padding(\n                json_tx,\n                excluded=[\"data\", \"to\", \"accessList\"],\n            )\n        elif isinstance(obj, FixtureExecutionPayload):\n            payload: Dict[str, Any] = {\n                \"parentHash\": hex_or_none(obj.header.parent_hash),\n                \"feeRecipient\": hex_or_none(obj.header.coinbase),\n                \"stateRoot\": hex_or_none(obj.header.state_root),\n                \"receiptsRoot\": hex_or_none(obj.header.receipt_root),\n                \"logsBloom\": hex_or_none(obj.header.bloom),\n                \"prevRandao\": hex_or_none(obj.header.mix_digest),\n                \"blockNumber\": hex(obj.header.number),\n                \"gasLimit\": hex(obj.header.gas_limit),\n                \"gasUsed\": hex(obj.header.gas_used),\n                \"timestamp\": hex(obj.header.timestamp),\n                \"extraData\": hex_or_none(obj.header.extra_data),\n            }\n            if obj.header.base_fee is not None:\n                payload[\"baseFeePerGas\"] = hex(obj.header.base_fee)\n            if obj.header.hash is not None:\n                payload[\"blockHash\"] = \"0x\" + obj.header.hash.hex()\n\n            if obj.transactions is not None:\n                payload[\"transactions\"] = [\n                    hex_or_none(tx.serialized_bytes()) for tx in obj.transactions\n                ]\n            if obj.withdrawals is not None:\n                payload[\"withdrawals\"] = obj.withdrawals\n\n            if obj.header.data_gas_used is not None:\n                payload[\"dataGasUsed\"] = hex(obj.header.data_gas_used)\n            if obj.header.excess_data_gas is not None:\n                payload[\"excessDataGas\"] = hex(obj.header.excess_data_gas)\n\n            return payload\n        elif isinstance(obj, FixtureEngineNewPayload):\n            new_payload: Dict[str, Any] = {\n                \"payload\": to_json(obj.payload),\n                \"version\": str_or_none(obj.version),\n            }\n            if obj.blob_versioned_hashes is not None:\n                new_payload[\"blobVersionedHashes\"] = [\n                    \"0x\" + hash_to_bytes(h).hex() for h in obj.blob_versioned_hashes\n                ]\n            if obj.error_code is not None:\n                new_payload[\"errorCode\"] = str(int(obj.error_code))\n            return new_payload\n\n        elif isinstance(obj, FixtureBlock):\n            b: Dict[str, Any] = {\"rlp\": hex_or_none(obj.rlp)}\n            if obj.block_header is not None:\n                b[\"blockHeader\"] = json.loads(json.dumps(obj.block_header, cls=JSONEncoder))\n            if obj.new_payload is not None:\n                b[\"engineNewPayload\"] = to_json_or_none(obj.new_payload)\n            if obj.expected_exception is not None:\n                b[\"expectException\"] = obj.expected_exception\n            if obj.block_number is not None:\n                b[\"blocknumber\"] = str(obj.block_number)\n            if obj.txs is not None:\n                b[\"transactions\"] = [FixtureTransaction(tx=tx) for tx in obj.txs]\n            if obj.ommers is not None:\n                b[\"uncleHeaders\"] = obj.ommers\n            if obj.withdrawals is not None:\n                b[\"withdrawals\"] = [\n                    even_padding(to_json(wd), excluded=[\"address\"]) for wd in obj.withdrawals\n                ]\n            return b\n\n        elif isinstance(obj, Fixture):\n            if obj._json is not None:\n                obj._json[\"_info\"] = obj.info\n                return obj._json\n\n            f = {\n                \"_info\": obj.info,\n                \"blocks\": [json.loads(json.dumps(b, cls=JSONEncoder)) for b in obj.blocks],\n                \"genesisBlockHeader\": self.default(obj.genesis),\n                \"genesisRLP\": hex_or_none(obj.genesis_rlp),\n                \"lastblockhash\": hex_or_none(obj.head),\n                \"network\": obj.fork,\n                \"pre\": json.loads(json.dumps(obj.pre_state, cls=JSONEncoder)),\n                \"postState\": json.loads(json.dumps(obj.post_state, cls=JSONEncoder)),\n                \"sealEngine\": obj.seal_engine,\n            }\n            if f[\"postState\"] is None:\n                del f[\"postState\"]\n            return f\n        else:\n            return super().default(obj)\n
"},{"location":"library/ethereum_test_tools/#ethereum_test_tools.common.types.JSONEncoder.default","title":"default(obj)","text":"

Enocdes types defined in this module using basic python facilities.

Source code in src/ethereum_test_tools/common/types.py
def default(self, obj: JSONEncoderSupportedType) -> Any:\n\"\"\"\n    Enocdes types defined in this module using basic python facilities.\n    \"\"\"\n    if isinstance(obj, Storage):\n        return obj.to_dict()\n    elif isinstance(obj, Account):\n        account = {\n            \"nonce\": hex_or_none(obj.nonce, hex(0)),\n            \"balance\": hex_or_none(obj.balance, hex(0)),\n            \"code\": code_or_none(obj.code, \"0x\"),\n            \"storage\": to_json_or_none(obj.storage, {}),\n        }\n        return even_padding(account, excluded=[\"storage\"])\n    elif isinstance(obj, AccessList):\n        access_list: Dict[str, Any] = {\n            \"address\": address_or_none(obj.address, \"0x\" + ZeroAddress.hex())\n        }\n        if obj.storage_keys is not None:\n            access_list[\"storageKeys\"] = [hex_or_none(k) for k in obj.storage_keys]\n        return access_list\n    elif isinstance(obj, Transaction):\n        assert obj.ty is not None, \"Transaction type must be set\"\n        tx: Dict[str, Any] = {\n            \"type\": hex(obj.ty),\n            \"chainId\": hex(obj.chain_id),\n            \"nonce\": hex(obj.nonce),\n            \"gasPrice\": hex_or_none(obj.gas_price),\n            \"maxPriorityFeePerGas\": hex_or_none(obj.max_priority_fee_per_gas),\n            \"maxFeePerGas\": hex_or_none(obj.max_fee_per_gas),\n            \"gas\": hex(obj.gas_limit),\n            \"value\": hex(obj.value),\n            \"input\": code_to_hex(obj.data),\n            \"to\": address_or_none(obj.to),\n            \"accessList\": obj.access_list,\n            \"secretKey\": obj.secret_key,\n            \"maxFeePerDataGas\": hex_or_none(obj.max_fee_per_data_gas),\n            \"sender\": address_or_none(obj.sender),\n        }\n\n        if obj.blob_versioned_hashes is not None:\n            tx[\"blobVersionedHashes\"] = [hash_string(h) for h in obj.blob_versioned_hashes]\n\n        if obj.secret_key is None:\n            assert obj.signature is not None\n            assert len(obj.signature) == 3\n            tx[\"v\"] = hex(obj.signature[0])\n            tx[\"r\"] = hex(obj.signature[1])\n            tx[\"s\"] = hex(obj.signature[2])\n        else:\n            tx[\"v\"] = \"\"\n            tx[\"r\"] = \"\"\n            tx[\"s\"] = \"\"\n\n        return {k: v for (k, v) in tx.items() if v is not None}\n    elif isinstance(obj, Withdrawal):\n        withdrawal = {\n            \"index\": hex(obj.index),\n            \"validatorIndex\": hex(obj.validator),\n            \"address\": obj.address,\n            \"amount\": hex(obj.amount),\n        }\n        return withdrawal\n    elif isinstance(obj, Environment):\n        env: Dict[str, Any] = {\n            \"currentCoinbase\": address_or_none(obj.coinbase, \"0x\" + ZeroAddress.hex()),\n            \"currentGasLimit\": str_or_none(obj.gas_limit),\n            \"currentNumber\": str_or_none(obj.number),\n            \"currentTimestamp\": str_or_none(obj.timestamp),\n            \"currentRandom\": str_or_none(obj.prev_randao),\n            \"currentDifficulty\": str_or_none(obj.difficulty),\n            \"parentDifficulty\": str_or_none(obj.parent_difficulty),\n            \"parentBaseFee\": str_or_none(obj.parent_base_fee),\n            \"parentGasUsed\": str_or_none(obj.parent_gas_used),\n            \"parentGasLimit\": str_or_none(obj.parent_gas_limit),\n            \"parentTimestamp\": str_or_none(obj.parent_timestamp),\n            \"blockHashes\": {str(k): hex_or_none(v) for (k, v) in obj.block_hashes.items()},\n            \"ommers\": [],\n            \"withdrawals\": to_json_or_none(obj.withdrawals),\n            \"parentUncleHash\": hash_string(obj.parent_ommers_hash),\n            \"currentBaseFee\": str_or_none(obj.base_fee),\n            \"parentDataGasUsed\": str_or_none(obj.parent_data_gas_used),\n            \"parentExcessDataGas\": str_or_none(obj.parent_excess_data_gas),\n            \"currentExcessDataGas\": str_or_none(obj.excess_data_gas),\n            \"currentDataGasUsed\": str_or_none(obj.data_gas_used),\n        }\n\n        return {k: v for (k, v) in env.items() if v is not None}\n    elif isinstance(obj, FixtureHeader):\n        header = {\n            \"parentHash\": hex_or_none(obj.parent_hash),\n            \"uncleHash\": hex_or_none(obj.ommers_hash),\n            \"coinbase\": hex_or_none(obj.coinbase),\n            \"stateRoot\": hex_or_none(obj.state_root),\n            \"transactionsTrie\": hex_or_none(obj.transactions_root),\n            \"receiptTrie\": hex_or_none(obj.receipt_root),\n            \"bloom\": hex_or_none(obj.bloom),\n            \"difficulty\": hex(obj.difficulty),\n            \"number\": hex(obj.number),\n            \"gasLimit\": hex(obj.gas_limit),\n            \"gasUsed\": hex(obj.gas_used),\n            \"timestamp\": hex(obj.timestamp),\n            \"extraData\": hex_or_none(obj.extra_data),\n            \"mixHash\": hex_or_none(obj.mix_digest),\n            \"nonce\": hex_or_none(obj.nonce),\n        }\n        if obj.base_fee is not None:\n            header[\"baseFeePerGas\"] = hex(obj.base_fee)\n        if obj.hash is not None:\n            header[\"hash\"] = \"0x\" + obj.hash.hex()\n        if obj.withdrawals_root is not None:\n            header[\"withdrawalsRoot\"] = hex_or_none(obj.withdrawals_root)\n        if obj.data_gas_used is not None:\n            header[\"dataGasUsed\"] = hex(obj.data_gas_used)\n        if obj.excess_data_gas is not None:\n            header[\"excessDataGas\"] = hex(obj.excess_data_gas)\n        return even_padding(\n            header,\n            excluded=[\n                \"parentHash\",\n                \"uncleHash\",\n                \"stateRoot\",\n                \"coinbase\",\n                \"transactionsTrie\",\n                \"receiptTrie\",\n                \"bloom\",\n                \"nonce\",\n                \"mixHash\",\n                \"hash\",\n                \"withdrawalsRoot\",\n                \"extraData\",\n            ],\n        )\n    elif isinstance(obj, FixtureTransaction):\n        json_tx = to_json(obj.tx)\n        if json_tx[\"v\"] == \"\":\n            del json_tx[\"v\"]\n            del json_tx[\"r\"]\n            del json_tx[\"s\"]\n        if \"input\" in json_tx:\n            json_tx[\"data\"] = json_tx[\"input\"]\n            del json_tx[\"input\"]\n        if \"gas\" in json_tx:\n            json_tx[\"gasLimit\"] = json_tx[\"gas\"]\n            del json_tx[\"gas\"]\n        if \"to\" not in json_tx:\n            json_tx[\"to\"] = \"\"\n        return even_padding(\n            json_tx,\n            excluded=[\"data\", \"to\", \"accessList\"],\n        )\n    elif isinstance(obj, FixtureExecutionPayload):\n        payload: Dict[str, Any] = {\n            \"parentHash\": hex_or_none(obj.header.parent_hash),\n            \"feeRecipient\": hex_or_none(obj.header.coinbase),\n            \"stateRoot\": hex_or_none(obj.header.state_root),\n            \"receiptsRoot\": hex_or_none(obj.header.receipt_root),\n            \"logsBloom\": hex_or_none(obj.header.bloom),\n            \"prevRandao\": hex_or_none(obj.header.mix_digest),\n            \"blockNumber\": hex(obj.header.number),\n            \"gasLimit\": hex(obj.header.gas_limit),\n            \"gasUsed\": hex(obj.header.gas_used),\n            \"timestamp\": hex(obj.header.timestamp),\n            \"extraData\": hex_or_none(obj.header.extra_data),\n        }\n        if obj.header.base_fee is not None:\n            payload[\"baseFeePerGas\"] = hex(obj.header.base_fee)\n        if obj.header.hash is not None:\n            payload[\"blockHash\"] = \"0x\" + obj.header.hash.hex()\n\n        if obj.transactions is not None:\n            payload[\"transactions\"] = [\n                hex_or_none(tx.serialized_bytes()) for tx in obj.transactions\n            ]\n        if obj.withdrawals is not None:\n            payload[\"withdrawals\"] = obj.withdrawals\n\n        if obj.header.data_gas_used is not None:\n            payload[\"dataGasUsed\"] = hex(obj.header.data_gas_used)\n        if obj.header.excess_data_gas is not None:\n            payload[\"excessDataGas\"] = hex(obj.header.excess_data_gas)\n\n        return payload\n    elif isinstance(obj, FixtureEngineNewPayload):\n        new_payload: Dict[str, Any] = {\n            \"payload\": to_json(obj.payload),\n            \"version\": str_or_none(obj.version),\n        }\n        if obj.blob_versioned_hashes is not None:\n            new_payload[\"blobVersionedHashes\"] = [\n                \"0x\" + hash_to_bytes(h).hex() for h in obj.blob_versioned_hashes\n            ]\n        if obj.error_code is not None:\n            new_payload[\"errorCode\"] = str(int(obj.error_code))\n        return new_payload\n\n    elif isinstance(obj, FixtureBlock):\n        b: Dict[str, Any] = {\"rlp\": hex_or_none(obj.rlp)}\n        if obj.block_header is not None:\n            b[\"blockHeader\"] = json.loads(json.dumps(obj.block_header, cls=JSONEncoder))\n        if obj.new_payload is not None:\n            b[\"engineNewPayload\"] = to_json_or_none(obj.new_payload)\n        if obj.expected_exception is not None:\n            b[\"expectException\"] = obj.expected_exception\n        if obj.block_number is not None:\n            b[\"blocknumber\"] = str(obj.block_number)\n        if obj.txs is not None:\n            b[\"transactions\"] = [FixtureTransaction(tx=tx) for tx in obj.txs]\n        if obj.ommers is not None:\n            b[\"uncleHeaders\"] = obj.ommers\n        if obj.withdrawals is not None:\n            b[\"withdrawals\"] = [\n                even_padding(to_json(wd), excluded=[\"address\"]) for wd in obj.withdrawals\n            ]\n        return b\n\n    elif isinstance(obj, Fixture):\n        if obj._json is not None:\n            obj._json[\"_info\"] = obj.info\n            return obj._json\n\n        f = {\n            \"_info\": obj.info,\n            \"blocks\": [json.loads(json.dumps(b, cls=JSONEncoder)) for b in obj.blocks],\n            \"genesisBlockHeader\": self.default(obj.genesis),\n            \"genesisRLP\": hex_or_none(obj.genesis_rlp),\n            \"lastblockhash\": hex_or_none(obj.head),\n            \"network\": obj.fork,\n            \"pre\": json.loads(json.dumps(obj.pre_state, cls=JSONEncoder)),\n            \"postState\": json.loads(json.dumps(obj.post_state, cls=JSONEncoder)),\n            \"sealEngine\": obj.seal_engine,\n        }\n        if f[\"postState\"] is None:\n            del f[\"postState\"]\n        return f\n    else:\n        return super().default(obj)\n
"},{"location":"library/evm_transition_tool/","title":"EVM Transition Tool Package","text":"

Library of Python wrappers for the different implementations of transition tools.

"},{"location":"library/evm_transition_tool/#evm_transition_tool.UnknownTransitionTool","title":"UnknownTransitionTool","text":"

Bases: Exception

Exception raised if an unknown t8n is encountered

Source code in src/evm_transition_tool/transition_tool.py
class UnknownTransitionTool(Exception):\n\"\"\"Exception raised if an unknown t8n is encountered\"\"\"\n\n    pass\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.GethTransitionTool","title":"GethTransitionTool","text":"

Bases: TransitionTool

Go-ethereum evm Transition tool frontend wrapper class.

Source code in src/evm_transition_tool/geth.py
class GethTransitionTool(TransitionTool):\n\"\"\"\n    Go-ethereum `evm` Transition tool frontend wrapper class.\n    \"\"\"\n\n    default_binary = Path(\"evm\")\n    detect_binary_pattern = compile(r\"^evm version\\b\")\n\n    binary: Path\n    cached_version: Optional[str] = None\n    trace: bool\n\n    def __init__(\n        self,\n        *,\n        binary: Optional[Path] = None,\n        trace: bool = False,\n    ):\n        super().__init__(binary=binary, trace=trace)\n        args = [str(self.binary), \"t8n\", \"--help\"]\n        try:\n            result = subprocess.run(args, capture_output=True, text=True)\n        except subprocess.CalledProcessError as e:\n            raise Exception(\"evm process unexpectedly returned a non-zero status code: \" f\"{e}.\")\n        except Exception as e:\n            raise Exception(f\"Unexpected exception calling evm tool: {e}.\")\n        self.help_string = result.stdout\n\n    def evaluate(\n        self,\n        alloc: Any,\n        txs: Any,\n        env: Any,\n        fork: Fork,\n        chain_id: int = 1,\n        reward: int = 0,\n        eips: Optional[List[int]] = None,\n    ) -> Tuple[Dict[str, Any], Dict[str, Any]]:\n\"\"\"\n        Executes `evm t8n` with the specified arguments.\n        \"\"\"\n        fork_name = fork.name()\n        if eips is not None:\n            fork_name = \"+\".join([fork_name] + [str(eip) for eip in eips])\n\n        temp_dir = tempfile.TemporaryDirectory()\n\n        if int(env[\"currentNumber\"], 0) == 0:\n            reward = -1\n        args = [\n            str(self.binary),\n            \"t8n\",\n            \"--input.alloc=stdin\",\n            \"--input.txs=stdin\",\n            \"--input.env=stdin\",\n            \"--output.result=stdout\",\n            \"--output.alloc=stdout\",\n            \"--output.body=txs.rlp\",\n            f\"--output.basedir={temp_dir.name}\",\n            f\"--state.fork={fork_name}\",\n            f\"--state.chainid={chain_id}\",\n            f\"--state.reward={reward}\",\n        ]\n\n        if self.trace:\n            args.append(\"--trace\")\n\n        stdin = {\n            \"alloc\": alloc,\n            \"txs\": txs,\n            \"env\": env,\n        }\n\n        encoded_input = str.encode(json.dumps(stdin))\n        result = subprocess.run(\n            args,\n            input=encoded_input,\n            stdout=subprocess.PIPE,\n            stderr=subprocess.PIPE,\n        )\n\n        if result.returncode != 0:\n            raise Exception(\"failed to evaluate: \" + result.stderr.decode())\n\n        output = json.loads(result.stdout)\n\n        if \"alloc\" not in output or \"result\" not in output:\n            raise Exception(\"malformed result\")\n\n        if self.trace:\n            receipts: List[Any] = output[\"result\"][\"receipts\"]\n            traces: List[List[Dict]] = []\n            for i, r in enumerate(receipts):\n                h = r[\"transactionHash\"]\n                trace_file_name = f\"trace-{i}-{h}.jsonl\"\n                with open(os.path.join(temp_dir.name, trace_file_name), \"r\") as trace_file:\n                    tx_traces: List[Dict] = []\n                    for trace_line in trace_file.readlines():\n                        tx_traces.append(json.loads(trace_line))\n                    traces.append(tx_traces)\n            self.append_traces(traces)\n\n        temp_dir.cleanup()\n\n        return output[\"alloc\"], output[\"result\"]\n\n    def version(self) -> str:\n\"\"\"\n        Gets `evm` binary version.\n        \"\"\"\n        if self.cached_version is None:\n            result = subprocess.run(\n                [str(self.binary), \"-v\"],\n                stdout=subprocess.PIPE,\n            )\n\n            if result.returncode != 0:\n                raise Exception(\"failed to evaluate: \" + result.stderr.decode())\n\n            self.cached_version = result.stdout.decode().strip()\n\n        return self.cached_version\n\n    def is_fork_supported(self, fork: Fork) -> bool:\n\"\"\"\n        Returns True if the fork is supported by the tool\n        \"\"\"\n        return fork().name() in self.help_string\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.geth.GethTransitionTool.evaluate","title":"evaluate(alloc, txs, env, fork, chain_id=1, reward=0, eips=None)","text":"

Executes evm t8n with the specified arguments.

Source code in src/evm_transition_tool/geth.py
def evaluate(\n    self,\n    alloc: Any,\n    txs: Any,\n    env: Any,\n    fork: Fork,\n    chain_id: int = 1,\n    reward: int = 0,\n    eips: Optional[List[int]] = None,\n) -> Tuple[Dict[str, Any], Dict[str, Any]]:\n\"\"\"\n    Executes `evm t8n` with the specified arguments.\n    \"\"\"\n    fork_name = fork.name()\n    if eips is not None:\n        fork_name = \"+\".join([fork_name] + [str(eip) for eip in eips])\n\n    temp_dir = tempfile.TemporaryDirectory()\n\n    if int(env[\"currentNumber\"], 0) == 0:\n        reward = -1\n    args = [\n        str(self.binary),\n        \"t8n\",\n        \"--input.alloc=stdin\",\n        \"--input.txs=stdin\",\n        \"--input.env=stdin\",\n        \"--output.result=stdout\",\n        \"--output.alloc=stdout\",\n        \"--output.body=txs.rlp\",\n        f\"--output.basedir={temp_dir.name}\",\n        f\"--state.fork={fork_name}\",\n        f\"--state.chainid={chain_id}\",\n        f\"--state.reward={reward}\",\n    ]\n\n    if self.trace:\n        args.append(\"--trace\")\n\n    stdin = {\n        \"alloc\": alloc,\n        \"txs\": txs,\n        \"env\": env,\n    }\n\n    encoded_input = str.encode(json.dumps(stdin))\n    result = subprocess.run(\n        args,\n        input=encoded_input,\n        stdout=subprocess.PIPE,\n        stderr=subprocess.PIPE,\n    )\n\n    if result.returncode != 0:\n        raise Exception(\"failed to evaluate: \" + result.stderr.decode())\n\n    output = json.loads(result.stdout)\n\n    if \"alloc\" not in output or \"result\" not in output:\n        raise Exception(\"malformed result\")\n\n    if self.trace:\n        receipts: List[Any] = output[\"result\"][\"receipts\"]\n        traces: List[List[Dict]] = []\n        for i, r in enumerate(receipts):\n            h = r[\"transactionHash\"]\n            trace_file_name = f\"trace-{i}-{h}.jsonl\"\n            with open(os.path.join(temp_dir.name, trace_file_name), \"r\") as trace_file:\n                tx_traces: List[Dict] = []\n                for trace_line in trace_file.readlines():\n                    tx_traces.append(json.loads(trace_line))\n                traces.append(tx_traces)\n        self.append_traces(traces)\n\n    temp_dir.cleanup()\n\n    return output[\"alloc\"], output[\"result\"]\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.geth.GethTransitionTool.version","title":"version()","text":"

Gets evm binary version.

Source code in src/evm_transition_tool/geth.py
def version(self) -> str:\n\"\"\"\n    Gets `evm` binary version.\n    \"\"\"\n    if self.cached_version is None:\n        result = subprocess.run(\n            [str(self.binary), \"-v\"],\n            stdout=subprocess.PIPE,\n        )\n\n        if result.returncode != 0:\n            raise Exception(\"failed to evaluate: \" + result.stderr.decode())\n\n        self.cached_version = result.stdout.decode().strip()\n\n    return self.cached_version\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.geth.GethTransitionTool.is_fork_supported","title":"is_fork_supported(fork)","text":"

Returns True if the fork is supported by the tool

Source code in src/evm_transition_tool/geth.py
def is_fork_supported(self, fork: Fork) -> bool:\n\"\"\"\n    Returns True if the fork is supported by the tool\n    \"\"\"\n    return fork().name() in self.help_string\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.TransitionToolNotFoundInPath","title":"TransitionToolNotFoundInPath","text":"

Bases: Exception

Exception raised if the specified t8n tool is not found in the path

Source code in src/evm_transition_tool/transition_tool.py
class TransitionToolNotFoundInPath(Exception):\n\"\"\"Exception raised if the specified t8n tool is not found in the path\"\"\"\n\n    def __init__(self, message=\"The transition tool was not found in the path\", binary=None):\n        if binary:\n            message = f\"{message} ({binary})\"\n        super().__init__(message)\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.EvmOneTransitionTool","title":"EvmOneTransitionTool","text":"

Bases: TransitionTool

Evmone evmone-t8n Transition tool frontend wrapper class.

Source code in src/evm_transition_tool/evmone.py
class EvmOneTransitionTool(TransitionTool):\n\"\"\"\n    Evmone `evmone-t8n` Transition tool frontend wrapper class.\n    \"\"\"\n\n    default_binary = Path(\"evmone-t8n\")\n    detect_binary_pattern = compile(r\"^evmone-t8n\\b\")\n\n    binary: Path\n    cached_version: Optional[str] = None\n    trace: bool\n\n    def __init__(\n        self,\n        *,\n        binary: Optional[Path] = None,\n        trace: bool = False,\n    ):\n        super().__init__(binary=binary, trace=trace)\n        if self.trace:\n            raise Exception(\"`evmone-t8n` does not support tracing.\")\n\n    def evaluate(\n        self,\n        alloc: Any,\n        txs: Any,\n        env: Any,\n        fork: Fork,\n        chain_id: int = 1,\n        reward: int = 0,\n        eips: Optional[List[int]] = None,\n    ) -> Tuple[Dict[str, Any], Dict[str, Any]]:\n\"\"\"\n        Executes `evmone-t8n` with the specified arguments.\n        \"\"\"\n        fork_name = fork.name()\n        if eips is not None:\n            fork_name = \"+\".join([fork_name] + [str(eip) for eip in eips])\n\n        temp_dir = tempfile.TemporaryDirectory()\n\n        input_contents = {\n            \"alloc\": alloc,\n            \"env\": env,\n            \"txs\": txs,\n        }\n        input_paths = {\n            k: os.path.join(temp_dir.name, f\"input_{k}.json\") for k in input_contents.keys()\n        }\n        for key, val in input_contents.items():\n            file_path = os.path.join(temp_dir.name, f\"input_{key}.json\")\n            write_json_file(val, file_path)\n\n        # Construct args for evmone-t8n binary\n        args = [\n            str(self.binary),\n            \"--state.fork\",\n            fork_name,\n            \"--input.alloc\",\n            input_paths[\"alloc\"],\n            \"--input.env\",\n            input_paths[\"env\"],\n            \"--input.txs\",\n            input_paths[\"txs\"],\n            \"--output.basedir\",\n            temp_dir.name,\n            \"--output.result\",\n            \"output_result.json\",\n            \"--output.alloc\",\n            \"output_alloc.json\",\n            \"--output.body\",\n            \"txs.rlp\",\n            \"--state.reward\",\n            str(reward),\n            \"--state.chainid\",\n            str(chain_id),\n        ]\n        result = subprocess.run(\n            args,\n            stdout=subprocess.PIPE,\n            stderr=subprocess.PIPE,\n        )\n\n        if result.returncode != 0:\n            raise Exception(\"failed to evaluate: \" + result.stderr.decode())\n\n        output_paths = {\n            \"alloc\": os.path.join(temp_dir.name, \"output_alloc.json\"),\n            \"result\": os.path.join(temp_dir.name, \"output_result.json\"),\n        }\n\n        output_contents = {}\n        for key, file_path in output_paths.items():\n            with open(file_path, \"r+\") as file:\n                contents = json.load(file)\n                file.seek(0)\n                json.dump(contents, file, ensure_ascii=False, indent=4)\n                file.truncate()\n                output_contents[key] = contents\n\n        temp_dir.cleanup()\n\n        return output_contents[\"alloc\"], output_contents[\"result\"]\n\n    def version(self) -> str:\n\"\"\"\n        Gets `evmone-t8n` binary version.\n        \"\"\"\n        if self.cached_version is None:\n            result = subprocess.run(\n                [str(self.binary), \"-v\"],\n                stdout=subprocess.PIPE,\n            )\n\n            if result.returncode != 0:\n                raise Exception(\"failed to evaluate: \" + result.stderr.decode())\n\n            self.cached_version = result.stdout.decode().strip()\n\n        return self.cached_version\n\n    def is_fork_supported(self, fork: Fork) -> bool:\n\"\"\"\n        Returns True if the fork is supported by the tool.\n        Currently, evmone-t8n provides no way to determine supported forks.\n        \"\"\"\n        return True\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.evmone.EvmOneTransitionTool.evaluate","title":"evaluate(alloc, txs, env, fork, chain_id=1, reward=0, eips=None)","text":"

Executes evmone-t8n with the specified arguments.

Source code in src/evm_transition_tool/evmone.py
def evaluate(\n    self,\n    alloc: Any,\n    txs: Any,\n    env: Any,\n    fork: Fork,\n    chain_id: int = 1,\n    reward: int = 0,\n    eips: Optional[List[int]] = None,\n) -> Tuple[Dict[str, Any], Dict[str, Any]]:\n\"\"\"\n    Executes `evmone-t8n` with the specified arguments.\n    \"\"\"\n    fork_name = fork.name()\n    if eips is not None:\n        fork_name = \"+\".join([fork_name] + [str(eip) for eip in eips])\n\n    temp_dir = tempfile.TemporaryDirectory()\n\n    input_contents = {\n        \"alloc\": alloc,\n        \"env\": env,\n        \"txs\": txs,\n    }\n    input_paths = {\n        k: os.path.join(temp_dir.name, f\"input_{k}.json\") for k in input_contents.keys()\n    }\n    for key, val in input_contents.items():\n        file_path = os.path.join(temp_dir.name, f\"input_{key}.json\")\n        write_json_file(val, file_path)\n\n    # Construct args for evmone-t8n binary\n    args = [\n        str(self.binary),\n        \"--state.fork\",\n        fork_name,\n        \"--input.alloc\",\n        input_paths[\"alloc\"],\n        \"--input.env\",\n        input_paths[\"env\"],\n        \"--input.txs\",\n        input_paths[\"txs\"],\n        \"--output.basedir\",\n        temp_dir.name,\n        \"--output.result\",\n        \"output_result.json\",\n        \"--output.alloc\",\n        \"output_alloc.json\",\n        \"--output.body\",\n        \"txs.rlp\",\n        \"--state.reward\",\n        str(reward),\n        \"--state.chainid\",\n        str(chain_id),\n    ]\n    result = subprocess.run(\n        args,\n        stdout=subprocess.PIPE,\n        stderr=subprocess.PIPE,\n    )\n\n    if result.returncode != 0:\n        raise Exception(\"failed to evaluate: \" + result.stderr.decode())\n\n    output_paths = {\n        \"alloc\": os.path.join(temp_dir.name, \"output_alloc.json\"),\n        \"result\": os.path.join(temp_dir.name, \"output_result.json\"),\n    }\n\n    output_contents = {}\n    for key, file_path in output_paths.items():\n        with open(file_path, \"r+\") as file:\n            contents = json.load(file)\n            file.seek(0)\n            json.dump(contents, file, ensure_ascii=False, indent=4)\n            file.truncate()\n            output_contents[key] = contents\n\n    temp_dir.cleanup()\n\n    return output_contents[\"alloc\"], output_contents[\"result\"]\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.evmone.EvmOneTransitionTool.version","title":"version()","text":"

Gets evmone-t8n binary version.

Source code in src/evm_transition_tool/evmone.py
def version(self) -> str:\n\"\"\"\n    Gets `evmone-t8n` binary version.\n    \"\"\"\n    if self.cached_version is None:\n        result = subprocess.run(\n            [str(self.binary), \"-v\"],\n            stdout=subprocess.PIPE,\n        )\n\n        if result.returncode != 0:\n            raise Exception(\"failed to evaluate: \" + result.stderr.decode())\n\n        self.cached_version = result.stdout.decode().strip()\n\n    return self.cached_version\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.evmone.EvmOneTransitionTool.is_fork_supported","title":"is_fork_supported(fork)","text":"

Returns True if the fork is supported by the tool. Currently, evmone-t8n provides no way to determine supported forks.

Source code in src/evm_transition_tool/evmone.py
def is_fork_supported(self, fork: Fork) -> bool:\n\"\"\"\n    Returns True if the fork is supported by the tool.\n    Currently, evmone-t8n provides no way to determine supported forks.\n    \"\"\"\n    return True\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.TransitionTool","title":"TransitionTool","text":"

Transition tool abstract base class which should be inherited by all transition tool implementations.

Source code in src/evm_transition_tool/transition_tool.py
class TransitionTool:\n\"\"\"\n    Transition tool abstract base class which should be inherited by all transition tool\n    implementations.\n    \"\"\"\n\n    traces: List[List[List[Dict]]] | None = None\n\n    registered_tools: List[Type[\"TransitionTool\"]] = []\n    default_tool: Optional[Type[\"TransitionTool\"]] = None\n    default_binary: Path\n    detect_binary_pattern: Pattern\n    version_flag: str = \"-v\"\n\n    # Abstract methods that each tool must implement\n\n    @abstractmethod\n    def __init__(\n        self,\n        *,\n        binary: Optional[Path] = None,\n        trace: bool = False,\n    ):\n\"\"\"\n        Abstract initialization method that all subclasses must implement.\n        \"\"\"\n        if binary is None:\n            binary = self.default_binary\n        else:\n            # improve behavior of which by resolving the path: ~/relative paths don't work\n            resolved_path = Path(os.path.expanduser(binary)).resolve()\n            if resolved_path.exists():\n                binary = resolved_path\n        binary = shutil.which(binary)  # type: ignore\n        if not binary:\n            raise TransitionToolNotFoundInPath(binary=binary)\n        self.binary = Path(binary)\n        self.trace = trace\n\n    def __init_subclass__(cls):\n\"\"\"\n        Registers all subclasses of TransitionTool as possible tools.\n        \"\"\"\n        TransitionTool.register_tool(cls)\n\n    @classmethod\n    def register_tool(cls, tool_subclass: Type[\"TransitionTool\"]):\n\"\"\"\n        Registers a given subclass as tool option.\n        \"\"\"\n        cls.registered_tools.append(tool_subclass)\n\n    @classmethod\n    def set_default_tool(cls, tool_subclass: Type[\"TransitionTool\"]):\n\"\"\"\n        Registers the default tool subclass.\n        \"\"\"\n        cls.default_tool = tool_subclass\n\n    @classmethod\n    def from_binary_path(cls, *, binary_path: Optional[Path], **kwargs) -> \"TransitionTool\":\n\"\"\"\n        Instantiates the appropriate TransitionTool subclass derived from the\n        tool's binary path.\n        \"\"\"\n        assert cls.default_tool is not None, \"default transition tool was never set\"\n\n        if binary_path is None:\n            return cls.default_tool(binary=binary_path, **kwargs)\n\n        resolved_path = Path(os.path.expanduser(binary_path)).resolve()\n        if resolved_path.exists():\n            binary_path = resolved_path\n        binary = shutil.which(binary_path)  # type: ignore\n\n        if not binary:\n            raise TransitionToolNotFoundInPath(binary=binary)\n\n        binary = Path(binary)\n\n        # Group the tools by version flag, so we only have to call the tool once for all the\n        # classes that share the same version flag\n        for version_flag, subclasses in groupby(\n            cls.registered_tools, key=lambda x: x.version_flag\n        ):\n            try:\n                with os.popen(f\"{binary} {version_flag}\") as f:\n                    binary_output = f.read()\n            except Exception:\n                # If the tool doesn't support the version flag,\n                # we'll get an non-zero exit code.\n                continue\n            for subclass in subclasses:\n                if subclass.detect_binary(binary_output):\n                    return subclass(binary=binary, **kwargs)\n\n        raise UnknownTransitionTool(f\"Unknown transition tool binary: {binary_path}\")\n\n    @classmethod\n    def detect_binary(cls, binary_output: str) -> bool:\n\"\"\"\n        Returns True if the binary matches the tool\n        \"\"\"\n        assert cls.detect_binary_pattern is not None\n\n        return cls.detect_binary_pattern.match(binary_output) is not None\n\n    @abstractmethod\n    def evaluate(\n        self,\n        alloc: Any,\n        txs: Any,\n        env: Any,\n        fork: Fork,\n        chain_id: int = 1,\n        reward: int = 0,\n        eips: Optional[List[int]] = None,\n    ) -> Tuple[Dict[str, Any], Dict[str, Any]]:\n\"\"\"\n        Simulate a state transition with specified parameters\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def version(self) -> str:\n\"\"\"\n        Return name and version of tool used to state transition\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def is_fork_supported(self, fork: Fork) -> bool:\n\"\"\"\n        Returns True if the fork is supported by the tool\n        \"\"\"\n        pass\n\n    def reset_traces(self):\n\"\"\"\n        Resets the internal trace storage for a new test to begin\n        \"\"\"\n        self.traces = None\n\n    def append_traces(self, new_traces: List[List[Dict]]):\n\"\"\"\n        Appends a list of traces of a state transition to the current list\n        \"\"\"\n        if self.traces is None:\n            self.traces = []\n        self.traces.append(new_traces)\n\n    def get_traces(self) -> List[List[List[Dict]]] | None:\n\"\"\"\n        Returns the accumulated traces\n        \"\"\"\n        return self.traces\n\n    def calc_state_root(self, alloc: Any, fork: Fork) -> bytes:\n\"\"\"\n        Calculate the state root for the given `alloc`.\n        \"\"\"\n        env: Dict[str, Any] = {\n            \"currentCoinbase\": \"0x0000000000000000000000000000000000000000\",\n            \"currentDifficulty\": \"0x0\",\n            \"currentGasLimit\": \"0x0\",\n            \"currentNumber\": \"0\",\n            \"currentTimestamp\": \"0\",\n        }\n\n        if fork.header_base_fee_required(0, 0):\n            env[\"currentBaseFee\"] = \"7\"\n\n        if fork.header_prev_randao_required(0, 0):\n            env[\"currentRandom\"] = \"0\"\n\n        if fork.header_withdrawals_required(0, 0):\n            env[\"withdrawals\"] = []\n\n        _, result = self.evaluate(alloc, [], env, fork)\n        state_root = result.get(\"stateRoot\")\n        if state_root is None or not isinstance(state_root, str):\n            raise Exception(\"Unable to calculate state root\")\n        return bytes.fromhex(state_root[2:])\n\n    def calc_withdrawals_root(self, withdrawals: Any, fork: Fork) -> bytes:\n\"\"\"\n        Calculate the state root for the given `alloc`.\n        \"\"\"\n        if type(withdrawals) is list and len(withdrawals) == 0:\n            # Optimize returning the empty root immediately\n            return bytes.fromhex(\n                \"56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\"\n            )\n\n        env: Dict[str, Any] = {\n            \"currentCoinbase\": \"0x0000000000000000000000000000000000000000\",\n            \"currentDifficulty\": \"0x0\",\n            \"currentGasLimit\": \"0x0\",\n            \"currentNumber\": \"0\",\n            \"currentTimestamp\": \"0\",\n            \"withdrawals\": withdrawals,\n        }\n\n        if fork.header_base_fee_required(0, 0):\n            env[\"currentBaseFee\"] = \"7\"\n\n        if fork.header_prev_randao_required(0, 0):\n            env[\"currentRandom\"] = \"0\"\n\n        if fork.header_excess_data_gas_required(0, 0):\n            env[\"currentExcessDataGas\"] = \"0\"\n\n        _, result = self.evaluate({}, [], env, fork)\n        withdrawals_root = result.get(\"withdrawalsRoot\")\n        if withdrawals_root is None:\n            raise Exception(\n                \"Unable to calculate withdrawals root: no value returned from transition tool\"\n            )\n        if type(withdrawals_root) is not str:\n            raise Exception(\n                \"Unable to calculate withdrawals root: \"\n                + \"incorrect type returned from transition tool: \"\n                + f\"{withdrawals_root}\"\n            )\n        return bytes.fromhex(withdrawals_root[2:])\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.transition_tool.TransitionTool.__init__","title":"__init__(*, binary=None, trace=False) abstractmethod","text":"

Abstract initialization method that all subclasses must implement.

Source code in src/evm_transition_tool/transition_tool.py
@abstractmethod\ndef __init__(\n    self,\n    *,\n    binary: Optional[Path] = None,\n    trace: bool = False,\n):\n\"\"\"\n    Abstract initialization method that all subclasses must implement.\n    \"\"\"\n    if binary is None:\n        binary = self.default_binary\n    else:\n        # improve behavior of which by resolving the path: ~/relative paths don't work\n        resolved_path = Path(os.path.expanduser(binary)).resolve()\n        if resolved_path.exists():\n            binary = resolved_path\n    binary = shutil.which(binary)  # type: ignore\n    if not binary:\n        raise TransitionToolNotFoundInPath(binary=binary)\n    self.binary = Path(binary)\n    self.trace = trace\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.transition_tool.TransitionTool.__init_subclass__","title":"__init_subclass__()","text":"

Registers all subclasses of TransitionTool as possible tools.

Source code in src/evm_transition_tool/transition_tool.py
def __init_subclass__(cls):\n\"\"\"\n    Registers all subclasses of TransitionTool as possible tools.\n    \"\"\"\n    TransitionTool.register_tool(cls)\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.transition_tool.TransitionTool.register_tool","title":"register_tool(tool_subclass) classmethod","text":"

Registers a given subclass as tool option.

Source code in src/evm_transition_tool/transition_tool.py
@classmethod\ndef register_tool(cls, tool_subclass: Type[\"TransitionTool\"]):\n\"\"\"\n    Registers a given subclass as tool option.\n    \"\"\"\n    cls.registered_tools.append(tool_subclass)\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.transition_tool.TransitionTool.set_default_tool","title":"set_default_tool(tool_subclass) classmethod","text":"

Registers the default tool subclass.

Source code in src/evm_transition_tool/transition_tool.py
@classmethod\ndef set_default_tool(cls, tool_subclass: Type[\"TransitionTool\"]):\n\"\"\"\n    Registers the default tool subclass.\n    \"\"\"\n    cls.default_tool = tool_subclass\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.transition_tool.TransitionTool.from_binary_path","title":"from_binary_path(*, binary_path, **kwargs) classmethod","text":"

Instantiates the appropriate TransitionTool subclass derived from the tool's binary path.

Source code in src/evm_transition_tool/transition_tool.py
@classmethod\ndef from_binary_path(cls, *, binary_path: Optional[Path], **kwargs) -> \"TransitionTool\":\n\"\"\"\n    Instantiates the appropriate TransitionTool subclass derived from the\n    tool's binary path.\n    \"\"\"\n    assert cls.default_tool is not None, \"default transition tool was never set\"\n\n    if binary_path is None:\n        return cls.default_tool(binary=binary_path, **kwargs)\n\n    resolved_path = Path(os.path.expanduser(binary_path)).resolve()\n    if resolved_path.exists():\n        binary_path = resolved_path\n    binary = shutil.which(binary_path)  # type: ignore\n\n    if not binary:\n        raise TransitionToolNotFoundInPath(binary=binary)\n\n    binary = Path(binary)\n\n    # Group the tools by version flag, so we only have to call the tool once for all the\n    # classes that share the same version flag\n    for version_flag, subclasses in groupby(\n        cls.registered_tools, key=lambda x: x.version_flag\n    ):\n        try:\n            with os.popen(f\"{binary} {version_flag}\") as f:\n                binary_output = f.read()\n        except Exception:\n            # If the tool doesn't support the version flag,\n            # we'll get an non-zero exit code.\n            continue\n        for subclass in subclasses:\n            if subclass.detect_binary(binary_output):\n                return subclass(binary=binary, **kwargs)\n\n    raise UnknownTransitionTool(f\"Unknown transition tool binary: {binary_path}\")\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.transition_tool.TransitionTool.detect_binary","title":"detect_binary(binary_output) classmethod","text":"

Returns True if the binary matches the tool

Source code in src/evm_transition_tool/transition_tool.py
@classmethod\ndef detect_binary(cls, binary_output: str) -> bool:\n\"\"\"\n    Returns True if the binary matches the tool\n    \"\"\"\n    assert cls.detect_binary_pattern is not None\n\n    return cls.detect_binary_pattern.match(binary_output) is not None\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.transition_tool.TransitionTool.evaluate","title":"evaluate(alloc, txs, env, fork, chain_id=1, reward=0, eips=None) abstractmethod","text":"

Simulate a state transition with specified parameters

Source code in src/evm_transition_tool/transition_tool.py
@abstractmethod\ndef evaluate(\n    self,\n    alloc: Any,\n    txs: Any,\n    env: Any,\n    fork: Fork,\n    chain_id: int = 1,\n    reward: int = 0,\n    eips: Optional[List[int]] = None,\n) -> Tuple[Dict[str, Any], Dict[str, Any]]:\n\"\"\"\n    Simulate a state transition with specified parameters\n    \"\"\"\n    pass\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.transition_tool.TransitionTool.version","title":"version() abstractmethod","text":"

Return name and version of tool used to state transition

Source code in src/evm_transition_tool/transition_tool.py
@abstractmethod\ndef version(self) -> str:\n\"\"\"\n    Return name and version of tool used to state transition\n    \"\"\"\n    pass\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.transition_tool.TransitionTool.is_fork_supported","title":"is_fork_supported(fork) abstractmethod","text":"

Returns True if the fork is supported by the tool

Source code in src/evm_transition_tool/transition_tool.py
@abstractmethod\ndef is_fork_supported(self, fork: Fork) -> bool:\n\"\"\"\n    Returns True if the fork is supported by the tool\n    \"\"\"\n    pass\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.transition_tool.TransitionTool.reset_traces","title":"reset_traces()","text":"

Resets the internal trace storage for a new test to begin

Source code in src/evm_transition_tool/transition_tool.py
def reset_traces(self):\n\"\"\"\n    Resets the internal trace storage for a new test to begin\n    \"\"\"\n    self.traces = None\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.transition_tool.TransitionTool.append_traces","title":"append_traces(new_traces)","text":"

Appends a list of traces of a state transition to the current list

Source code in src/evm_transition_tool/transition_tool.py
def append_traces(self, new_traces: List[List[Dict]]):\n\"\"\"\n    Appends a list of traces of a state transition to the current list\n    \"\"\"\n    if self.traces is None:\n        self.traces = []\n    self.traces.append(new_traces)\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.transition_tool.TransitionTool.get_traces","title":"get_traces()","text":"

Returns the accumulated traces

Source code in src/evm_transition_tool/transition_tool.py
def get_traces(self) -> List[List[List[Dict]]] | None:\n\"\"\"\n    Returns the accumulated traces\n    \"\"\"\n    return self.traces\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.transition_tool.TransitionTool.calc_state_root","title":"calc_state_root(alloc, fork)","text":"

Calculate the state root for the given alloc.

Source code in src/evm_transition_tool/transition_tool.py
def calc_state_root(self, alloc: Any, fork: Fork) -> bytes:\n\"\"\"\n    Calculate the state root for the given `alloc`.\n    \"\"\"\n    env: Dict[str, Any] = {\n        \"currentCoinbase\": \"0x0000000000000000000000000000000000000000\",\n        \"currentDifficulty\": \"0x0\",\n        \"currentGasLimit\": \"0x0\",\n        \"currentNumber\": \"0\",\n        \"currentTimestamp\": \"0\",\n    }\n\n    if fork.header_base_fee_required(0, 0):\n        env[\"currentBaseFee\"] = \"7\"\n\n    if fork.header_prev_randao_required(0, 0):\n        env[\"currentRandom\"] = \"0\"\n\n    if fork.header_withdrawals_required(0, 0):\n        env[\"withdrawals\"] = []\n\n    _, result = self.evaluate(alloc, [], env, fork)\n    state_root = result.get(\"stateRoot\")\n    if state_root is None or not isinstance(state_root, str):\n        raise Exception(\"Unable to calculate state root\")\n    return bytes.fromhex(state_root[2:])\n
"},{"location":"library/evm_transition_tool/#evm_transition_tool.transition_tool.TransitionTool.calc_withdrawals_root","title":"calc_withdrawals_root(withdrawals, fork)","text":"

Calculate the state root for the given alloc.

Source code in src/evm_transition_tool/transition_tool.py
def calc_withdrawals_root(self, withdrawals: Any, fork: Fork) -> bytes:\n\"\"\"\n    Calculate the state root for the given `alloc`.\n    \"\"\"\n    if type(withdrawals) is list and len(withdrawals) == 0:\n        # Optimize returning the empty root immediately\n        return bytes.fromhex(\n            \"56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\"\n        )\n\n    env: Dict[str, Any] = {\n        \"currentCoinbase\": \"0x0000000000000000000000000000000000000000\",\n        \"currentDifficulty\": \"0x0\",\n        \"currentGasLimit\": \"0x0\",\n        \"currentNumber\": \"0\",\n        \"currentTimestamp\": \"0\",\n        \"withdrawals\": withdrawals,\n    }\n\n    if fork.header_base_fee_required(0, 0):\n        env[\"currentBaseFee\"] = \"7\"\n\n    if fork.header_prev_randao_required(0, 0):\n        env[\"currentRandom\"] = \"0\"\n\n    if fork.header_excess_data_gas_required(0, 0):\n        env[\"currentExcessDataGas\"] = \"0\"\n\n    _, result = self.evaluate({}, [], env, fork)\n    withdrawals_root = result.get(\"withdrawalsRoot\")\n    if withdrawals_root is None:\n        raise Exception(\n            \"Unable to calculate withdrawals root: no value returned from transition tool\"\n        )\n    if type(withdrawals_root) is not str:\n        raise Exception(\n            \"Unable to calculate withdrawals root: \"\n            + \"incorrect type returned from transition tool: \"\n            + f\"{withdrawals_root}\"\n        )\n    return bytes.fromhex(withdrawals_root[2:])\n
"},{"location":"library/pytest_plugins/","title":"Overview","text":""},{"location":"library/pytest_plugins/#pytest-framework-and-customizations","title":"Pytest Framework and Customizations","text":"

Package containing pytest plugins related to test filling.

"},{"location":"library/pytest_plugins/forks/","title":"Forks Plugin","text":"

A pytest plugin to configure the forks in the test session. It parametrizes tests based on the user-provided fork range the tests' specified validity markers.

Pytest plugin to enable fork range configuration for the test session.

"},{"location":"library/pytest_plugins/forks/#pytest_plugins.forks.forks.pytest_addoption","title":"pytest_addoption(parser)","text":"

Adds command-line options to pytest.

Source code in src/pytest_plugins/forks/forks.py
def pytest_addoption(parser):\n\"\"\"\n    Adds command-line options to pytest.\n    \"\"\"\n    fork_group = parser.getgroup(\"Forks\", \"Specify the fork range to generate fixtures for\")\n    fork_group.addoption(\n        \"--forks\",\n        action=\"store_true\",\n        dest=\"show_fork_help\",\n        default=False,\n        help=\"Display forks supported by the test framework and exit.\",\n    )\n    fork_group.addoption(\n        \"--fork\",\n        action=\"store\",\n        dest=\"single_fork\",\n        default=None,\n        help=\"Only fill tests for the specified fork.\",\n    )\n    fork_group.addoption(\n        \"--from\",\n        action=\"store\",\n        dest=\"forks_from\",\n        default=None,\n        help=\"Fill tests from and including the specified fork.\",\n    )\n    fork_group.addoption(\n        \"--until\",\n        action=\"store\",\n        dest=\"forks_until\",\n        default=None,\n        help=\"Fill tests until and including the specified fork.\",\n    )\n
"},{"location":"library/pytest_plugins/forks/#pytest_plugins.forks.forks.get_forks","title":"get_forks()","text":"

Returns a list of all the fork classes implemented by ethereum_test_forks ordered chronologically by deployment.

Source code in src/ethereum_test_forks/helpers.py
def get_forks() -> List[Fork]:\n\"\"\"\n    Returns a list of all the fork classes implemented by\n    `ethereum_test_forks` ordered chronologically by deployment.\n    \"\"\"\n    all_forks: List[Fork] = []\n    for fork_name in forks.__dict__:\n        fork = forks.__dict__[fork_name]\n        if not isinstance(fork, type):\n            continue\n        if issubclass(fork, BaseFork) and fork is not BaseFork:\n            all_forks.append(fork)\n    return all_forks\n
"},{"location":"library/pytest_plugins/forks/#pytest_plugins.forks.forks.TransitionTool","title":"TransitionTool","text":"

Transition tool abstract base class which should be inherited by all transition tool implementations.

Source code in src/evm_transition_tool/transition_tool.py
class TransitionTool:\n\"\"\"\n    Transition tool abstract base class which should be inherited by all transition tool\n    implementations.\n    \"\"\"\n\n    traces: List[List[List[Dict]]] | None = None\n\n    registered_tools: List[Type[\"TransitionTool\"]] = []\n    default_tool: Optional[Type[\"TransitionTool\"]] = None\n    default_binary: Path\n    detect_binary_pattern: Pattern\n    version_flag: str = \"-v\"\n\n    # Abstract methods that each tool must implement\n\n    @abstractmethod\n    def __init__(\n        self,\n        *,\n        binary: Optional[Path] = None,\n        trace: bool = False,\n    ):\n\"\"\"\n        Abstract initialization method that all subclasses must implement.\n        \"\"\"\n        if binary is None:\n            binary = self.default_binary\n        else:\n            # improve behavior of which by resolving the path: ~/relative paths don't work\n            resolved_path = Path(os.path.expanduser(binary)).resolve()\n            if resolved_path.exists():\n                binary = resolved_path\n        binary = shutil.which(binary)  # type: ignore\n        if not binary:\n            raise TransitionToolNotFoundInPath(binary=binary)\n        self.binary = Path(binary)\n        self.trace = trace\n\n    def __init_subclass__(cls):\n\"\"\"\n        Registers all subclasses of TransitionTool as possible tools.\n        \"\"\"\n        TransitionTool.register_tool(cls)\n\n    @classmethod\n    def register_tool(cls, tool_subclass: Type[\"TransitionTool\"]):\n\"\"\"\n        Registers a given subclass as tool option.\n        \"\"\"\n        cls.registered_tools.append(tool_subclass)\n\n    @classmethod\n    def set_default_tool(cls, tool_subclass: Type[\"TransitionTool\"]):\n\"\"\"\n        Registers the default tool subclass.\n        \"\"\"\n        cls.default_tool = tool_subclass\n\n    @classmethod\n    def from_binary_path(cls, *, binary_path: Optional[Path], **kwargs) -> \"TransitionTool\":\n\"\"\"\n        Instantiates the appropriate TransitionTool subclass derived from the\n        tool's binary path.\n        \"\"\"\n        assert cls.default_tool is not None, \"default transition tool was never set\"\n\n        if binary_path is None:\n            return cls.default_tool(binary=binary_path, **kwargs)\n\n        resolved_path = Path(os.path.expanduser(binary_path)).resolve()\n        if resolved_path.exists():\n            binary_path = resolved_path\n        binary = shutil.which(binary_path)  # type: ignore\n\n        if not binary:\n            raise TransitionToolNotFoundInPath(binary=binary)\n\n        binary = Path(binary)\n\n        # Group the tools by version flag, so we only have to call the tool once for all the\n        # classes that share the same version flag\n        for version_flag, subclasses in groupby(\n            cls.registered_tools, key=lambda x: x.version_flag\n        ):\n            try:\n                with os.popen(f\"{binary} {version_flag}\") as f:\n                    binary_output = f.read()\n            except Exception:\n                # If the tool doesn't support the version flag,\n                # we'll get an non-zero exit code.\n                continue\n            for subclass in subclasses:\n                if subclass.detect_binary(binary_output):\n                    return subclass(binary=binary, **kwargs)\n\n        raise UnknownTransitionTool(f\"Unknown transition tool binary: {binary_path}\")\n\n    @classmethod\n    def detect_binary(cls, binary_output: str) -> bool:\n\"\"\"\n        Returns True if the binary matches the tool\n        \"\"\"\n        assert cls.detect_binary_pattern is not None\n\n        return cls.detect_binary_pattern.match(binary_output) is not None\n\n    @abstractmethod\n    def evaluate(\n        self,\n        alloc: Any,\n        txs: Any,\n        env: Any,\n        fork: Fork,\n        chain_id: int = 1,\n        reward: int = 0,\n        eips: Optional[List[int]] = None,\n    ) -> Tuple[Dict[str, Any], Dict[str, Any]]:\n\"\"\"\n        Simulate a state transition with specified parameters\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def version(self) -> str:\n\"\"\"\n        Return name and version of tool used to state transition\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def is_fork_supported(self, fork: Fork) -> bool:\n\"\"\"\n        Returns True if the fork is supported by the tool\n        \"\"\"\n        pass\n\n    def reset_traces(self):\n\"\"\"\n        Resets the internal trace storage for a new test to begin\n        \"\"\"\n        self.traces = None\n\n    def append_traces(self, new_traces: List[List[Dict]]):\n\"\"\"\n        Appends a list of traces of a state transition to the current list\n        \"\"\"\n        if self.traces is None:\n            self.traces = []\n        self.traces.append(new_traces)\n\n    def get_traces(self) -> List[List[List[Dict]]] | None:\n\"\"\"\n        Returns the accumulated traces\n        \"\"\"\n        return self.traces\n\n    def calc_state_root(self, alloc: Any, fork: Fork) -> bytes:\n\"\"\"\n        Calculate the state root for the given `alloc`.\n        \"\"\"\n        env: Dict[str, Any] = {\n            \"currentCoinbase\": \"0x0000000000000000000000000000000000000000\",\n            \"currentDifficulty\": \"0x0\",\n            \"currentGasLimit\": \"0x0\",\n            \"currentNumber\": \"0\",\n            \"currentTimestamp\": \"0\",\n        }\n\n        if fork.header_base_fee_required(0, 0):\n            env[\"currentBaseFee\"] = \"7\"\n\n        if fork.header_prev_randao_required(0, 0):\n            env[\"currentRandom\"] = \"0\"\n\n        if fork.header_withdrawals_required(0, 0):\n            env[\"withdrawals\"] = []\n\n        _, result = self.evaluate(alloc, [], env, fork)\n        state_root = result.get(\"stateRoot\")\n        if state_root is None or not isinstance(state_root, str):\n            raise Exception(\"Unable to calculate state root\")\n        return bytes.fromhex(state_root[2:])\n\n    def calc_withdrawals_root(self, withdrawals: Any, fork: Fork) -> bytes:\n\"\"\"\n        Calculate the state root for the given `alloc`.\n        \"\"\"\n        if type(withdrawals) is list and len(withdrawals) == 0:\n            # Optimize returning the empty root immediately\n            return bytes.fromhex(\n                \"56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\"\n            )\n\n        env: Dict[str, Any] = {\n            \"currentCoinbase\": \"0x0000000000000000000000000000000000000000\",\n            \"currentDifficulty\": \"0x0\",\n            \"currentGasLimit\": \"0x0\",\n            \"currentNumber\": \"0\",\n            \"currentTimestamp\": \"0\",\n            \"withdrawals\": withdrawals,\n        }\n\n        if fork.header_base_fee_required(0, 0):\n            env[\"currentBaseFee\"] = \"7\"\n\n        if fork.header_prev_randao_required(0, 0):\n            env[\"currentRandom\"] = \"0\"\n\n        if fork.header_excess_data_gas_required(0, 0):\n            env[\"currentExcessDataGas\"] = \"0\"\n\n        _, result = self.evaluate({}, [], env, fork)\n        withdrawals_root = result.get(\"withdrawalsRoot\")\n        if withdrawals_root is None:\n            raise Exception(\n                \"Unable to calculate withdrawals root: no value returned from transition tool\"\n            )\n        if type(withdrawals_root) is not str:\n            raise Exception(\n                \"Unable to calculate withdrawals root: \"\n                + \"incorrect type returned from transition tool: \"\n                + f\"{withdrawals_root}\"\n            )\n        return bytes.fromhex(withdrawals_root[2:])\n
"},{"location":"library/pytest_plugins/forks/#evm_transition_tool.transition_tool.TransitionTool.__init__","title":"__init__(*, binary=None, trace=False) abstractmethod","text":"

Abstract initialization method that all subclasses must implement.

Source code in src/evm_transition_tool/transition_tool.py
@abstractmethod\ndef __init__(\n    self,\n    *,\n    binary: Optional[Path] = None,\n    trace: bool = False,\n):\n\"\"\"\n    Abstract initialization method that all subclasses must implement.\n    \"\"\"\n    if binary is None:\n        binary = self.default_binary\n    else:\n        # improve behavior of which by resolving the path: ~/relative paths don't work\n        resolved_path = Path(os.path.expanduser(binary)).resolve()\n        if resolved_path.exists():\n            binary = resolved_path\n    binary = shutil.which(binary)  # type: ignore\n    if not binary:\n        raise TransitionToolNotFoundInPath(binary=binary)\n    self.binary = Path(binary)\n    self.trace = trace\n
"},{"location":"library/pytest_plugins/forks/#evm_transition_tool.transition_tool.TransitionTool.__init_subclass__","title":"__init_subclass__()","text":"

Registers all subclasses of TransitionTool as possible tools.

Source code in src/evm_transition_tool/transition_tool.py
def __init_subclass__(cls):\n\"\"\"\n    Registers all subclasses of TransitionTool as possible tools.\n    \"\"\"\n    TransitionTool.register_tool(cls)\n
"},{"location":"library/pytest_plugins/forks/#evm_transition_tool.transition_tool.TransitionTool.register_tool","title":"register_tool(tool_subclass) classmethod","text":"

Registers a given subclass as tool option.

Source code in src/evm_transition_tool/transition_tool.py
@classmethod\ndef register_tool(cls, tool_subclass: Type[\"TransitionTool\"]):\n\"\"\"\n    Registers a given subclass as tool option.\n    \"\"\"\n    cls.registered_tools.append(tool_subclass)\n
"},{"location":"library/pytest_plugins/forks/#evm_transition_tool.transition_tool.TransitionTool.set_default_tool","title":"set_default_tool(tool_subclass) classmethod","text":"

Registers the default tool subclass.

Source code in src/evm_transition_tool/transition_tool.py
@classmethod\ndef set_default_tool(cls, tool_subclass: Type[\"TransitionTool\"]):\n\"\"\"\n    Registers the default tool subclass.\n    \"\"\"\n    cls.default_tool = tool_subclass\n
"},{"location":"library/pytest_plugins/forks/#evm_transition_tool.transition_tool.TransitionTool.from_binary_path","title":"from_binary_path(*, binary_path, **kwargs) classmethod","text":"

Instantiates the appropriate TransitionTool subclass derived from the tool's binary path.

Source code in src/evm_transition_tool/transition_tool.py
@classmethod\ndef from_binary_path(cls, *, binary_path: Optional[Path], **kwargs) -> \"TransitionTool\":\n\"\"\"\n    Instantiates the appropriate TransitionTool subclass derived from the\n    tool's binary path.\n    \"\"\"\n    assert cls.default_tool is not None, \"default transition tool was never set\"\n\n    if binary_path is None:\n        return cls.default_tool(binary=binary_path, **kwargs)\n\n    resolved_path = Path(os.path.expanduser(binary_path)).resolve()\n    if resolved_path.exists():\n        binary_path = resolved_path\n    binary = shutil.which(binary_path)  # type: ignore\n\n    if not binary:\n        raise TransitionToolNotFoundInPath(binary=binary)\n\n    binary = Path(binary)\n\n    # Group the tools by version flag, so we only have to call the tool once for all the\n    # classes that share the same version flag\n    for version_flag, subclasses in groupby(\n        cls.registered_tools, key=lambda x: x.version_flag\n    ):\n        try:\n            with os.popen(f\"{binary} {version_flag}\") as f:\n                binary_output = f.read()\n        except Exception:\n            # If the tool doesn't support the version flag,\n            # we'll get an non-zero exit code.\n            continue\n        for subclass in subclasses:\n            if subclass.detect_binary(binary_output):\n                return subclass(binary=binary, **kwargs)\n\n    raise UnknownTransitionTool(f\"Unknown transition tool binary: {binary_path}\")\n
"},{"location":"library/pytest_plugins/forks/#evm_transition_tool.transition_tool.TransitionTool.detect_binary","title":"detect_binary(binary_output) classmethod","text":"

Returns True if the binary matches the tool

Source code in src/evm_transition_tool/transition_tool.py
@classmethod\ndef detect_binary(cls, binary_output: str) -> bool:\n\"\"\"\n    Returns True if the binary matches the tool\n    \"\"\"\n    assert cls.detect_binary_pattern is not None\n\n    return cls.detect_binary_pattern.match(binary_output) is not None\n
"},{"location":"library/pytest_plugins/forks/#evm_transition_tool.transition_tool.TransitionTool.evaluate","title":"evaluate(alloc, txs, env, fork, chain_id=1, reward=0, eips=None) abstractmethod","text":"

Simulate a state transition with specified parameters

Source code in src/evm_transition_tool/transition_tool.py
@abstractmethod\ndef evaluate(\n    self,\n    alloc: Any,\n    txs: Any,\n    env: Any,\n    fork: Fork,\n    chain_id: int = 1,\n    reward: int = 0,\n    eips: Optional[List[int]] = None,\n) -> Tuple[Dict[str, Any], Dict[str, Any]]:\n\"\"\"\n    Simulate a state transition with specified parameters\n    \"\"\"\n    pass\n
"},{"location":"library/pytest_plugins/forks/#evm_transition_tool.transition_tool.TransitionTool.version","title":"version() abstractmethod","text":"

Return name and version of tool used to state transition

Source code in src/evm_transition_tool/transition_tool.py
@abstractmethod\ndef version(self) -> str:\n\"\"\"\n    Return name and version of tool used to state transition\n    \"\"\"\n    pass\n
"},{"location":"library/pytest_plugins/forks/#evm_transition_tool.transition_tool.TransitionTool.is_fork_supported","title":"is_fork_supported(fork) abstractmethod","text":"

Returns True if the fork is supported by the tool

Source code in src/evm_transition_tool/transition_tool.py
@abstractmethod\ndef is_fork_supported(self, fork: Fork) -> bool:\n\"\"\"\n    Returns True if the fork is supported by the tool\n    \"\"\"\n    pass\n
"},{"location":"library/pytest_plugins/forks/#evm_transition_tool.transition_tool.TransitionTool.reset_traces","title":"reset_traces()","text":"

Resets the internal trace storage for a new test to begin

Source code in src/evm_transition_tool/transition_tool.py
def reset_traces(self):\n\"\"\"\n    Resets the internal trace storage for a new test to begin\n    \"\"\"\n    self.traces = None\n
"},{"location":"library/pytest_plugins/forks/#evm_transition_tool.transition_tool.TransitionTool.append_traces","title":"append_traces(new_traces)","text":"

Appends a list of traces of a state transition to the current list

Source code in src/evm_transition_tool/transition_tool.py
def append_traces(self, new_traces: List[List[Dict]]):\n\"\"\"\n    Appends a list of traces of a state transition to the current list\n    \"\"\"\n    if self.traces is None:\n        self.traces = []\n    self.traces.append(new_traces)\n
"},{"location":"library/pytest_plugins/forks/#evm_transition_tool.transition_tool.TransitionTool.get_traces","title":"get_traces()","text":"

Returns the accumulated traces

Source code in src/evm_transition_tool/transition_tool.py
def get_traces(self) -> List[List[List[Dict]]] | None:\n\"\"\"\n    Returns the accumulated traces\n    \"\"\"\n    return self.traces\n
"},{"location":"library/pytest_plugins/forks/#evm_transition_tool.transition_tool.TransitionTool.calc_state_root","title":"calc_state_root(alloc, fork)","text":"

Calculate the state root for the given alloc.

Source code in src/evm_transition_tool/transition_tool.py
def calc_state_root(self, alloc: Any, fork: Fork) -> bytes:\n\"\"\"\n    Calculate the state root for the given `alloc`.\n    \"\"\"\n    env: Dict[str, Any] = {\n        \"currentCoinbase\": \"0x0000000000000000000000000000000000000000\",\n        \"currentDifficulty\": \"0x0\",\n        \"currentGasLimit\": \"0x0\",\n        \"currentNumber\": \"0\",\n        \"currentTimestamp\": \"0\",\n    }\n\n    if fork.header_base_fee_required(0, 0):\n        env[\"currentBaseFee\"] = \"7\"\n\n    if fork.header_prev_randao_required(0, 0):\n        env[\"currentRandom\"] = \"0\"\n\n    if fork.header_withdrawals_required(0, 0):\n        env[\"withdrawals\"] = []\n\n    _, result = self.evaluate(alloc, [], env, fork)\n    state_root = result.get(\"stateRoot\")\n    if state_root is None or not isinstance(state_root, str):\n        raise Exception(\"Unable to calculate state root\")\n    return bytes.fromhex(state_root[2:])\n
"},{"location":"library/pytest_plugins/forks/#evm_transition_tool.transition_tool.TransitionTool.calc_withdrawals_root","title":"calc_withdrawals_root(withdrawals, fork)","text":"

Calculate the state root for the given alloc.

Source code in src/evm_transition_tool/transition_tool.py
def calc_withdrawals_root(self, withdrawals: Any, fork: Fork) -> bytes:\n\"\"\"\n    Calculate the state root for the given `alloc`.\n    \"\"\"\n    if type(withdrawals) is list and len(withdrawals) == 0:\n        # Optimize returning the empty root immediately\n        return bytes.fromhex(\n            \"56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\"\n        )\n\n    env: Dict[str, Any] = {\n        \"currentCoinbase\": \"0x0000000000000000000000000000000000000000\",\n        \"currentDifficulty\": \"0x0\",\n        \"currentGasLimit\": \"0x0\",\n        \"currentNumber\": \"0\",\n        \"currentTimestamp\": \"0\",\n        \"withdrawals\": withdrawals,\n    }\n\n    if fork.header_base_fee_required(0, 0):\n        env[\"currentBaseFee\"] = \"7\"\n\n    if fork.header_prev_randao_required(0, 0):\n        env[\"currentRandom\"] = \"0\"\n\n    if fork.header_excess_data_gas_required(0, 0):\n        env[\"currentExcessDataGas\"] = \"0\"\n\n    _, result = self.evaluate({}, [], env, fork)\n    withdrawals_root = result.get(\"withdrawalsRoot\")\n    if withdrawals_root is None:\n        raise Exception(\n            \"Unable to calculate withdrawals root: no value returned from transition tool\"\n        )\n    if type(withdrawals_root) is not str:\n        raise Exception(\n            \"Unable to calculate withdrawals root: \"\n            + \"incorrect type returned from transition tool: \"\n            + f\"{withdrawals_root}\"\n        )\n    return bytes.fromhex(withdrawals_root[2:])\n
"},{"location":"library/pytest_plugins/forks/#pytest_plugins.forks.forks.get_deployed_forks","title":"get_deployed_forks()","text":"

Returns a list of all the fork classes implemented by ethereum_test_forks that have been deployed to mainnet, chronologically ordered by deployment.

Source code in src/ethereum_test_forks/helpers.py
def get_deployed_forks():\n\"\"\"\n    Returns a list of all the fork classes implemented by `ethereum_test_forks`\n    that have been deployed to mainnet, chronologically ordered by deployment.\n    \"\"\"\n    return [fork for fork in get_forks() if fork.is_deployed()]\n
"},{"location":"library/pytest_plugins/forks/#pytest_plugins.forks.forks.pytest_configure","title":"pytest_configure(config)","text":"

Register the plugin's custom markers and process command-line options.

Custom marker registration: https://docs.pytest.org/en/7.1.x/how-to/writing_plugins.html#registering-custom-markers

Source code in src/pytest_plugins/forks/forks.py
@pytest.hookimpl(tryfirst=True)\ndef pytest_configure(config):\n\"\"\"\n    Register the plugin's custom markers and process command-line options.\n\n    Custom marker registration:\n    https://docs.pytest.org/en/7.1.x/how-to/writing_plugins.html#registering-custom-markers\n    \"\"\"\n    config.addinivalue_line(\n        \"markers\",\n        (\n            \"valid_at_transition_to(fork): specifies a test case is valid \"\n            \"only at fork transition boundary to the specified fork\"\n        ),\n    )\n    config.addinivalue_line(\n        \"markers\",\n        \"valid_from(fork): specifies from which fork a test case is valid\",\n    )\n    config.addinivalue_line(\n        \"markers\",\n        \"valid_until(fork): specifies until which fork a test case is valid\",\n    )\n\n    single_fork = config.getoption(\"single_fork\")\n    forks_from = config.getoption(\"forks_from\")\n    forks_until = config.getoption(\"forks_until\")\n    show_fork_help = config.getoption(\"show_fork_help\")\n\n    all_forks = get_forks()\n    # TODO: Tricky, this removes the *Glacier forks.\n    config.all_forks = forks_from_until(all_forks[0], all_forks[-1])\n    config.fork_map = {fork.name(): fork for fork in config.all_forks}\n    config.fork_names = list(config.fork_map.keys())\n\n    available_forks_help = textwrap.dedent(\n        f\"\"\"\\\n        Available forks:\n{\", \".join(config.fork_names)}\n        \"\"\"\n    )\n    available_forks_help += textwrap.dedent(\n        f\"\"\"\\\n        Available transition forks:\n{\", \".join([fork.name() for fork in get_transition_forks()])}\n        \"\"\"\n    )\n    dev_forks_help = textwrap.dedent(\n        \"To run tests for a fork under active development, it must be \"\n        \"specified explicitly via --forks-until=FORK.\\n\"\n        \"Tests are only ran for deployed mainnet forks by default, i.e., \"\n        f\"until {get_deployed_forks()[-1].name()}.\\n\"\n    )\n    if show_fork_help:\n        print(available_forks_help)\n        print(dev_forks_help)\n        pytest.exit(\"After displaying help.\", returncode=0)\n\n    if single_fork and single_fork not in config.fork_map.keys():\n        print(\"Error: Unsupported fork provided to --fork:\", single_fork, \"\\n\", file=sys.stderr)\n        print(available_forks_help, file=sys.stderr)\n        pytest.exit(\"Invalid command-line options.\", returncode=pytest.ExitCode.USAGE_ERROR)\n\n    if single_fork and (forks_from or forks_until):\n        print(\n            \"Error: --fork cannot be used in combination with --from or --until\", file=sys.stderr\n        )\n        pytest.exit(\"Invalid command-line options.\", returncode=pytest.ExitCode.USAGE_ERROR)\n\n    if single_fork:\n        forks_from = single_fork\n        forks_until = single_fork\n    else:\n        if not forks_from:\n            forks_from = config.fork_names[0]\n        if not forks_until:\n            forks_until = get_deployed_forks()[-1].name()\n\n    if forks_from not in config.fork_map.keys():\n        print(f\"Error: Unsupported fork provided to --from: {forks_from}\\n\", file=sys.stderr)\n        print(available_forks_help, file=sys.stderr)\n        pytest.exit(\"Invalid command-line options.\", returncode=pytest.ExitCode.USAGE_ERROR)\n\n    if forks_until not in config.fork_map.keys():\n        print(f\"Error: Unsupported fork provided to --until: {forks_until}\\n\", file=sys.stderr)\n        print(available_forks_help, file=sys.stderr)\n        pytest.exit(\"Invalid command-line options.\", returncode=pytest.ExitCode.USAGE_ERROR)\n\n    config.fork_range = config.fork_names[\n        config.fork_names.index(forks_from) : config.fork_names.index(forks_until) + 1\n    ]\n\n    if not config.fork_range:\n        print(\n            f\"Error: --from {forks_from} --until {forks_until} creates an empty fork range.\",\n            file=sys.stderr,\n        )\n        pytest.exit(\n            \"Command-line options produce empty fork range.\",\n            returncode=pytest.ExitCode.USAGE_ERROR,\n        )\n\n    # with --collect-only, we don't have access to these config options\n    if config.option.collectonly:\n        return\n\n    evm_bin = config.getoption(\"evm_bin\")\n    t8n = TransitionTool.from_binary_path(binary_path=evm_bin)\n    unsupported_forks = [\n        fork for fork in config.fork_range if not t8n.is_fork_supported(config.fork_map[fork])\n    ]\n    if unsupported_forks:\n        print(\n            \"Error: The configured evm tool doesn't support the following \"\n            f\"forks: {', '.join(unsupported_forks)}.\",\n            file=sys.stderr,\n        )\n        print(\n            \"\\nPlease specify a version of the evm tool which supports these \"\n            \"forks or use --until FORK to specify a supported fork.\\n\",\n            file=sys.stderr,\n        )\n        pytest.exit(\n            \"Incompatible evm tool with fork range.\", returncode=pytest.ExitCode.USAGE_ERROR\n        )\n
"},{"location":"library/pytest_plugins/forks/#pytest_plugins.forks.forks.get_transition_forks","title":"get_transition_forks()","text":"

Returns all the transition forks

Source code in src/ethereum_test_forks/helpers.py
def get_transition_forks() -> List[Fork]:\n\"\"\"\n    Returns all the transition forks\n    \"\"\"\n    transition_forks: List[Fork] = []\n\n    for fork_name in transition.__dict__:\n        fork = transition.__dict__[fork_name]\n        if not isinstance(fork, type):\n            continue\n        if issubclass(fork, TransitionBaseClass) and issubclass(fork, BaseFork):\n            transition_forks.append(fork)\n\n    return transition_forks\n
"},{"location":"library/pytest_plugins/forks/#pytest_plugins.forks.forks.transition_fork_to","title":"transition_fork_to(fork_to)","text":"

Returns the transition fork that transitions to the specified fork.

Source code in src/ethereum_test_forks/helpers.py
def transition_fork_to(fork_to: Fork) -> List[Fork]:\n\"\"\"\n    Returns the transition fork that transitions to the specified fork.\n    \"\"\"\n    transition_forks: List[Fork] = []\n    for transition_fork in get_transition_forks():\n        if not issubclass(transition_fork, TransitionBaseClass):\n            continue\n        if transition_fork.transitions_to() == fork_to:\n            transition_forks.append(transition_fork)\n\n    return transition_forks\n
"},{"location":"library/pytest_plugins/forks/#pytest_plugins.forks.forks.forks_from_until","title":"forks_from_until(fork_from, fork_until)","text":"

Returns the specified fork and all forks after it until and including the second specified fork

Source code in src/ethereum_test_forks/helpers.py
def forks_from_until(fork_from: Fork, fork_until: Fork) -> List[Fork]:\n\"\"\"\n    Returns the specified fork and all forks after it until and including the\n    second specified fork\n    \"\"\"\n    prev_fork = fork_until\n\n    forks: List[Fork] = []\n\n    while prev_fork != BaseFork and prev_fork != fork_from:\n        forks.insert(0, prev_fork)\n\n        prev_fork = prev_fork.__base__\n\n    if prev_fork == BaseFork:\n        return []\n\n    forks.insert(0, fork_from)\n\n    return forks\n
"},{"location":"library/pytest_plugins/forks/#pytest_plugins.forks.forks.pytest_report_header","title":"pytest_report_header(config, start_path)","text":"

A pytest hook called to obtain the report header.

Source code in src/pytest_plugins/forks/forks.py
@pytest.hookimpl(trylast=True)\ndef pytest_report_header(config, start_path):\n\"\"\"A pytest hook called to obtain the report header.\"\"\"\n    bold = \"\\033[1m\"\n    warning = \"\\033[93m\"\n    reset = \"\\033[39;49m\"\n    header = [\n        (bold + f\"Executing tests for: {', '.join(config.fork_range)} \" + reset),\n    ]\n    if config.getoption(\"forks_until\") is None:\n        header += [\n            (\n                bold + warning + \"Only executing tests with stable/deployed forks: \"\n                \"Specify an upcoming fork via --until=fork to \"\n                \"add forks under development.\" + reset\n            )\n        ]\n    return header\n
"},{"location":"library/pytest_plugins/forks/#pytest_plugins.forks.forks.fork","title":"fork(request)","text":"

Parametrize test cases by fork.

Source code in src/pytest_plugins/forks/forks.py
@pytest.fixture(autouse=True)\ndef fork(request):\n\"\"\"\n    Parametrize test cases by fork.\n    \"\"\"\n    pass\n
"},{"location":"library/pytest_plugins/forks/#pytest_plugins.forks.forks.get_validity_marker_args","title":"get_validity_marker_args(metafunc, validity_marker_name, test_name)","text":"

Check and return the arguments specified to validity markers.

Check that the validity markers:

  • pytest.mark.valid_from
  • pytest.mark.valid_until
  • pytest.mark.valid_at_transition_to

are applied at most once and have been provided with exactly one argument which is a valid fork name.

Parameters:

Name Type Description Default metafunc Metafunc

Pytest's metafunc object.

required validity_marker_name str

Name of the validity marker to validate and return.

required test_name str

The name of the test being parametrized by pytest_generate_tests.

required

Returns:

Type Description str | None

The name of the fork specified to the validity marker.

Source code in src/pytest_plugins/forks/forks.py
def get_validity_marker_args(\n    metafunc: Metafunc,\n    validity_marker_name: str,\n    test_name: str,\n) -> str | None:\n\"\"\"Check and return the arguments specified to validity markers.\n\n    Check that the validity markers:\n\n    - `pytest.mark.valid_from`\n    - `pytest.mark.valid_until`\n    - `pytest.mark.valid_at_transition_to`\n\n    are applied at most once and have been provided with exactly one\n    argument which is a valid fork name.\n\n    Args:\n        metafunc: Pytest's metafunc object.\n        validity_marker_name: Name of the validity marker to validate\n            and return.\n        test_name: The name of the test being parametrized by\n            `pytest_generate_tests`.\n\n    Returns:\n        The name of the fork specified to the validity marker.\n    \"\"\"\n    validity_markers = [\n        marker for marker in metafunc.definition.iter_markers(validity_marker_name)\n    ]\n    if not validity_markers:\n        return None\n    if len(validity_markers) > 1:\n        pytest.fail(f\"'{test_name}': Too many '{validity_marker_name}' markers applied to test. \")\n    if len(validity_markers[0].args) == 0:\n        pytest.fail(f\"'{test_name}': Missing fork argument with '{validity_marker_name}' marker. \")\n    if len(validity_markers[0].args) > 1:\n        pytest.fail(\n            f\"'{test_name}': Too many arguments specified to '{validity_marker_name}' marker. \"\n        )\n    fork_name = validity_markers[0].args[0]\n    if fork_name not in metafunc.config.fork_names:  # type: ignore\n        pytest.fail(\n            f\"'{test_name}' specifies an invalid fork '{fork_name}' to the \"\n            f\"'{validity_marker_name}'. \"\n            f\"List of valid forks: {', '.join(metafunc.config.fork_names)}\"  # type: ignore\n        )\n\n    return fork_name\n
"},{"location":"library/pytest_plugins/forks/#pytest_plugins.forks.forks.pytest_generate_tests","title":"pytest_generate_tests(metafunc)","text":"

Pytest hook used to dynamically generate test cases.

Source code in src/pytest_plugins/forks/forks.py
def pytest_generate_tests(metafunc):\n\"\"\"\n    Pytest hook used to dynamically generate test cases.\n    \"\"\"\n    test_name = metafunc.function.__name__\n    valid_at_transition_to = get_validity_marker_args(\n        metafunc, \"valid_at_transition_to\", test_name\n    )\n    valid_from = get_validity_marker_args(metafunc, \"valid_from\", test_name)\n    valid_until = get_validity_marker_args(metafunc, \"valid_until\", test_name)\n\n    if valid_at_transition_to and valid_from:\n        pytest.fail(\n            f\"'{test_name}': \"\n            \"The markers 'valid_from' and 'valid_at_transition_to' can't be combined. \"\n        )\n    if valid_at_transition_to and valid_until:\n        pytest.fail(\n            f\"'{test_name}': \"\n            \"The markers 'valid_until' and 'valid_at_transition_to' can't be combined. \"\n        )\n\n    intersection_range = []\n\n    if valid_at_transition_to:\n        if valid_at_transition_to in metafunc.config.fork_range:\n            to_fork = metafunc.config.fork_map[valid_at_transition_to]\n            intersection_range = transition_fork_to(to_fork)\n\n    else:\n        if not valid_from:\n            valid_from = metafunc.config.fork_names[0]\n\n        if not valid_until:\n            valid_until = metafunc.config.fork_names[-1]\n\n        test_fork_range = set(\n            metafunc.config.fork_names[\n                metafunc.config.fork_names.index(valid_from) : metafunc.config.fork_names.index(\n                    valid_until\n                )\n                + 1\n            ]\n        )\n\n        if not test_fork_range:\n            pytest.fail(\n                \"The test function's \"\n                f\"'{test_name}' fork validity markers generate \"\n                \"an empty fork range. Please check the arguments to its \"\n                f\"markers:  @pytest.mark.valid_from ({valid_from}) and \"\n                f\"@pytest.mark.valid_until ({valid_until}).\"\n            )\n\n        intersection_range = list(set(metafunc.config.fork_range) & test_fork_range)\n\n        intersection_range.sort(key=metafunc.config.fork_range.index)\n        intersection_range = [metafunc.config.fork_map[fork] for fork in intersection_range]\n\n    if \"fork\" in metafunc.fixturenames:\n        if not intersection_range:\n            pytest.skip(  # this reason is not reported on the command-line\n                f\"{test_name} is not valid for any any of forks specified on the command-line.\"\n            )\n        else:\n            metafunc.parametrize(\"fork\", intersection_range, scope=\"function\")\n
"},{"location":"library/pytest_plugins/navigation/","title":"Navigation","text":"
  • Overview
  • Forks
  • Test Filler
  • Spec Version Checker
"},{"location":"library/pytest_plugins/spec_version_checker/","title":"Spec Version Checker Plugin","text":"

A pytest plugin that verifies the tested version of an EIP specification against the latest version from the ethereum/EIPs Github repository.

A pytest plugin that checks that the spec version specified in test/filler modules matches that of ethereum/EIPs.

"},{"location":"library/pytest_plugins/spec_version_checker/#pytest_plugins.spec_version_checker.spec_version_checker.pytest_configure","title":"pytest_configure(config)","text":"

Register the plugin's custom markers and process command-line options.

Custom marker registration: https://docs.pytest.org/en/7.1.x/how-to/writing_plugins.html#registering-custom-markers

Source code in src/pytest_plugins/spec_version_checker/spec_version_checker.py
@pytest.hookimpl(tryfirst=True)\ndef pytest_configure(config):\n\"\"\"\n    Register the plugin's custom markers and process command-line options.\n\n    Custom marker registration:\n    https://docs.pytest.org/en/7.1.x/how-to/writing_plugins.html#registering-custom-markers\n    \"\"\"\n    config.addinivalue_line(\n        \"markers\",\n        \"eip_version_check: a test that tests the reference spec defined in an EIP test module.\",\n    )\n
"},{"location":"library/pytest_plugins/spec_version_checker/#pytest_plugins.spec_version_checker.spec_version_checker.ReferenceSpec","title":"ReferenceSpec","text":"

Reference Specification Description Abstract Class.

Source code in src/ethereum_test_tools/reference_spec/reference_spec.py
class ReferenceSpec:\n\"\"\"\n    Reference Specification Description Abstract Class.\n    \"\"\"\n\n    @abstractmethod\n    def name(self) -> str:\n\"\"\"\n        Returns the name of the spec.\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def has_known_version(self) -> bool:\n\"\"\"\n        Returns true if the reference spec object is hard-coded with a latest\n        known version.\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def known_version(self) -> str:\n\"\"\"\n        Returns the latest known version in the reference.\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def api_url(self) -> str:\n\"\"\"\n        Returns the URL required to poll the version from an API, if needed.\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def latest_version(self) -> str:\n\"\"\"\n        Returns a digest that points to the latest version of the spec.\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def is_outdated(self) -> bool:\n\"\"\"\n        Checks whether the reference specification has been updated since the\n        test was last updated.\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def write_info(self, info: Dict[str, str]):\n\"\"\"\n        Writes info about the reference specification used into the output\n        fixture.\n        \"\"\"\n        pass\n\n    @staticmethod\n    @abstractmethod\n    def parseable_from_module(module_dict: Dict[str, Any]) -> bool:\n\"\"\"\n        Checks whether the module's dict contains required reference spec\n        information.\n        \"\"\"\n        pass\n\n    @staticmethod\n    @abstractmethod\n    def parse_from_module(module_dict: Dict[str, Any]) -> \"ReferenceSpec\":\n\"\"\"\n        Parses the module's dict into a reference spec.\n        \"\"\"\n        pass\n
"},{"location":"library/pytest_plugins/spec_version_checker/#ethereum_test_tools.reference_spec.reference_spec.ReferenceSpec.name","title":"name() abstractmethod","text":"

Returns the name of the spec.

Source code in src/ethereum_test_tools/reference_spec/reference_spec.py
@abstractmethod\ndef name(self) -> str:\n\"\"\"\n    Returns the name of the spec.\n    \"\"\"\n    pass\n
"},{"location":"library/pytest_plugins/spec_version_checker/#ethereum_test_tools.reference_spec.reference_spec.ReferenceSpec.has_known_version","title":"has_known_version() abstractmethod","text":"

Returns true if the reference spec object is hard-coded with a latest known version.

Source code in src/ethereum_test_tools/reference_spec/reference_spec.py
@abstractmethod\ndef has_known_version(self) -> bool:\n\"\"\"\n    Returns true if the reference spec object is hard-coded with a latest\n    known version.\n    \"\"\"\n    pass\n
"},{"location":"library/pytest_plugins/spec_version_checker/#ethereum_test_tools.reference_spec.reference_spec.ReferenceSpec.known_version","title":"known_version() abstractmethod","text":"

Returns the latest known version in the reference.

Source code in src/ethereum_test_tools/reference_spec/reference_spec.py
@abstractmethod\ndef known_version(self) -> str:\n\"\"\"\n    Returns the latest known version in the reference.\n    \"\"\"\n    pass\n
"},{"location":"library/pytest_plugins/spec_version_checker/#ethereum_test_tools.reference_spec.reference_spec.ReferenceSpec.api_url","title":"api_url() abstractmethod","text":"

Returns the URL required to poll the version from an API, if needed.

Source code in src/ethereum_test_tools/reference_spec/reference_spec.py
@abstractmethod\ndef api_url(self) -> str:\n\"\"\"\n    Returns the URL required to poll the version from an API, if needed.\n    \"\"\"\n    pass\n
"},{"location":"library/pytest_plugins/spec_version_checker/#ethereum_test_tools.reference_spec.reference_spec.ReferenceSpec.latest_version","title":"latest_version() abstractmethod","text":"

Returns a digest that points to the latest version of the spec.

Source code in src/ethereum_test_tools/reference_spec/reference_spec.py
@abstractmethod\ndef latest_version(self) -> str:\n\"\"\"\n    Returns a digest that points to the latest version of the spec.\n    \"\"\"\n    pass\n
"},{"location":"library/pytest_plugins/spec_version_checker/#ethereum_test_tools.reference_spec.reference_spec.ReferenceSpec.is_outdated","title":"is_outdated() abstractmethod","text":"

Checks whether the reference specification has been updated since the test was last updated.

Source code in src/ethereum_test_tools/reference_spec/reference_spec.py
@abstractmethod\ndef is_outdated(self) -> bool:\n\"\"\"\n    Checks whether the reference specification has been updated since the\n    test was last updated.\n    \"\"\"\n    pass\n
"},{"location":"library/pytest_plugins/spec_version_checker/#ethereum_test_tools.reference_spec.reference_spec.ReferenceSpec.write_info","title":"write_info(info) abstractmethod","text":"

Writes info about the reference specification used into the output fixture.

Source code in src/ethereum_test_tools/reference_spec/reference_spec.py
@abstractmethod\ndef write_info(self, info: Dict[str, str]):\n\"\"\"\n    Writes info about the reference specification used into the output\n    fixture.\n    \"\"\"\n    pass\n
"},{"location":"library/pytest_plugins/spec_version_checker/#ethereum_test_tools.reference_spec.reference_spec.ReferenceSpec.parseable_from_module","title":"parseable_from_module(module_dict) staticmethod abstractmethod","text":"

Checks whether the module's dict contains required reference spec information.

Source code in src/ethereum_test_tools/reference_spec/reference_spec.py
@staticmethod\n@abstractmethod\ndef parseable_from_module(module_dict: Dict[str, Any]) -> bool:\n\"\"\"\n    Checks whether the module's dict contains required reference spec\n    information.\n    \"\"\"\n    pass\n
"},{"location":"library/pytest_plugins/spec_version_checker/#ethereum_test_tools.reference_spec.reference_spec.ReferenceSpec.parse_from_module","title":"parse_from_module(module_dict) staticmethod abstractmethod","text":"

Parses the module's dict into a reference spec.

Source code in src/ethereum_test_tools/reference_spec/reference_spec.py
@staticmethod\n@abstractmethod\ndef parse_from_module(module_dict: Dict[str, Any]) -> \"ReferenceSpec\":\n\"\"\"\n    Parses the module's dict into a reference spec.\n    \"\"\"\n    pass\n
"},{"location":"library/pytest_plugins/spec_version_checker/#pytest_plugins.spec_version_checker.spec_version_checker.get_ref_spec_from_module","title":"get_ref_spec_from_module(module)","text":"

Return the reference spec object defined in a module.

Raises:

Type Description Exception

If the module path contains \"eip\" and the module does not define a reference spec.

Returns:

Name Type Description spec_obj None | ReferenceSpec

Return None if the module path does not contain \"eip\", i.e., the module is not required to define a reference spec, otherwise, return the ReferenceSpec object as defined by the module.

Source code in src/pytest_plugins/spec_version_checker/spec_version_checker.py
def get_ref_spec_from_module(module: ModuleType) -> None | ReferenceSpec:\n\"\"\"\n    Return the reference spec object defined in a module.\n\n    Raises:\n        Exception: If the module path contains \"eip\" and the module\n            does not define a reference spec.\n\n    Returns:\n        spec_obj: Return None if the module path does not contain \"eip\",\n            i.e., the module is not required to define a reference spec,\n            otherwise, return the ReferenceSpec object as defined by the\n            module.\n    \"\"\"\n    if not is_test_for_an_eip(str(module.__file__)):\n        return None\n    module_dict = module.__dict__\n    parseable_ref_specs = [\n        ref_spec_type\n        for ref_spec_type in ReferenceSpecTypes\n        if ref_spec_type.parseable_from_module(module_dict)\n    ]\n    if len(parseable_ref_specs) > 0:\n        module_dict = module.__dict__\n        try:\n            spec_obj = parseable_ref_specs[0].parse_from_module(module_dict)\n        except Exception as e:\n            raise Exception(f\"Error in spec_version_checker: {e} (this test is generated).\")\n    else:\n        raise Exception(\"Test doesn't define REFERENCE_SPEC_GIT_PATH and REFERENCE_SPEC_VERSION\")\n    return spec_obj\n
"},{"location":"library/pytest_plugins/spec_version_checker/#pytest_plugins.spec_version_checker.spec_version_checker.reference_spec","title":"reference_spec(request)","text":"

Pytest fixture that returns the reference spec defined in a module.

See get_ref_spec_from_module.

Source code in src/pytest_plugins/spec_version_checker/spec_version_checker.py
@pytest.fixture(autouse=True, scope=\"module\")\ndef reference_spec(request) -> None | ReferenceSpec:\n\"\"\"\n    Pytest fixture that returns the reference spec defined in a module.\n\n    See `get_ref_spec_from_module`.\n    \"\"\"\n    return get_ref_spec_from_module(request.module)\n
"},{"location":"library/pytest_plugins/spec_version_checker/#pytest_plugins.spec_version_checker.spec_version_checker.is_test_for_an_eip","title":"is_test_for_an_eip(input_string)","text":"

Return True if input_string contains an EIP number, i.e., eipNNNN.

Source code in src/pytest_plugins/spec_version_checker/spec_version_checker.py
def is_test_for_an_eip(input_string: str) -> bool:\n\"\"\"\n    Return True if `input_string` contains an EIP number, i.e., eipNNNN.\n    \"\"\"\n    pattern = re.compile(r\".*eip\\d{1,4}\", re.IGNORECASE)\n    if pattern.match(input_string):\n        return True\n    return False\n
"},{"location":"library/pytest_plugins/spec_version_checker/#pytest_plugins.spec_version_checker.spec_version_checker.test_eip_spec_version","title":"test_eip_spec_version(module)","text":"

Test that the ReferenceSpec object as defined in the test module is not outdated when compared to the remote hash from ethereum/EIPs.

Source code in src/pytest_plugins/spec_version_checker/spec_version_checker.py
def test_eip_spec_version(module: ModuleType):\n\"\"\"\n    Test that the ReferenceSpec object as defined in the test module\n    is not outdated when compared to the remote hash from\n    ethereum/EIPs.\n    \"\"\"\n    ref_spec = get_ref_spec_from_module(module)\n    assert ref_spec, \"No reference spec object defined\"\n\n    message = (\n        \"The version of the spec referenced in \"\n        f\"{module} does not match that from ethereum/EIPs, \"\n        f\"tests might be outdated: Spec: {ref_spec.name()}. \"\n        f\"Referenced version: {ref_spec.known_version()}. \"\n        f\"Latest version: {ref_spec.latest_version()}. The \"\n        f\"version was retrieved from {ref_spec.api_url()}.\"\n    )\n    try:\n        is_up_to_date = not ref_spec.is_outdated()\n    except Exception as e:\n        raise Exception(\n            f\"Error in spec_version_checker: {e} (this test is generated). \"\n            f\"Reference spec URL: {ref_spec.api_url()}.\"\n        )\n\n    assert is_up_to_date, message\n
"},{"location":"library/pytest_plugins/spec_version_checker/#pytest_plugins.spec_version_checker.spec_version_checker.EIPSpecTestItem","title":"EIPSpecTestItem","text":"

Bases: Item

Custom pytest test item to test EIP spec versions.

Source code in src/pytest_plugins/spec_version_checker/spec_version_checker.py
class EIPSpecTestItem(Item):\n\"\"\"\n    Custom pytest test item to test EIP spec versions.\n    \"\"\"\n\n    def __init__(self, name, parent, module):\n        super().__init__(name, parent)\n        self.module = module\n\n    @classmethod\n    def from_parent(cls, parent, module):\n\"\"\"\n        Public constructor to define new tests.\n        https://docs.pytest.org/en/latest/reference/reference.html#pytest.nodes.Node.from_parent\n        \"\"\"\n        return super().from_parent(parent=parent, name=\"test_eip_spec_version\", module=module)\n\n    def runtest(self):\n\"\"\"\n        Define the test to execute for this item.\n        \"\"\"\n        test_eip_spec_version(self.module)\n\n    def reportinfo(self):\n\"\"\"\n        Get location information for this test item to use test reports.\n        \"\"\"\n        return \"spec_version_checker\", 0, f\"{self.name}\"\n
"},{"location":"library/pytest_plugins/spec_version_checker/#pytest_plugins.spec_version_checker.spec_version_checker.EIPSpecTestItem.from_parent","title":"from_parent(parent, module) classmethod","text":"

Public constructor to define new tests. https://docs.pytest.org/en/latest/reference/reference.html#pytest.nodes.Node.from_parent

Source code in src/pytest_plugins/spec_version_checker/spec_version_checker.py
@classmethod\ndef from_parent(cls, parent, module):\n\"\"\"\n    Public constructor to define new tests.\n    https://docs.pytest.org/en/latest/reference/reference.html#pytest.nodes.Node.from_parent\n    \"\"\"\n    return super().from_parent(parent=parent, name=\"test_eip_spec_version\", module=module)\n
"},{"location":"library/pytest_plugins/spec_version_checker/#pytest_plugins.spec_version_checker.spec_version_checker.EIPSpecTestItem.runtest","title":"runtest()","text":"

Define the test to execute for this item.

Source code in src/pytest_plugins/spec_version_checker/spec_version_checker.py
def runtest(self):\n\"\"\"\n    Define the test to execute for this item.\n    \"\"\"\n    test_eip_spec_version(self.module)\n
"},{"location":"library/pytest_plugins/spec_version_checker/#pytest_plugins.spec_version_checker.spec_version_checker.EIPSpecTestItem.reportinfo","title":"reportinfo()","text":"

Get location information for this test item to use test reports.

Source code in src/pytest_plugins/spec_version_checker/spec_version_checker.py
def reportinfo(self):\n\"\"\"\n    Get location information for this test item to use test reports.\n    \"\"\"\n    return \"spec_version_checker\", 0, f\"{self.name}\"\n
"},{"location":"library/pytest_plugins/spec_version_checker/#pytest_plugins.spec_version_checker.spec_version_checker.pytest_collection_modifyitems","title":"pytest_collection_modifyitems(session, config, items)","text":"

Insert a new test EIPSpecTestItem for every test modules that contains 'eip' in its path.

Source code in src/pytest_plugins/spec_version_checker/spec_version_checker.py
def pytest_collection_modifyitems(session, config, items):\n\"\"\"\n    Insert a new test EIPSpecTestItem for every test modules that\n    contains 'eip' in its path.\n    \"\"\"\n    modules = set(item.parent for item in items if isinstance(item.parent, Module))\n    new_test_eip_spec_version_items = [\n        EIPSpecTestItem.from_parent(module, module.obj)\n        for module in modules\n        if is_test_for_an_eip(str(module.path))\n    ]\n    for item in new_test_eip_spec_version_items:\n        item.add_marker(\"eip_version_check\", append=True)\n    items.extend(new_test_eip_spec_version_items)\n
"},{"location":"library/pytest_plugins/test_filler/","title":"Test Filler Plugin","text":"

A pytest plugin that provides fixtures that fill tests and generate fixtures.

Top-level pytest configuration file providing: - Command-line options, - Test-fixtures that can be used by all test cases, and that modifies pytest hooks in order to fill test specs for all tests and writes the generated fixtures to file.

"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.fill_test","title":"fill_test(t8n, test_spec, fork, engine, spec, eips=None)","text":"

Fills fixtures for the specified fork.

Source code in src/ethereum_test_tools/filling/fill.py
def fill_test(\n    t8n: TransitionTool,\n    test_spec: BaseTest,\n    fork: Fork,\n    engine: str,\n    spec: ReferenceSpec | None,\n    eips: Optional[List[int]] = None,\n) -> Fixture:\n\"\"\"\n    Fills fixtures for the specified fork.\n    \"\"\"\n    t8n.reset_traces()\n\n    genesis_rlp, genesis = test_spec.make_genesis(t8n, fork)\n\n    (blocks, head, alloc) = test_spec.make_blocks(\n        t8n,\n        genesis,\n        fork,\n        eips=eips,\n    )\n\n    fork_name = fork.name()\n    fixture = Fixture(\n        blocks=blocks,\n        genesis=genesis,\n        genesis_rlp=genesis_rlp,\n        head=head,\n        fork=\"+\".join([fork_name] + [str(eip) for eip in eips]) if eips is not None else fork_name,\n        pre_state=copy(test_spec.pre),\n        post_state=alloc_to_accounts(alloc),\n        seal_engine=engine,\n        name=test_spec.tag,\n    )\n    fixture.fill_info(t8n, spec)\n\n    return fixture\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.BlockchainTest","title":"BlockchainTest dataclass","text":"

Bases: BaseTest

Filler type that tests multiple blocks (valid or invalid) in a chain.

Source code in src/ethereum_test_tools/spec/blockchain_test.py
@dataclass(kw_only=True)\nclass BlockchainTest(BaseTest):\n\"\"\"\n    Filler type that tests multiple blocks (valid or invalid) in a chain.\n    \"\"\"\n\n    pre: Mapping[str, Account]\n    post: Mapping[str, Account]\n    blocks: List[Block]\n    genesis_environment: Environment = field(default_factory=Environment)\n    tag: str = \"\"\n\n    @classmethod\n    def pytest_parameter_name(cls) -> str:\n\"\"\"\n        Returns the parameter name used to identify this filler in a test.\n        \"\"\"\n        return \"blockchain_test\"\n\n    def make_genesis(\n        self,\n        t8n: TransitionTool,\n        fork: Fork,\n    ) -> Tuple[bytes, FixtureHeader]:\n\"\"\"\n        Create a genesis block from the state test definition.\n        \"\"\"\n        env = self.genesis_environment.set_fork_requirements(fork)\n\n        genesis = FixtureHeader(\n            parent_hash=EmptyHash,\n            ommers_hash=EmptyOmmersRoot,\n            coinbase=ZeroAddress,\n            state_root=t8n.calc_state_root(\n                to_json(self.pre),\n                fork,\n            ),\n            transactions_root=EmptyTrieRoot,\n            receipt_root=EmptyTrieRoot,\n            bloom=EmptyBloom,\n            difficulty=0x20000 if env.difficulty is None else env.difficulty,\n            number=0,\n            gas_limit=env.gas_limit,\n            gas_used=0,\n            timestamp=0,\n            extra_data=bytes([0]),\n            mix_digest=EmptyHash,\n            nonce=EmptyNonce,\n            base_fee=env.base_fee,\n            data_gas_used=env.data_gas_used,\n            excess_data_gas=env.excess_data_gas,\n            withdrawals_root=t8n.calc_withdrawals_root(env.withdrawals, fork)\n            if env.withdrawals is not None\n            else None,\n        )\n\n        genesis_rlp, genesis.hash = genesis.build(\n            txs=[],\n            ommers=[],\n            withdrawals=env.withdrawals,\n        )\n\n        return genesis_rlp, genesis\n\n    def make_block(\n        self,\n        t8n: TransitionTool,\n        fork: Fork,\n        block: Block,\n        previous_env: Environment,\n        previous_alloc: Dict[str, Any],\n        previous_head: bytes,\n        chain_id=1,\n        eips: Optional[List[int]] = None,\n    ) -> Tuple[FixtureBlock, Environment, Dict[str, Any], bytes]:\n\"\"\"\n        Produces a block based on the previous environment and allocation.\n        If the block is an invalid block, the environment and allocation\n        returned are the same as passed as parameters.\n        Raises exception on invalid test behavior.\n\n        Returns\n        -------\n            FixtureBlock: Block to be appended to the fixture.\n            Environment: Environment for the next block to produce.\n                If the produced block is invalid, this is exactly the same\n                environment as the one passed as parameter.\n            Dict[str, Any]: Allocation for the next block to produce.\n                If the produced block is invalid, this is exactly the same\n                allocation as the one passed as parameter.\n            str: Hash of the head of the chain, only updated if the produced\n                block is not invalid.\n\n        \"\"\"\n        if block.rlp and block.exception is not None:\n            raise Exception(\n                \"test correctness: post-state cannot be verified if the \"\n                + \"block's rlp is supplied and the block is not supposed \"\n                + \"to produce an exception\"\n            )\n\n        if block.rlp is None:\n            # This is the most common case, the RLP needs to be constructed\n            # based on the transactions to be included in the block.\n            # Set the environment according to the block to execute.\n            env = block.set_environment(previous_env)\n            env = env.set_fork_requirements(fork)\n\n            txs = (\n                [tx.with_signature_and_sender() for tx in block.txs]\n                if block.txs is not None\n                else []\n            )\n\n            next_alloc, result = t8n.evaluate(\n                alloc=previous_alloc,\n                txs=to_json_or_none(txs),\n                env=to_json(env),\n                fork=fork,\n                chain_id=chain_id,\n                reward=fork.get_reward(env.number, env.timestamp),\n                eips=eips,\n            )\n            try:\n                rejected_txs = verify_transactions(txs, result)\n            except Exception as e:\n                print_traces(t8n.get_traces())\n                pprint(result)\n                pprint(previous_alloc)\n                pprint(next_alloc)\n                raise e\n\n            if len(rejected_txs) > 0 and block.exception is None:\n                print_traces(t8n.get_traces())\n                raise Exception(\n                    \"one or more transactions in `BlockchainTest` are \"\n                    + \"intrinsically invalid, but the block was not expected \"\n                    + \"to be invalid. Please verify whether the transaction \"\n                    + \"was indeed expected to fail and add the proper \"\n                    + \"`block.exception`\"\n                )\n\n            header = FixtureHeader.from_dict(\n                result\n                | {\n                    \"parentHash\": env.parent_hash(),\n                    \"miner\": env.coinbase,\n                    \"transactionsRoot\": result.get(\"txRoot\"),\n                    \"difficulty\": str_or_none(result.get(\"currentDifficulty\"), \"0\"),\n                    \"number\": str(env.number),\n                    \"gasLimit\": str(env.gas_limit),\n                    \"timestamp\": str(env.timestamp),\n                    \"extraData\": block.extra_data\n                    if block.extra_data is not None and len(block.extra_data) != 0\n                    else \"0x\",\n                    \"sha3Uncles\": \"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",  # noqa: E501\n                    \"mixHash\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",  # noqa: E501\n                    \"nonce\": \"0x0000000000000000\",\n                    \"baseFeePerGas\": result.get(\"currentBaseFee\"),\n                    \"excessDataGas\": result.get(\"currentExcessDataGas\"),\n                }\n            )\n\n            assert len(header.state_root) == 32\n\n            if block.rlp_modifier is not None:\n                # Modify any parameter specified in the `rlp_modifier` after\n                # transition tool processing.\n                header = header.join(block.rlp_modifier)\n\n            rlp, header.hash = header.build(\n                txs=txs,\n                ommers=[],\n                withdrawals=env.withdrawals,\n            )\n\n            new_payload = FixtureEngineNewPayload.from_fixture_header(\n                fork=fork,\n                header=header,\n                transactions=txs,\n                withdrawals=env.withdrawals,\n                error_code=block.engine_api_error_code,\n            )\n\n            if block.exception is None:\n                # Return environment and allocation of the following block\n                return (\n                    FixtureBlock(\n                        rlp=rlp,\n                        new_payload=new_payload,\n                        block_header=header,\n                        block_number=header.number,\n                        txs=txs,\n                        ommers=[],\n                        withdrawals=env.withdrawals,\n                    ),\n                    env.apply_new_parent(header),\n                    next_alloc,\n                    header.hash,\n                )\n            else:\n                return (\n                    FixtureBlock(\n                        rlp=rlp,\n                        new_payload=new_payload,\n                        expected_exception=block.exception,\n                        block_number=header.number,\n                    ),\n                    previous_env,\n                    previous_alloc,\n                    previous_head,\n                )\n        else:\n            return (\n                FixtureBlock(\n                    rlp=block.rlp,\n                    expected_exception=block.exception,\n                ),\n                previous_env,\n                previous_alloc,\n                previous_head,\n            )\n\n    def make_blocks(\n        self,\n        t8n: TransitionTool,\n        genesis: FixtureHeader,\n        fork: Fork,\n        chain_id=1,\n        eips: Optional[List[int]] = None,\n    ) -> Tuple[List[FixtureBlock], bytes, Dict[str, Any]]:\n\"\"\"\n        Create a block list from the blockchain test definition.\n        Performs checks against the expected behavior of the test.\n        Raises exception on invalid test behavior.\n        \"\"\"\n        alloc = to_json(self.pre)\n        env = Environment.from_parent_header(genesis)\n        blocks: List[FixtureBlock] = []\n        head = genesis.hash if genesis.hash is not None else bytes([0] * 32)\n        for block in self.blocks:\n            fixture_block, env, alloc, head = self.make_block(\n                t8n=t8n,\n                fork=fork,\n                block=block,\n                previous_env=env,\n                previous_alloc=alloc,\n                previous_head=head,\n                chain_id=chain_id,\n                eips=eips,\n            )\n            blocks.append(fixture_block)\n\n        try:\n            verify_post_alloc(self.post, alloc)\n        except Exception as e:\n            print_traces(t8n.get_traces())\n            raise e\n\n        return (blocks, head, alloc)\n
"},{"location":"library/pytest_plugins/test_filler/#ethereum_test_tools.spec.blockchain_test.BlockchainTest.pytest_parameter_name","title":"pytest_parameter_name() classmethod","text":"

Returns the parameter name used to identify this filler in a test.

Source code in src/ethereum_test_tools/spec/blockchain_test.py
@classmethod\ndef pytest_parameter_name(cls) -> str:\n\"\"\"\n    Returns the parameter name used to identify this filler in a test.\n    \"\"\"\n    return \"blockchain_test\"\n
"},{"location":"library/pytest_plugins/test_filler/#ethereum_test_tools.spec.blockchain_test.BlockchainTest.make_genesis","title":"make_genesis(t8n, fork)","text":"

Create a genesis block from the state test definition.

Source code in src/ethereum_test_tools/spec/blockchain_test.py
def make_genesis(\n    self,\n    t8n: TransitionTool,\n    fork: Fork,\n) -> Tuple[bytes, FixtureHeader]:\n\"\"\"\n    Create a genesis block from the state test definition.\n    \"\"\"\n    env = self.genesis_environment.set_fork_requirements(fork)\n\n    genesis = FixtureHeader(\n        parent_hash=EmptyHash,\n        ommers_hash=EmptyOmmersRoot,\n        coinbase=ZeroAddress,\n        state_root=t8n.calc_state_root(\n            to_json(self.pre),\n            fork,\n        ),\n        transactions_root=EmptyTrieRoot,\n        receipt_root=EmptyTrieRoot,\n        bloom=EmptyBloom,\n        difficulty=0x20000 if env.difficulty is None else env.difficulty,\n        number=0,\n        gas_limit=env.gas_limit,\n        gas_used=0,\n        timestamp=0,\n        extra_data=bytes([0]),\n        mix_digest=EmptyHash,\n        nonce=EmptyNonce,\n        base_fee=env.base_fee,\n        data_gas_used=env.data_gas_used,\n        excess_data_gas=env.excess_data_gas,\n        withdrawals_root=t8n.calc_withdrawals_root(env.withdrawals, fork)\n        if env.withdrawals is not None\n        else None,\n    )\n\n    genesis_rlp, genesis.hash = genesis.build(\n        txs=[],\n        ommers=[],\n        withdrawals=env.withdrawals,\n    )\n\n    return genesis_rlp, genesis\n
"},{"location":"library/pytest_plugins/test_filler/#ethereum_test_tools.spec.blockchain_test.BlockchainTest.make_block","title":"make_block(t8n, fork, block, previous_env, previous_alloc, previous_head, chain_id=1, eips=None)","text":"

Produces a block based on the previous environment and allocation. If the block is an invalid block, the environment and allocation returned are the same as passed as parameters. Raises exception on invalid test behavior.

"},{"location":"library/pytest_plugins/test_filler/#ethereum_test_tools.spec.blockchain_test.BlockchainTest.make_block--returns","title":"Returns","text":"
FixtureBlock: Block to be appended to the fixture.\nEnvironment: Environment for the next block to produce.\n    If the produced block is invalid, this is exactly the same\n    environment as the one passed as parameter.\nDict[str, Any]: Allocation for the next block to produce.\n    If the produced block is invalid, this is exactly the same\n    allocation as the one passed as parameter.\nstr: Hash of the head of the chain, only updated if the produced\n    block is not invalid.\n
Source code in src/ethereum_test_tools/spec/blockchain_test.py
def make_block(\n    self,\n    t8n: TransitionTool,\n    fork: Fork,\n    block: Block,\n    previous_env: Environment,\n    previous_alloc: Dict[str, Any],\n    previous_head: bytes,\n    chain_id=1,\n    eips: Optional[List[int]] = None,\n) -> Tuple[FixtureBlock, Environment, Dict[str, Any], bytes]:\n\"\"\"\n    Produces a block based on the previous environment and allocation.\n    If the block is an invalid block, the environment and allocation\n    returned are the same as passed as parameters.\n    Raises exception on invalid test behavior.\n\n    Returns\n    -------\n        FixtureBlock: Block to be appended to the fixture.\n        Environment: Environment for the next block to produce.\n            If the produced block is invalid, this is exactly the same\n            environment as the one passed as parameter.\n        Dict[str, Any]: Allocation for the next block to produce.\n            If the produced block is invalid, this is exactly the same\n            allocation as the one passed as parameter.\n        str: Hash of the head of the chain, only updated if the produced\n            block is not invalid.\n\n    \"\"\"\n    if block.rlp and block.exception is not None:\n        raise Exception(\n            \"test correctness: post-state cannot be verified if the \"\n            + \"block's rlp is supplied and the block is not supposed \"\n            + \"to produce an exception\"\n        )\n\n    if block.rlp is None:\n        # This is the most common case, the RLP needs to be constructed\n        # based on the transactions to be included in the block.\n        # Set the environment according to the block to execute.\n        env = block.set_environment(previous_env)\n        env = env.set_fork_requirements(fork)\n\n        txs = (\n            [tx.with_signature_and_sender() for tx in block.txs]\n            if block.txs is not None\n            else []\n        )\n\n        next_alloc, result = t8n.evaluate(\n            alloc=previous_alloc,\n            txs=to_json_or_none(txs),\n            env=to_json(env),\n            fork=fork,\n            chain_id=chain_id,\n            reward=fork.get_reward(env.number, env.timestamp),\n            eips=eips,\n        )\n        try:\n            rejected_txs = verify_transactions(txs, result)\n        except Exception as e:\n            print_traces(t8n.get_traces())\n            pprint(result)\n            pprint(previous_alloc)\n            pprint(next_alloc)\n            raise e\n\n        if len(rejected_txs) > 0 and block.exception is None:\n            print_traces(t8n.get_traces())\n            raise Exception(\n                \"one or more transactions in `BlockchainTest` are \"\n                + \"intrinsically invalid, but the block was not expected \"\n                + \"to be invalid. Please verify whether the transaction \"\n                + \"was indeed expected to fail and add the proper \"\n                + \"`block.exception`\"\n            )\n\n        header = FixtureHeader.from_dict(\n            result\n            | {\n                \"parentHash\": env.parent_hash(),\n                \"miner\": env.coinbase,\n                \"transactionsRoot\": result.get(\"txRoot\"),\n                \"difficulty\": str_or_none(result.get(\"currentDifficulty\"), \"0\"),\n                \"number\": str(env.number),\n                \"gasLimit\": str(env.gas_limit),\n                \"timestamp\": str(env.timestamp),\n                \"extraData\": block.extra_data\n                if block.extra_data is not None and len(block.extra_data) != 0\n                else \"0x\",\n                \"sha3Uncles\": \"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",  # noqa: E501\n                \"mixHash\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",  # noqa: E501\n                \"nonce\": \"0x0000000000000000\",\n                \"baseFeePerGas\": result.get(\"currentBaseFee\"),\n                \"excessDataGas\": result.get(\"currentExcessDataGas\"),\n            }\n        )\n\n        assert len(header.state_root) == 32\n\n        if block.rlp_modifier is not None:\n            # Modify any parameter specified in the `rlp_modifier` after\n            # transition tool processing.\n            header = header.join(block.rlp_modifier)\n\n        rlp, header.hash = header.build(\n            txs=txs,\n            ommers=[],\n            withdrawals=env.withdrawals,\n        )\n\n        new_payload = FixtureEngineNewPayload.from_fixture_header(\n            fork=fork,\n            header=header,\n            transactions=txs,\n            withdrawals=env.withdrawals,\n            error_code=block.engine_api_error_code,\n        )\n\n        if block.exception is None:\n            # Return environment and allocation of the following block\n            return (\n                FixtureBlock(\n                    rlp=rlp,\n                    new_payload=new_payload,\n                    block_header=header,\n                    block_number=header.number,\n                    txs=txs,\n                    ommers=[],\n                    withdrawals=env.withdrawals,\n                ),\n                env.apply_new_parent(header),\n                next_alloc,\n                header.hash,\n            )\n        else:\n            return (\n                FixtureBlock(\n                    rlp=rlp,\n                    new_payload=new_payload,\n                    expected_exception=block.exception,\n                    block_number=header.number,\n                ),\n                previous_env,\n                previous_alloc,\n                previous_head,\n            )\n    else:\n        return (\n            FixtureBlock(\n                rlp=block.rlp,\n                expected_exception=block.exception,\n            ),\n            previous_env,\n            previous_alloc,\n            previous_head,\n        )\n
"},{"location":"library/pytest_plugins/test_filler/#ethereum_test_tools.spec.blockchain_test.BlockchainTest.make_blocks","title":"make_blocks(t8n, genesis, fork, chain_id=1, eips=None)","text":"

Create a block list from the blockchain test definition. Performs checks against the expected behavior of the test. Raises exception on invalid test behavior.

Source code in src/ethereum_test_tools/spec/blockchain_test.py
def make_blocks(\n    self,\n    t8n: TransitionTool,\n    genesis: FixtureHeader,\n    fork: Fork,\n    chain_id=1,\n    eips: Optional[List[int]] = None,\n) -> Tuple[List[FixtureBlock], bytes, Dict[str, Any]]:\n\"\"\"\n    Create a block list from the blockchain test definition.\n    Performs checks against the expected behavior of the test.\n    Raises exception on invalid test behavior.\n    \"\"\"\n    alloc = to_json(self.pre)\n    env = Environment.from_parent_header(genesis)\n    blocks: List[FixtureBlock] = []\n    head = genesis.hash if genesis.hash is not None else bytes([0] * 32)\n    for block in self.blocks:\n        fixture_block, env, alloc, head = self.make_block(\n            t8n=t8n,\n            fork=fork,\n            block=block,\n            previous_env=env,\n            previous_alloc=alloc,\n            previous_head=head,\n            chain_id=chain_id,\n            eips=eips,\n        )\n        blocks.append(fixture_block)\n\n    try:\n        verify_post_alloc(self.post, alloc)\n    except Exception as e:\n        print_traces(t8n.get_traces())\n        raise e\n\n    return (blocks, head, alloc)\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.TransitionTool","title":"TransitionTool","text":"

Transition tool abstract base class which should be inherited by all transition tool implementations.

Source code in src/evm_transition_tool/transition_tool.py
class TransitionTool:\n\"\"\"\n    Transition tool abstract base class which should be inherited by all transition tool\n    implementations.\n    \"\"\"\n\n    traces: List[List[List[Dict]]] | None = None\n\n    registered_tools: List[Type[\"TransitionTool\"]] = []\n    default_tool: Optional[Type[\"TransitionTool\"]] = None\n    default_binary: Path\n    detect_binary_pattern: Pattern\n    version_flag: str = \"-v\"\n\n    # Abstract methods that each tool must implement\n\n    @abstractmethod\n    def __init__(\n        self,\n        *,\n        binary: Optional[Path] = None,\n        trace: bool = False,\n    ):\n\"\"\"\n        Abstract initialization method that all subclasses must implement.\n        \"\"\"\n        if binary is None:\n            binary = self.default_binary\n        else:\n            # improve behavior of which by resolving the path: ~/relative paths don't work\n            resolved_path = Path(os.path.expanduser(binary)).resolve()\n            if resolved_path.exists():\n                binary = resolved_path\n        binary = shutil.which(binary)  # type: ignore\n        if not binary:\n            raise TransitionToolNotFoundInPath(binary=binary)\n        self.binary = Path(binary)\n        self.trace = trace\n\n    def __init_subclass__(cls):\n\"\"\"\n        Registers all subclasses of TransitionTool as possible tools.\n        \"\"\"\n        TransitionTool.register_tool(cls)\n\n    @classmethod\n    def register_tool(cls, tool_subclass: Type[\"TransitionTool\"]):\n\"\"\"\n        Registers a given subclass as tool option.\n        \"\"\"\n        cls.registered_tools.append(tool_subclass)\n\n    @classmethod\n    def set_default_tool(cls, tool_subclass: Type[\"TransitionTool\"]):\n\"\"\"\n        Registers the default tool subclass.\n        \"\"\"\n        cls.default_tool = tool_subclass\n\n    @classmethod\n    def from_binary_path(cls, *, binary_path: Optional[Path], **kwargs) -> \"TransitionTool\":\n\"\"\"\n        Instantiates the appropriate TransitionTool subclass derived from the\n        tool's binary path.\n        \"\"\"\n        assert cls.default_tool is not None, \"default transition tool was never set\"\n\n        if binary_path is None:\n            return cls.default_tool(binary=binary_path, **kwargs)\n\n        resolved_path = Path(os.path.expanduser(binary_path)).resolve()\n        if resolved_path.exists():\n            binary_path = resolved_path\n        binary = shutil.which(binary_path)  # type: ignore\n\n        if not binary:\n            raise TransitionToolNotFoundInPath(binary=binary)\n\n        binary = Path(binary)\n\n        # Group the tools by version flag, so we only have to call the tool once for all the\n        # classes that share the same version flag\n        for version_flag, subclasses in groupby(\n            cls.registered_tools, key=lambda x: x.version_flag\n        ):\n            try:\n                with os.popen(f\"{binary} {version_flag}\") as f:\n                    binary_output = f.read()\n            except Exception:\n                # If the tool doesn't support the version flag,\n                # we'll get an non-zero exit code.\n                continue\n            for subclass in subclasses:\n                if subclass.detect_binary(binary_output):\n                    return subclass(binary=binary, **kwargs)\n\n        raise UnknownTransitionTool(f\"Unknown transition tool binary: {binary_path}\")\n\n    @classmethod\n    def detect_binary(cls, binary_output: str) -> bool:\n\"\"\"\n        Returns True if the binary matches the tool\n        \"\"\"\n        assert cls.detect_binary_pattern is not None\n\n        return cls.detect_binary_pattern.match(binary_output) is not None\n\n    @abstractmethod\n    def evaluate(\n        self,\n        alloc: Any,\n        txs: Any,\n        env: Any,\n        fork: Fork,\n        chain_id: int = 1,\n        reward: int = 0,\n        eips: Optional[List[int]] = None,\n    ) -> Tuple[Dict[str, Any], Dict[str, Any]]:\n\"\"\"\n        Simulate a state transition with specified parameters\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def version(self) -> str:\n\"\"\"\n        Return name and version of tool used to state transition\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def is_fork_supported(self, fork: Fork) -> bool:\n\"\"\"\n        Returns True if the fork is supported by the tool\n        \"\"\"\n        pass\n\n    def reset_traces(self):\n\"\"\"\n        Resets the internal trace storage for a new test to begin\n        \"\"\"\n        self.traces = None\n\n    def append_traces(self, new_traces: List[List[Dict]]):\n\"\"\"\n        Appends a list of traces of a state transition to the current list\n        \"\"\"\n        if self.traces is None:\n            self.traces = []\n        self.traces.append(new_traces)\n\n    def get_traces(self) -> List[List[List[Dict]]] | None:\n\"\"\"\n        Returns the accumulated traces\n        \"\"\"\n        return self.traces\n\n    def calc_state_root(self, alloc: Any, fork: Fork) -> bytes:\n\"\"\"\n        Calculate the state root for the given `alloc`.\n        \"\"\"\n        env: Dict[str, Any] = {\n            \"currentCoinbase\": \"0x0000000000000000000000000000000000000000\",\n            \"currentDifficulty\": \"0x0\",\n            \"currentGasLimit\": \"0x0\",\n            \"currentNumber\": \"0\",\n            \"currentTimestamp\": \"0\",\n        }\n\n        if fork.header_base_fee_required(0, 0):\n            env[\"currentBaseFee\"] = \"7\"\n\n        if fork.header_prev_randao_required(0, 0):\n            env[\"currentRandom\"] = \"0\"\n\n        if fork.header_withdrawals_required(0, 0):\n            env[\"withdrawals\"] = []\n\n        _, result = self.evaluate(alloc, [], env, fork)\n        state_root = result.get(\"stateRoot\")\n        if state_root is None or not isinstance(state_root, str):\n            raise Exception(\"Unable to calculate state root\")\n        return bytes.fromhex(state_root[2:])\n\n    def calc_withdrawals_root(self, withdrawals: Any, fork: Fork) -> bytes:\n\"\"\"\n        Calculate the state root for the given `alloc`.\n        \"\"\"\n        if type(withdrawals) is list and len(withdrawals) == 0:\n            # Optimize returning the empty root immediately\n            return bytes.fromhex(\n                \"56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\"\n            )\n\n        env: Dict[str, Any] = {\n            \"currentCoinbase\": \"0x0000000000000000000000000000000000000000\",\n            \"currentDifficulty\": \"0x0\",\n            \"currentGasLimit\": \"0x0\",\n            \"currentNumber\": \"0\",\n            \"currentTimestamp\": \"0\",\n            \"withdrawals\": withdrawals,\n        }\n\n        if fork.header_base_fee_required(0, 0):\n            env[\"currentBaseFee\"] = \"7\"\n\n        if fork.header_prev_randao_required(0, 0):\n            env[\"currentRandom\"] = \"0\"\n\n        if fork.header_excess_data_gas_required(0, 0):\n            env[\"currentExcessDataGas\"] = \"0\"\n\n        _, result = self.evaluate({}, [], env, fork)\n        withdrawals_root = result.get(\"withdrawalsRoot\")\n        if withdrawals_root is None:\n            raise Exception(\n                \"Unable to calculate withdrawals root: no value returned from transition tool\"\n            )\n        if type(withdrawals_root) is not str:\n            raise Exception(\n                \"Unable to calculate withdrawals root: \"\n                + \"incorrect type returned from transition tool: \"\n                + f\"{withdrawals_root}\"\n            )\n        return bytes.fromhex(withdrawals_root[2:])\n
"},{"location":"library/pytest_plugins/test_filler/#evm_transition_tool.transition_tool.TransitionTool.__init__","title":"__init__(*, binary=None, trace=False) abstractmethod","text":"

Abstract initialization method that all subclasses must implement.

Source code in src/evm_transition_tool/transition_tool.py
@abstractmethod\ndef __init__(\n    self,\n    *,\n    binary: Optional[Path] = None,\n    trace: bool = False,\n):\n\"\"\"\n    Abstract initialization method that all subclasses must implement.\n    \"\"\"\n    if binary is None:\n        binary = self.default_binary\n    else:\n        # improve behavior of which by resolving the path: ~/relative paths don't work\n        resolved_path = Path(os.path.expanduser(binary)).resolve()\n        if resolved_path.exists():\n            binary = resolved_path\n    binary = shutil.which(binary)  # type: ignore\n    if not binary:\n        raise TransitionToolNotFoundInPath(binary=binary)\n    self.binary = Path(binary)\n    self.trace = trace\n
"},{"location":"library/pytest_plugins/test_filler/#evm_transition_tool.transition_tool.TransitionTool.__init_subclass__","title":"__init_subclass__()","text":"

Registers all subclasses of TransitionTool as possible tools.

Source code in src/evm_transition_tool/transition_tool.py
def __init_subclass__(cls):\n\"\"\"\n    Registers all subclasses of TransitionTool as possible tools.\n    \"\"\"\n    TransitionTool.register_tool(cls)\n
"},{"location":"library/pytest_plugins/test_filler/#evm_transition_tool.transition_tool.TransitionTool.register_tool","title":"register_tool(tool_subclass) classmethod","text":"

Registers a given subclass as tool option.

Source code in src/evm_transition_tool/transition_tool.py
@classmethod\ndef register_tool(cls, tool_subclass: Type[\"TransitionTool\"]):\n\"\"\"\n    Registers a given subclass as tool option.\n    \"\"\"\n    cls.registered_tools.append(tool_subclass)\n
"},{"location":"library/pytest_plugins/test_filler/#evm_transition_tool.transition_tool.TransitionTool.set_default_tool","title":"set_default_tool(tool_subclass) classmethod","text":"

Registers the default tool subclass.

Source code in src/evm_transition_tool/transition_tool.py
@classmethod\ndef set_default_tool(cls, tool_subclass: Type[\"TransitionTool\"]):\n\"\"\"\n    Registers the default tool subclass.\n    \"\"\"\n    cls.default_tool = tool_subclass\n
"},{"location":"library/pytest_plugins/test_filler/#evm_transition_tool.transition_tool.TransitionTool.from_binary_path","title":"from_binary_path(*, binary_path, **kwargs) classmethod","text":"

Instantiates the appropriate TransitionTool subclass derived from the tool's binary path.

Source code in src/evm_transition_tool/transition_tool.py
@classmethod\ndef from_binary_path(cls, *, binary_path: Optional[Path], **kwargs) -> \"TransitionTool\":\n\"\"\"\n    Instantiates the appropriate TransitionTool subclass derived from the\n    tool's binary path.\n    \"\"\"\n    assert cls.default_tool is not None, \"default transition tool was never set\"\n\n    if binary_path is None:\n        return cls.default_tool(binary=binary_path, **kwargs)\n\n    resolved_path = Path(os.path.expanduser(binary_path)).resolve()\n    if resolved_path.exists():\n        binary_path = resolved_path\n    binary = shutil.which(binary_path)  # type: ignore\n\n    if not binary:\n        raise TransitionToolNotFoundInPath(binary=binary)\n\n    binary = Path(binary)\n\n    # Group the tools by version flag, so we only have to call the tool once for all the\n    # classes that share the same version flag\n    for version_flag, subclasses in groupby(\n        cls.registered_tools, key=lambda x: x.version_flag\n    ):\n        try:\n            with os.popen(f\"{binary} {version_flag}\") as f:\n                binary_output = f.read()\n        except Exception:\n            # If the tool doesn't support the version flag,\n            # we'll get an non-zero exit code.\n            continue\n        for subclass in subclasses:\n            if subclass.detect_binary(binary_output):\n                return subclass(binary=binary, **kwargs)\n\n    raise UnknownTransitionTool(f\"Unknown transition tool binary: {binary_path}\")\n
"},{"location":"library/pytest_plugins/test_filler/#evm_transition_tool.transition_tool.TransitionTool.detect_binary","title":"detect_binary(binary_output) classmethod","text":"

Returns True if the binary matches the tool

Source code in src/evm_transition_tool/transition_tool.py
@classmethod\ndef detect_binary(cls, binary_output: str) -> bool:\n\"\"\"\n    Returns True if the binary matches the tool\n    \"\"\"\n    assert cls.detect_binary_pattern is not None\n\n    return cls.detect_binary_pattern.match(binary_output) is not None\n
"},{"location":"library/pytest_plugins/test_filler/#evm_transition_tool.transition_tool.TransitionTool.evaluate","title":"evaluate(alloc, txs, env, fork, chain_id=1, reward=0, eips=None) abstractmethod","text":"

Simulate a state transition with specified parameters

Source code in src/evm_transition_tool/transition_tool.py
@abstractmethod\ndef evaluate(\n    self,\n    alloc: Any,\n    txs: Any,\n    env: Any,\n    fork: Fork,\n    chain_id: int = 1,\n    reward: int = 0,\n    eips: Optional[List[int]] = None,\n) -> Tuple[Dict[str, Any], Dict[str, Any]]:\n\"\"\"\n    Simulate a state transition with specified parameters\n    \"\"\"\n    pass\n
"},{"location":"library/pytest_plugins/test_filler/#evm_transition_tool.transition_tool.TransitionTool.version","title":"version() abstractmethod","text":"

Return name and version of tool used to state transition

Source code in src/evm_transition_tool/transition_tool.py
@abstractmethod\ndef version(self) -> str:\n\"\"\"\n    Return name and version of tool used to state transition\n    \"\"\"\n    pass\n
"},{"location":"library/pytest_plugins/test_filler/#evm_transition_tool.transition_tool.TransitionTool.is_fork_supported","title":"is_fork_supported(fork) abstractmethod","text":"

Returns True if the fork is supported by the tool

Source code in src/evm_transition_tool/transition_tool.py
@abstractmethod\ndef is_fork_supported(self, fork: Fork) -> bool:\n\"\"\"\n    Returns True if the fork is supported by the tool\n    \"\"\"\n    pass\n
"},{"location":"library/pytest_plugins/test_filler/#evm_transition_tool.transition_tool.TransitionTool.reset_traces","title":"reset_traces()","text":"

Resets the internal trace storage for a new test to begin

Source code in src/evm_transition_tool/transition_tool.py
def reset_traces(self):\n\"\"\"\n    Resets the internal trace storage for a new test to begin\n    \"\"\"\n    self.traces = None\n
"},{"location":"library/pytest_plugins/test_filler/#evm_transition_tool.transition_tool.TransitionTool.append_traces","title":"append_traces(new_traces)","text":"

Appends a list of traces of a state transition to the current list

Source code in src/evm_transition_tool/transition_tool.py
def append_traces(self, new_traces: List[List[Dict]]):\n\"\"\"\n    Appends a list of traces of a state transition to the current list\n    \"\"\"\n    if self.traces is None:\n        self.traces = []\n    self.traces.append(new_traces)\n
"},{"location":"library/pytest_plugins/test_filler/#evm_transition_tool.transition_tool.TransitionTool.get_traces","title":"get_traces()","text":"

Returns the accumulated traces

Source code in src/evm_transition_tool/transition_tool.py
def get_traces(self) -> List[List[List[Dict]]] | None:\n\"\"\"\n    Returns the accumulated traces\n    \"\"\"\n    return self.traces\n
"},{"location":"library/pytest_plugins/test_filler/#evm_transition_tool.transition_tool.TransitionTool.calc_state_root","title":"calc_state_root(alloc, fork)","text":"

Calculate the state root for the given alloc.

Source code in src/evm_transition_tool/transition_tool.py
def calc_state_root(self, alloc: Any, fork: Fork) -> bytes:\n\"\"\"\n    Calculate the state root for the given `alloc`.\n    \"\"\"\n    env: Dict[str, Any] = {\n        \"currentCoinbase\": \"0x0000000000000000000000000000000000000000\",\n        \"currentDifficulty\": \"0x0\",\n        \"currentGasLimit\": \"0x0\",\n        \"currentNumber\": \"0\",\n        \"currentTimestamp\": \"0\",\n    }\n\n    if fork.header_base_fee_required(0, 0):\n        env[\"currentBaseFee\"] = \"7\"\n\n    if fork.header_prev_randao_required(0, 0):\n        env[\"currentRandom\"] = \"0\"\n\n    if fork.header_withdrawals_required(0, 0):\n        env[\"withdrawals\"] = []\n\n    _, result = self.evaluate(alloc, [], env, fork)\n    state_root = result.get(\"stateRoot\")\n    if state_root is None or not isinstance(state_root, str):\n        raise Exception(\"Unable to calculate state root\")\n    return bytes.fromhex(state_root[2:])\n
"},{"location":"library/pytest_plugins/test_filler/#evm_transition_tool.transition_tool.TransitionTool.calc_withdrawals_root","title":"calc_withdrawals_root(withdrawals, fork)","text":"

Calculate the state root for the given alloc.

Source code in src/evm_transition_tool/transition_tool.py
def calc_withdrawals_root(self, withdrawals: Any, fork: Fork) -> bytes:\n\"\"\"\n    Calculate the state root for the given `alloc`.\n    \"\"\"\n    if type(withdrawals) is list and len(withdrawals) == 0:\n        # Optimize returning the empty root immediately\n        return bytes.fromhex(\n            \"56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\"\n        )\n\n    env: Dict[str, Any] = {\n        \"currentCoinbase\": \"0x0000000000000000000000000000000000000000\",\n        \"currentDifficulty\": \"0x0\",\n        \"currentGasLimit\": \"0x0\",\n        \"currentNumber\": \"0\",\n        \"currentTimestamp\": \"0\",\n        \"withdrawals\": withdrawals,\n    }\n\n    if fork.header_base_fee_required(0, 0):\n        env[\"currentBaseFee\"] = \"7\"\n\n    if fork.header_prev_randao_required(0, 0):\n        env[\"currentRandom\"] = \"0\"\n\n    if fork.header_excess_data_gas_required(0, 0):\n        env[\"currentExcessDataGas\"] = \"0\"\n\n    _, result = self.evaluate({}, [], env, fork)\n    withdrawals_root = result.get(\"withdrawalsRoot\")\n    if withdrawals_root is None:\n        raise Exception(\n            \"Unable to calculate withdrawals root: no value returned from transition tool\"\n        )\n    if type(withdrawals_root) is not str:\n        raise Exception(\n            \"Unable to calculate withdrawals root: \"\n            + \"incorrect type returned from transition tool: \"\n            + f\"{withdrawals_root}\"\n        )\n    return bytes.fromhex(withdrawals_root[2:])\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.pytest_addoption","title":"pytest_addoption(parser)","text":"

Adds command-line options to pytest.

Source code in src/pytest_plugins/test_filler/test_filler.py
def pytest_addoption(parser):\n\"\"\"\n    Adds command-line options to pytest.\n    \"\"\"\n    evm_group = parser.getgroup(\"evm\", \"Arguments defining evm executable behavior\")\n    evm_group.addoption(\n        \"--evm-bin\",\n        action=\"store\",\n        dest=\"evm_bin\",\n        type=Path,\n        default=None,\n        help=(\n            \"Path to an evm executable that provides `t8n`. \" \"Default: First 'evm' entry in PATH\"\n        ),\n    )\n    evm_group.addoption(\n        \"--traces\",\n        action=\"store_true\",\n        dest=\"evm_collect_traces\",\n        default=None,\n        help=\"Collect traces of the execution information from the \" + \"transition tool\",\n    )\n\n    solc_group = parser.getgroup(\"solc\", \"Arguments defining the solc executable\")\n    solc_group.addoption(\n        \"--solc-bin\",\n        action=\"store\",\n        dest=\"solc_bin\",\n        default=None,\n        help=(\n            \"Path to a solc executable (for Yul source compilation). \"\n            \"Default: First 'solc' entry in PATH\"\n        ),\n    )\n\n    test_group = parser.getgroup(\"tests\", \"Arguments defining filler location and output\")\n    test_group.addoption(\n        \"--filler-path\",\n        action=\"store\",\n        dest=\"filler_path\",\n        default=\"./tests/\",\n        help=\"Path to filler directives\",\n    )\n    test_group.addoption(\n        \"--output\",\n        action=\"store\",\n        dest=\"output\",\n        default=\"./fixtures/\",\n        help=\"Directory to store the generated test fixtures. Can be deleted.\",\n    )\n    test_group.addoption(\n        \"--flat-output\",\n        action=\"store_true\",\n        dest=\"flat_output\",\n        default=False,\n        help=\"Output each test case in the directory without the folder structure.\",\n    )\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.StateTest","title":"StateTest dataclass","text":"

Bases: BaseTest

Filler type that tests transactions over the period of a single block.

Source code in src/ethereum_test_tools/spec/state_test.py
@dataclass(kw_only=True)\nclass StateTest(BaseTest):\n\"\"\"\n    Filler type that tests transactions over the period of a single block.\n    \"\"\"\n\n    env: Environment\n    pre: Mapping[str, Account]\n    post: Mapping[str, Account]\n    txs: List[Transaction]\n    engine_api_error_code: Optional[EngineAPIError] = None\n    tag: str = \"\"\n\n    @classmethod\n    def pytest_parameter_name(cls) -> str:\n\"\"\"\n        Returns the parameter name used to identify this filler in a test.\n        \"\"\"\n        return \"state_test\"\n\n    def make_genesis(\n        self,\n        t8n: TransitionTool,\n        fork: Fork,\n    ) -> Tuple[bytes, FixtureHeader]:\n\"\"\"\n        Create a genesis block from the state test definition.\n        \"\"\"\n        env = self.env.set_fork_requirements(fork)\n\n        genesis = FixtureHeader(\n            parent_hash=EmptyHash,\n            ommers_hash=EmptyOmmersRoot,\n            coinbase=ZeroAddress,\n            state_root=t8n.calc_state_root(\n                to_json(self.pre),\n                fork,\n            ),\n            transactions_root=EmptyTrieRoot,\n            receipt_root=EmptyTrieRoot,\n            bloom=EmptyBloom,\n            difficulty=0x20000 if env.difficulty is None else env.difficulty,\n            number=env.number - 1,\n            gas_limit=env.gas_limit,\n            gas_used=0,\n            timestamp=0,\n            extra_data=bytes([0]),\n            mix_digest=EmptyHash,\n            nonce=EmptyNonce,\n            base_fee=env.base_fee,\n            data_gas_used=env.data_gas_used,\n            excess_data_gas=env.excess_data_gas,\n            withdrawals_root=t8n.calc_withdrawals_root(env.withdrawals, fork)\n            if env.withdrawals is not None\n            else None,\n        )\n\n        genesis_rlp, genesis.hash = genesis.build(\n            txs=[],\n            ommers=[],\n            withdrawals=env.withdrawals,\n        )\n\n        return genesis_rlp, genesis\n\n    def make_blocks(\n        self,\n        t8n: TransitionTool,\n        genesis: FixtureHeader,\n        fork: Fork,\n        chain_id=1,\n        eips: Optional[List[int]] = None,\n    ) -> Tuple[List[FixtureBlock], bytes, Dict[str, Any]]:\n\"\"\"\n        Create a block from the state test definition.\n        Performs checks against the expected behavior of the test.\n        Raises exception on invalid test behavior.\n        \"\"\"\n        env = self.env.apply_new_parent(genesis)\n        env = env.set_fork_requirements(fork)\n\n        txs = [tx.with_signature_and_sender() for tx in self.txs] if self.txs is not None else []\n\n        alloc, result = t8n.evaluate(\n            alloc=to_json(self.pre),\n            txs=to_json(txs),\n            env=to_json(env),\n            fork=fork,\n            chain_id=chain_id,\n            reward=fork.get_reward(env.number, env.timestamp),\n            eips=eips,\n        )\n\n        rejected_txs = verify_transactions(txs, result)\n        if len(rejected_txs) > 0:\n            raise Exception(\n                \"one or more transactions in `StateTest` are \"\n                + \"intrinsically invalid, which are not allowed. \"\n                + \"Use `BlockchainTest` to verify rejection of blocks \"\n                + \"that include invalid transactions.\"\n            )\n\n        try:\n            verify_post_alloc(self.post, alloc)\n        except Exception as e:\n            print_traces(traces=t8n.get_traces())\n            raise e\n\n        header = FixtureHeader.from_dict(\n            result\n            | {\n                \"parentHash\": genesis.hash,\n                \"miner\": env.coinbase,\n                \"transactionsRoot\": result.get(\"txRoot\"),\n                \"difficulty\": str_or_none(env.difficulty, result.get(\"currentDifficulty\")),\n                \"number\": str(env.number),\n                \"gasLimit\": str(env.gas_limit),\n                \"timestamp\": str(env.timestamp),\n                \"extraData\": \"0x00\",\n                \"sha3Uncles\": \"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\n                \"mixHash\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n                \"nonce\": \"0x0000000000000000\",\n                \"baseFeePerGas\": result.get(\"currentBaseFee\"),\n                \"excessDataGas\": result.get(\"currentExcessDataGas\"),\n            }\n        )\n\n        block, header.hash = header.build(\n            txs=txs,\n            ommers=[],\n            withdrawals=env.withdrawals,\n        )\n\n        new_payload = FixtureEngineNewPayload.from_fixture_header(\n            fork=fork,\n            header=header,\n            transactions=txs,\n            withdrawals=env.withdrawals,\n            error_code=self.engine_api_error_code,\n        )\n\n        return (\n            [\n                FixtureBlock(\n                    rlp=block,\n                    new_payload=new_payload,\n                    block_header=header,\n                    txs=txs,\n                    ommers=[],\n                    withdrawals=env.withdrawals,\n                )\n            ],\n            header.hash,\n            alloc,\n        )\n
"},{"location":"library/pytest_plugins/test_filler/#ethereum_test_tools.spec.state_test.StateTest.pytest_parameter_name","title":"pytest_parameter_name() classmethod","text":"

Returns the parameter name used to identify this filler in a test.

Source code in src/ethereum_test_tools/spec/state_test.py
@classmethod\ndef pytest_parameter_name(cls) -> str:\n\"\"\"\n    Returns the parameter name used to identify this filler in a test.\n    \"\"\"\n    return \"state_test\"\n
"},{"location":"library/pytest_plugins/test_filler/#ethereum_test_tools.spec.state_test.StateTest.make_genesis","title":"make_genesis(t8n, fork)","text":"

Create a genesis block from the state test definition.

Source code in src/ethereum_test_tools/spec/state_test.py
def make_genesis(\n    self,\n    t8n: TransitionTool,\n    fork: Fork,\n) -> Tuple[bytes, FixtureHeader]:\n\"\"\"\n    Create a genesis block from the state test definition.\n    \"\"\"\n    env = self.env.set_fork_requirements(fork)\n\n    genesis = FixtureHeader(\n        parent_hash=EmptyHash,\n        ommers_hash=EmptyOmmersRoot,\n        coinbase=ZeroAddress,\n        state_root=t8n.calc_state_root(\n            to_json(self.pre),\n            fork,\n        ),\n        transactions_root=EmptyTrieRoot,\n        receipt_root=EmptyTrieRoot,\n        bloom=EmptyBloom,\n        difficulty=0x20000 if env.difficulty is None else env.difficulty,\n        number=env.number - 1,\n        gas_limit=env.gas_limit,\n        gas_used=0,\n        timestamp=0,\n        extra_data=bytes([0]),\n        mix_digest=EmptyHash,\n        nonce=EmptyNonce,\n        base_fee=env.base_fee,\n        data_gas_used=env.data_gas_used,\n        excess_data_gas=env.excess_data_gas,\n        withdrawals_root=t8n.calc_withdrawals_root(env.withdrawals, fork)\n        if env.withdrawals is not None\n        else None,\n    )\n\n    genesis_rlp, genesis.hash = genesis.build(\n        txs=[],\n        ommers=[],\n        withdrawals=env.withdrawals,\n    )\n\n    return genesis_rlp, genesis\n
"},{"location":"library/pytest_plugins/test_filler/#ethereum_test_tools.spec.state_test.StateTest.make_blocks","title":"make_blocks(t8n, genesis, fork, chain_id=1, eips=None)","text":"

Create a block from the state test definition. Performs checks against the expected behavior of the test. Raises exception on invalid test behavior.

Source code in src/ethereum_test_tools/spec/state_test.py
def make_blocks(\n    self,\n    t8n: TransitionTool,\n    genesis: FixtureHeader,\n    fork: Fork,\n    chain_id=1,\n    eips: Optional[List[int]] = None,\n) -> Tuple[List[FixtureBlock], bytes, Dict[str, Any]]:\n\"\"\"\n    Create a block from the state test definition.\n    Performs checks against the expected behavior of the test.\n    Raises exception on invalid test behavior.\n    \"\"\"\n    env = self.env.apply_new_parent(genesis)\n    env = env.set_fork_requirements(fork)\n\n    txs = [tx.with_signature_and_sender() for tx in self.txs] if self.txs is not None else []\n\n    alloc, result = t8n.evaluate(\n        alloc=to_json(self.pre),\n        txs=to_json(txs),\n        env=to_json(env),\n        fork=fork,\n        chain_id=chain_id,\n        reward=fork.get_reward(env.number, env.timestamp),\n        eips=eips,\n    )\n\n    rejected_txs = verify_transactions(txs, result)\n    if len(rejected_txs) > 0:\n        raise Exception(\n            \"one or more transactions in `StateTest` are \"\n            + \"intrinsically invalid, which are not allowed. \"\n            + \"Use `BlockchainTest` to verify rejection of blocks \"\n            + \"that include invalid transactions.\"\n        )\n\n    try:\n        verify_post_alloc(self.post, alloc)\n    except Exception as e:\n        print_traces(traces=t8n.get_traces())\n        raise e\n\n    header = FixtureHeader.from_dict(\n        result\n        | {\n            \"parentHash\": genesis.hash,\n            \"miner\": env.coinbase,\n            \"transactionsRoot\": result.get(\"txRoot\"),\n            \"difficulty\": str_or_none(env.difficulty, result.get(\"currentDifficulty\")),\n            \"number\": str(env.number),\n            \"gasLimit\": str(env.gas_limit),\n            \"timestamp\": str(env.timestamp),\n            \"extraData\": \"0x00\",\n            \"sha3Uncles\": \"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\n            \"mixHash\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n            \"nonce\": \"0x0000000000000000\",\n            \"baseFeePerGas\": result.get(\"currentBaseFee\"),\n            \"excessDataGas\": result.get(\"currentExcessDataGas\"),\n        }\n    )\n\n    block, header.hash = header.build(\n        txs=txs,\n        ommers=[],\n        withdrawals=env.withdrawals,\n    )\n\n    new_payload = FixtureEngineNewPayload.from_fixture_header(\n        fork=fork,\n        header=header,\n        transactions=txs,\n        withdrawals=env.withdrawals,\n        error_code=self.engine_api_error_code,\n    )\n\n    return (\n        [\n            FixtureBlock(\n                rlp=block,\n                new_payload=new_payload,\n                block_header=header,\n                txs=txs,\n                ommers=[],\n                withdrawals=env.withdrawals,\n            )\n        ],\n        header.hash,\n        alloc,\n    )\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.Yul","title":"Yul","text":"

Bases: Code

Yul compiler. Compiles Yul source code into bytecode.

Source code in src/ethereum_test_tools/code/yul.py
class Yul(Code):\n\"\"\"\n    Yul compiler.\n    Compiles Yul source code into bytecode.\n    \"\"\"\n\n    source: str\n    compiled: Optional[bytes] = None\n\n    def __init__(\n        self,\n        source: str,\n        fork: Optional[Fork] = None,\n        binary: Optional[Path | str] = None,\n    ):\n        self.source = source\n        self.evm_version = get_evm_version_from_fork(fork)\n        if binary is None:\n            which_path = which(\"solc\")\n            if which_path is not None:\n                binary = Path(which_path)\n        if binary is None or not Path(binary).exists():\n            raise Exception(\n\"\"\"`solc` binary executable not found, please refer to\n                https://docs.soliditylang.org/en/latest/installing-solidity.html\n                for help downloading and installing `solc`\"\"\"\n            )\n        self.binary = Path(binary)\n\n    def assemble(self) -> bytes:\n\"\"\"\n        Assembles using `solc --assemble`.\n        \"\"\"\n        if not self.compiled:\n            solc_args: Tuple[Union[Path, str], ...] = ()\n            if self.evm_version:\n                solc_args = (\n                    self.binary,\n                    \"--evm-version\",\n                    self.evm_version,\n                    *DEFAULT_SOLC_ARGS,\n                )\n            else:\n                solc_args = (self.binary, *DEFAULT_SOLC_ARGS)\n            result = run(\n                solc_args,\n                input=str.encode(self.source),\n                stdout=PIPE,\n                stderr=PIPE,\n            )\n\n            if result.returncode != 0:\n                stderr_lines = result.stderr.decode().split(\"\\n\")\n                stderr_message = \"\\n\".join(line.strip() for line in stderr_lines)\n                raise Exception(f\"failed to compile yul source:\\n{stderr_message[7:]}\")\n\n            lines = result.stdout.decode().split(\"\\n\")\n\n            hex_str = lines[lines.index(\"Binary representation:\") + 1]\n\n            self.compiled = bytes.fromhex(hex_str)\n        return self.compiled\n\n    def version(self) -> str:\n\"\"\"\n        Return solc's version string\n        \"\"\"\n        result = run(\n            [self.binary, \"--version\"],\n            stdout=PIPE,\n            stderr=PIPE,\n        )\n        solc_output = result.stdout.decode().split(\"\\n\")\n        version_pattern = r\"0\\.\\d+\\.\\d+\\+\\S+\"\n        solc_version_string = None\n        for line in solc_output:\n            match = re.search(version_pattern, line)\n            if match:\n                solc_version_string = match.group(0)\n                break\n        if not solc_version_string:\n            warnings.warn(\"Unable to determine solc version.\")\n            solc_version_string = \"unknown\"\n        return solc_version_string\n
"},{"location":"library/pytest_plugins/test_filler/#ethereum_test_tools.code.yul.Yul.assemble","title":"assemble()","text":"

Assembles using solc --assemble.

Source code in src/ethereum_test_tools/code/yul.py
def assemble(self) -> bytes:\n\"\"\"\n    Assembles using `solc --assemble`.\n    \"\"\"\n    if not self.compiled:\n        solc_args: Tuple[Union[Path, str], ...] = ()\n        if self.evm_version:\n            solc_args = (\n                self.binary,\n                \"--evm-version\",\n                self.evm_version,\n                *DEFAULT_SOLC_ARGS,\n            )\n        else:\n            solc_args = (self.binary, *DEFAULT_SOLC_ARGS)\n        result = run(\n            solc_args,\n            input=str.encode(self.source),\n            stdout=PIPE,\n            stderr=PIPE,\n        )\n\n        if result.returncode != 0:\n            stderr_lines = result.stderr.decode().split(\"\\n\")\n            stderr_message = \"\\n\".join(line.strip() for line in stderr_lines)\n            raise Exception(f\"failed to compile yul source:\\n{stderr_message[7:]}\")\n\n        lines = result.stdout.decode().split(\"\\n\")\n\n        hex_str = lines[lines.index(\"Binary representation:\") + 1]\n\n        self.compiled = bytes.fromhex(hex_str)\n    return self.compiled\n
"},{"location":"library/pytest_plugins/test_filler/#ethereum_test_tools.code.yul.Yul.version","title":"version()","text":"

Return solc's version string

Source code in src/ethereum_test_tools/code/yul.py
def version(self) -> str:\n\"\"\"\n    Return solc's version string\n    \"\"\"\n    result = run(\n        [self.binary, \"--version\"],\n        stdout=PIPE,\n        stderr=PIPE,\n    )\n    solc_output = result.stdout.decode().split(\"\\n\")\n    version_pattern = r\"0\\.\\d+\\.\\d+\\+\\S+\"\n    solc_version_string = None\n    for line in solc_output:\n        match = re.search(version_pattern, line)\n        if match:\n            solc_version_string = match.group(0)\n            break\n    if not solc_version_string:\n        warnings.warn(\"Unable to determine solc version.\")\n        solc_version_string = \"unknown\"\n    return solc_version_string\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.BaseTest","title":"BaseTest","text":"

Represents a base Ethereum test which must return a genesis and a blockchain.

Source code in src/ethereum_test_tools/spec/base_test.py
class BaseTest:\n\"\"\"\n    Represents a base Ethereum test which must return a genesis and a\n    blockchain.\n    \"\"\"\n\n    pre: Mapping[str, Account]\n    tag: str = \"\"\n\n    @abstractmethod\n    def make_genesis(\n        self,\n        t8n: TransitionTool,\n        fork: Fork,\n    ) -> Tuple[bytes, FixtureHeader]:\n\"\"\"\n        Create a genesis block from the test definition.\n        \"\"\"\n        pass\n\n    @abstractmethod\n    def make_blocks(\n        self,\n        t8n: TransitionTool,\n        genesis: FixtureHeader,\n        fork: Fork,\n        chain_id: int = 1,\n        eips: Optional[List[int]] = None,\n    ) -> Tuple[List[FixtureBlock], bytes, Dict[str, Any]]:\n\"\"\"\n        Generate the blockchain that must be executed sequentially during test.\n        \"\"\"\n        pass\n\n    @classmethod\n    @abstractmethod\n    def pytest_parameter_name(cls) -> str:\n\"\"\"\n        Must return the name of the parameter used in pytest to select this\n        spec type as filler for the test.\n        \"\"\"\n        pass\n
"},{"location":"library/pytest_plugins/test_filler/#ethereum_test_tools.spec.base_test.BaseTest.make_genesis","title":"make_genesis(t8n, fork) abstractmethod","text":"

Create a genesis block from the test definition.

Source code in src/ethereum_test_tools/spec/base_test.py
@abstractmethod\ndef make_genesis(\n    self,\n    t8n: TransitionTool,\n    fork: Fork,\n) -> Tuple[bytes, FixtureHeader]:\n\"\"\"\n    Create a genesis block from the test definition.\n    \"\"\"\n    pass\n
"},{"location":"library/pytest_plugins/test_filler/#ethereum_test_tools.spec.base_test.BaseTest.make_blocks","title":"make_blocks(t8n, genesis, fork, chain_id=1, eips=None) abstractmethod","text":"

Generate the blockchain that must be executed sequentially during test.

Source code in src/ethereum_test_tools/spec/base_test.py
@abstractmethod\ndef make_blocks(\n    self,\n    t8n: TransitionTool,\n    genesis: FixtureHeader,\n    fork: Fork,\n    chain_id: int = 1,\n    eips: Optional[List[int]] = None,\n) -> Tuple[List[FixtureBlock], bytes, Dict[str, Any]]:\n\"\"\"\n    Generate the blockchain that must be executed sequentially during test.\n    \"\"\"\n    pass\n
"},{"location":"library/pytest_plugins/test_filler/#ethereum_test_tools.spec.base_test.BaseTest.pytest_parameter_name","title":"pytest_parameter_name() classmethod abstractmethod","text":"

Must return the name of the parameter used in pytest to select this spec type as filler for the test.

Source code in src/ethereum_test_tools/spec/base_test.py
@classmethod\n@abstractmethod\ndef pytest_parameter_name(cls) -> str:\n\"\"\"\n    Must return the name of the parameter used in pytest to select this\n    spec type as filler for the test.\n    \"\"\"\n    pass\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.pytest_configure","title":"pytest_configure(config)","text":"

Register the plugin's custom markers and process command-line options.

Custom marker registration: https://docs.pytest.org/en/7.1.x/how-to/writing_plugins.html#registering-custom-markers

Source code in src/pytest_plugins/test_filler/test_filler.py
@pytest.hookimpl(tryfirst=True)\ndef pytest_configure(config):\n\"\"\"\n    Register the plugin's custom markers and process command-line options.\n\n    Custom marker registration:\n    https://docs.pytest.org/en/7.1.x/how-to/writing_plugins.html#registering-custom-markers\n    \"\"\"\n    config.addinivalue_line(\n        \"markers\",\n        \"state_test: a test case that implement a single state transition test.\",\n    )\n    config.addinivalue_line(\n        \"markers\",\n        \"blockchain_test: a test case that implements a block transition test.\",\n    )\n    config.addinivalue_line(\n        \"markers\",\n        \"yul_test: a test case that compiles Yul code.\",\n    )\n    config.addinivalue_line(\n        \"markers\",\n        \"compile_yul_with(fork): Always compile Yul source using the corresponding evm version.\",\n    )\n    if config.option.collectonly:\n        return\n    # Instantiate the transition tool here to check that the binary path/trace option is valid.\n    # This ensures we only raise an error once, if appropriate, instead of for every test.\n    TransitionTool.from_binary_path(\n        binary_path=config.getoption(\"evm_bin\"), trace=config.getoption(\"evm_collect_traces\")\n    )\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.EIPSpecTestItem","title":"EIPSpecTestItem","text":"

Bases: Item

Custom pytest test item to test EIP spec versions.

Source code in src/pytest_plugins/spec_version_checker/spec_version_checker.py
class EIPSpecTestItem(Item):\n\"\"\"\n    Custom pytest test item to test EIP spec versions.\n    \"\"\"\n\n    def __init__(self, name, parent, module):\n        super().__init__(name, parent)\n        self.module = module\n\n    @classmethod\n    def from_parent(cls, parent, module):\n\"\"\"\n        Public constructor to define new tests.\n        https://docs.pytest.org/en/latest/reference/reference.html#pytest.nodes.Node.from_parent\n        \"\"\"\n        return super().from_parent(parent=parent, name=\"test_eip_spec_version\", module=module)\n\n    def runtest(self):\n\"\"\"\n        Define the test to execute for this item.\n        \"\"\"\n        test_eip_spec_version(self.module)\n\n    def reportinfo(self):\n\"\"\"\n        Get location information for this test item to use test reports.\n        \"\"\"\n        return \"spec_version_checker\", 0, f\"{self.name}\"\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.spec_version_checker.spec_version_checker.EIPSpecTestItem.from_parent","title":"from_parent(parent, module) classmethod","text":"

Public constructor to define new tests. https://docs.pytest.org/en/latest/reference/reference.html#pytest.nodes.Node.from_parent

Source code in src/pytest_plugins/spec_version_checker/spec_version_checker.py
@classmethod\ndef from_parent(cls, parent, module):\n\"\"\"\n    Public constructor to define new tests.\n    https://docs.pytest.org/en/latest/reference/reference.html#pytest.nodes.Node.from_parent\n    \"\"\"\n    return super().from_parent(parent=parent, name=\"test_eip_spec_version\", module=module)\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.spec_version_checker.spec_version_checker.EIPSpecTestItem.runtest","title":"runtest()","text":"

Define the test to execute for this item.

Source code in src/pytest_plugins/spec_version_checker/spec_version_checker.py
def runtest(self):\n\"\"\"\n    Define the test to execute for this item.\n    \"\"\"\n    test_eip_spec_version(self.module)\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.spec_version_checker.spec_version_checker.EIPSpecTestItem.reportinfo","title":"reportinfo()","text":"

Get location information for this test item to use test reports.

Source code in src/pytest_plugins/spec_version_checker/spec_version_checker.py
def reportinfo(self):\n\"\"\"\n    Get location information for this test item to use test reports.\n    \"\"\"\n    return \"spec_version_checker\", 0, f\"{self.name}\"\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.pytest_report_header","title":"pytest_report_header(config, start_path)","text":"

Add lines to pytest's console output header

Source code in src/pytest_plugins/test_filler/test_filler.py
@pytest.hookimpl(trylast=True)\ndef pytest_report_header(config, start_path):\n\"\"\"Add lines to pytest's console output header\"\"\"\n    if config.option.collectonly:\n        return\n    binary_path = config.getoption(\"evm_bin\")\n    t8n = TransitionTool.from_binary_path(binary_path=binary_path)\n    solc_version_string = Yul(\"\", binary=config.getoption(\"solc_bin\")).version()\n    return [f\"{t8n.version()}, solc version {solc_version_string}\"]\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.evm_bin","title":"evm_bin(request)","text":"

Returns the configured evm tool binary path.

Source code in src/pytest_plugins/test_filler/test_filler.py
@pytest.fixture(autouse=True, scope=\"session\")\ndef evm_bin(request) -> Path:\n\"\"\"\n    Returns the configured evm tool binary path.\n    \"\"\"\n    return request.config.getoption(\"evm_bin\")\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.solc_bin","title":"solc_bin(request)","text":"

Returns the configured solc binary path.

Source code in src/pytest_plugins/test_filler/test_filler.py
@pytest.fixture(autouse=True, scope=\"session\")\ndef solc_bin(request):\n\"\"\"\n    Returns the configured solc binary path.\n    \"\"\"\n    return request.config.getoption(\"solc_bin\")\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.t8n","title":"t8n(request, evm_bin)","text":"

Returns the configured transition tool.

Source code in src/pytest_plugins/test_filler/test_filler.py
@pytest.fixture(autouse=True, scope=\"session\")\ndef t8n(request, evm_bin: Path) -> TransitionTool:\n\"\"\"\n    Returns the configured transition tool.\n    \"\"\"\n    return TransitionTool.from_binary_path(\n        binary_path=evm_bin, trace=request.config.getoption(\"evm_collect_traces\")\n    )\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.strip_test_prefix","title":"strip_test_prefix(name)","text":"

Removes the test prefix from a test case name.

Source code in src/pytest_plugins/test_filler/test_filler.py
def strip_test_prefix(name: str) -> str:\n\"\"\"\n    Removes the test prefix from a test case name.\n    \"\"\"\n    TEST_PREFIX = \"test_\"\n    if name.startswith(TEST_PREFIX):\n        return name[len(TEST_PREFIX) :]\n    return name\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.FixtureCollector","title":"FixtureCollector","text":"

Collects all fixtures generated by the test cases.

Source code in src/pytest_plugins/test_filler/test_filler.py
class FixtureCollector:\n\"\"\"\n    Collects all fixtures generated by the test cases.\n    \"\"\"\n\n    all_fixtures: Dict[str, List[Tuple[str, Any]]]\n    output_dir: str\n    flat_output: bool\n\n    def __init__(self, output_dir: str, flat_output: bool) -> None:\n        self.all_fixtures = {}\n        self.output_dir = output_dir\n        self.flat_output = flat_output\n\n    def add_fixture(self, item, fixture: Fixture) -> None:\n\"\"\"\n        Adds a fixture to the list of fixtures of a given test case.\n        \"\"\"\n\n        def get_module_dir(item) -> str:\n\"\"\"\n            Returns the directory of the test case module.\n            \"\"\"\n            dirname = os.path.dirname(item.path)\n            basename, _ = os.path.splitext(item.path)\n            basename = strip_test_prefix(os.path.basename(basename))\n            module_path_no_ext = os.path.join(dirname, basename)\n            module_dir = os.path.relpath(\n                module_path_no_ext,\n                item.funcargs[\"filler_path\"],\n            )\n            return module_dir\n\n        module_dir = (\n            strip_test_prefix(item.originalname)\n            if self.flat_output\n            else os.path.join(\n                get_module_dir(item),\n                strip_test_prefix(item.originalname),\n            )\n        )\n        if module_dir not in self.all_fixtures:\n            self.all_fixtures[module_dir] = []\n        m = re.match(r\".*?\\[(.*)\\]\", item.name)\n        if not m:\n            raise Exception(\"Could not parse test name: \" + item.name)\n        name = m.group(1)\n        if fixture.name:\n            name += \"-\" + fixture.name\n        jsonFixture = json.loads(json.dumps(fixture, cls=JSONEncoder))\n        self.all_fixtures[module_dir].append((name, jsonFixture))\n\n    def dump_fixtures(self) -> None:\n\"\"\"\n        Dumps all collected fixtures to their respective files.\n        \"\"\"\n        os.makedirs(self.output_dir, exist_ok=True)\n        for module_file, fixtures in self.all_fixtures.items():\n            output_json = {}\n            for index, name_fixture in enumerate(fixtures):\n                name, fixture = name_fixture\n                name = str(index).zfill(3) + \"-\" + name\n                output_json[name] = fixture\n            file_path = os.path.join(self.output_dir, module_file + \".json\")\n            if not self.flat_output:\n                os.makedirs(os.path.dirname(file_path), exist_ok=True)\n            with open(file_path, \"w\") as f:\n                json.dump(output_json, f, indent=4)\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.FixtureCollector.add_fixture","title":"add_fixture(item, fixture)","text":"

Adds a fixture to the list of fixtures of a given test case.

Source code in src/pytest_plugins/test_filler/test_filler.py
def add_fixture(self, item, fixture: Fixture) -> None:\n\"\"\"\n    Adds a fixture to the list of fixtures of a given test case.\n    \"\"\"\n\n    def get_module_dir(item) -> str:\n\"\"\"\n        Returns the directory of the test case module.\n        \"\"\"\n        dirname = os.path.dirname(item.path)\n        basename, _ = os.path.splitext(item.path)\n        basename = strip_test_prefix(os.path.basename(basename))\n        module_path_no_ext = os.path.join(dirname, basename)\n        module_dir = os.path.relpath(\n            module_path_no_ext,\n            item.funcargs[\"filler_path\"],\n        )\n        return module_dir\n\n    module_dir = (\n        strip_test_prefix(item.originalname)\n        if self.flat_output\n        else os.path.join(\n            get_module_dir(item),\n            strip_test_prefix(item.originalname),\n        )\n    )\n    if module_dir not in self.all_fixtures:\n        self.all_fixtures[module_dir] = []\n    m = re.match(r\".*?\\[(.*)\\]\", item.name)\n    if not m:\n        raise Exception(\"Could not parse test name: \" + item.name)\n    name = m.group(1)\n    if fixture.name:\n        name += \"-\" + fixture.name\n    jsonFixture = json.loads(json.dumps(fixture, cls=JSONEncoder))\n    self.all_fixtures[module_dir].append((name, jsonFixture))\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.FixtureCollector.dump_fixtures","title":"dump_fixtures()","text":"

Dumps all collected fixtures to their respective files.

Source code in src/pytest_plugins/test_filler/test_filler.py
def dump_fixtures(self) -> None:\n\"\"\"\n    Dumps all collected fixtures to their respective files.\n    \"\"\"\n    os.makedirs(self.output_dir, exist_ok=True)\n    for module_file, fixtures in self.all_fixtures.items():\n        output_json = {}\n        for index, name_fixture in enumerate(fixtures):\n            name, fixture = name_fixture\n            name = str(index).zfill(3) + \"-\" + name\n            output_json[name] = fixture\n        file_path = os.path.join(self.output_dir, module_file + \".json\")\n        if not self.flat_output:\n            os.makedirs(os.path.dirname(file_path), exist_ok=True)\n        with open(file_path, \"w\") as f:\n            json.dump(output_json, f, indent=4)\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.fixture_collector","title":"fixture_collector(request)","text":"

Returns the configured fixture collector instance used for all tests in one test module.

Source code in src/pytest_plugins/test_filler/test_filler.py
@pytest.fixture(scope=\"module\")\ndef fixture_collector(request):\n\"\"\"\n    Returns the configured fixture collector instance used for all tests\n    in one test module.\n    \"\"\"\n    fixture_collector = FixtureCollector(\n        output_dir=request.config.getoption(\"output\"),\n        flat_output=request.config.getoption(\"flat_output\"),\n    )\n    yield fixture_collector\n    fixture_collector.dump_fixtures()\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.engine","title":"engine()","text":"

Returns the sealEngine used in the generated test fixtures.

Source code in src/pytest_plugins/test_filler/test_filler.py
@pytest.fixture(autouse=True, scope=\"session\")\ndef engine():\n\"\"\"\n    Returns the sealEngine used in the generated test fixtures.\n    \"\"\"\n    return \"NoProof\"\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.filler_path","title":"filler_path(request)","text":"

Returns the directory containing the tests to execute.

Source code in src/pytest_plugins/test_filler/test_filler.py
@pytest.fixture(autouse=True, scope=\"session\")\ndef filler_path(request):\n\"\"\"\n    Returns the directory containing the tests to execute.\n    \"\"\"\n    return request.config.getoption(\"filler_path\")\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.eips","title":"eips()","text":"

A fixture specifying that, by default, no EIPs should be activated for tests.

This fixture (function) may be redefined in test filler modules in order to overwrite this default and return a list of integers specifying which EIPs should be activated for the tests in scope.

Source code in src/pytest_plugins/test_filler/test_filler.py
@pytest.fixture(autouse=True)\ndef eips():\n\"\"\"\n    A fixture specifying that, by default, no EIPs should be activated for\n    tests.\n\n    This fixture (function) may be redefined in test filler modules in order\n    to overwrite this default and return a list of integers specifying which\n    EIPs should be activated for the tests in scope.\n    \"\"\"\n    return []\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.yul","title":"yul(fork, request)","text":"

A fixture that allows contract code to be defined with Yul code.

This fixture defines a class that wraps the ::ethereum_test_tools.Yul class so that upon instantiation within the test case, it provides the test case's current fork parameter. The forks is then available for use in solc's arguments for the Yul code compilation.

Test cases can override the default value by specifying a fixed version with the @pytest.mark.compile_yul_with(FORK) marker.

Source code in src/pytest_plugins/test_filler/test_filler.py
@pytest.fixture\ndef yul(fork: Fork, request):\n\"\"\"\n    A fixture that allows contract code to be defined with Yul code.\n\n    This fixture defines a class that wraps the ::ethereum_test_tools.Yul\n    class so that upon instantiation within the test case, it provides the\n    test case's current fork parameter. The forks is then available for use\n    in solc's arguments for the Yul code compilation.\n\n    Test cases can override the default value by specifying a fixed version\n    with the @pytest.mark.compile_yul_with(FORK) marker.\n    \"\"\"\n    marker = request.node.get_closest_marker(\"compile_yul_with\")\n    if marker:\n        if not marker.args[0]:\n            pytest.fail(\n                f\"{request.node.name}: Expected one argument in 'compile_yul_with' marker.\"\n            )\n        fork = request.config.fork_map[marker.args[0]]\n\n    class YulWrapper(Yul):\n        def __init__(self, *args, **kwargs):\n            super(YulWrapper, self).__init__(*args, **kwargs, fork=fork)\n\n    return YulWrapper\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.state_test","title":"state_test(request, t8n, fork, engine, reference_spec, eips, fixture_collector)","text":"

Fixture used to instantiate an auto-fillable StateTest object from within a test function.

Every test that defines a StateTest filler must explicitly specify this fixture in its function arguments and set the StateTestWrapper's spec property.

Implementation detail: It must be scoped on test function level to avoid leakage between tests.

Source code in src/pytest_plugins/test_filler/test_filler.py
@pytest.fixture(scope=\"function\")\ndef state_test(\n    request, t8n, fork, engine, reference_spec, eips, fixture_collector\n) -> StateTestFiller:\n\"\"\"\n    Fixture used to instantiate an auto-fillable StateTest object from within\n    a test function.\n\n    Every test that defines a StateTest filler must explicitly specify this\n    fixture in its function arguments and set the StateTestWrapper's spec\n    property.\n\n    Implementation detail: It must be scoped on test function level to avoid\n    leakage between tests.\n    \"\"\"\n\n    class StateTestWrapper(StateTest):\n        def __init__(self, *args, **kwargs):\n            super(StateTestWrapper, self).__init__(*args, **kwargs)\n            fixture_collector.add_fixture(\n                request.node,\n                fill_test(\n                    t8n,\n                    self,\n                    fork,\n                    engine,\n                    reference_spec,\n                    eips=eips,\n                ),\n            )\n\n    return StateTestWrapper\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.blockchain_test","title":"blockchain_test(request, t8n, fork, engine, reference_spec, eips, fixture_collector)","text":"

Fixture used to define an auto-fillable BlockchainTest analogous to the state_test fixture for StateTests. See the state_test fixture docstring for details.

Source code in src/pytest_plugins/test_filler/test_filler.py
@pytest.fixture(scope=\"function\")\ndef blockchain_test(\n    request, t8n, fork, engine, reference_spec, eips, fixture_collector\n) -> BlockchainTestFiller:\n\"\"\"\n    Fixture used to define an auto-fillable BlockchainTest analogous to the\n    state_test fixture for StateTests.\n    See the state_test fixture docstring for details.\n    \"\"\"\n\n    class BlockchainTestWrapper(BlockchainTest):\n        def __init__(self, *args, **kwargs):\n            super(BlockchainTestWrapper, self).__init__(*args, **kwargs)\n            fixture_collector.add_fixture(\n                request.node,\n                fill_test(\n                    t8n,\n                    self,\n                    fork,\n                    engine,\n                    reference_spec,\n                    eips=eips,\n                ),\n            )\n\n    return BlockchainTestWrapper\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.pytest_collection_modifyitems","title":"pytest_collection_modifyitems(items, config)","text":"

A pytest hook called during collection, after all items have been collected.

Here we dynamically apply \"state_test\" or \"blockchain_test\" markers to a test if the test function uses the corresponding fixture.

Source code in src/pytest_plugins/test_filler/test_filler.py
def pytest_collection_modifyitems(items, config):\n\"\"\"\n    A pytest hook called during collection, after all items have been\n    collected.\n\n    Here we dynamically apply \"state_test\" or \"blockchain_test\" markers\n    to a test if the test function uses the corresponding fixture.\n    \"\"\"\n    for item in items:\n        if isinstance(item, EIPSpecTestItem):\n            continue\n        if \"state_test\" in item.fixturenames:\n            marker = pytest.mark.state_test()\n            item.add_marker(marker)\n        elif \"blockchain_test\" in item.fixturenames:\n            marker = pytest.mark.blockchain_test()\n            item.add_marker(marker)\n        if \"yul\" in item.fixturenames:\n            marker = pytest.mark.yul_test()\n            item.add_marker(marker)\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.pytest_make_parametrize_id","title":"pytest_make_parametrize_id(config, val, argname)","text":"

Pytest hook called when generating test ids. We use this to generate more readable test ids for the generated tests.

Source code in src/pytest_plugins/test_filler/test_filler.py
def pytest_make_parametrize_id(config, val, argname):\n\"\"\"\n    Pytest hook called when generating test ids. We use this to generate\n    more readable test ids for the generated tests.\n    \"\"\"\n    return f\"{argname}={val}\"\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.pytest_runtest_call","title":"pytest_runtest_call(item)","text":"

Pytest hook called in the context of test execution.

Source code in src/pytest_plugins/test_filler/test_filler.py
def pytest_runtest_call(item):\n\"\"\"\n    Pytest hook called in the context of test execution.\n    \"\"\"\n    if isinstance(item, EIPSpecTestItem):\n        return\n\n    class InvalidFiller(Exception):\n        def __init__(self, message):\n            super().__init__(message)\n\n    if \"state_test\" in item.fixturenames and \"blockchain_test\" in item.fixturenames:\n        raise InvalidFiller(\n            \"A filler should only implement either a state test or \" \"a blockchain test; not both.\"\n        )\n\n    # Check that the test defines either test type as parameter.\n    if not any([i for i in item.funcargs if i in SPEC_TYPES_PARAMETERS]):\n        pytest.fail(\n            \"Test must define either one of the following parameters to \"\n            + \"properly generate a test: \"\n            + \", \".join(SPEC_TYPES_PARAMETERS)\n        )\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.Fixture","title":"Fixture dataclass","text":"

Cross-client compatible Ethereum test fixture.

Source code in src/ethereum_test_tools/common/types.py
@dataclass(kw_only=True)\nclass Fixture:\n\"\"\"\n    Cross-client compatible Ethereum test fixture.\n    \"\"\"\n\n    blocks: List[FixtureBlock]\n    genesis: FixtureHeader\n    genesis_rlp: bytes\n    head: bytes\n    fork: str\n    pre_state: Mapping[str, Account]\n    post_state: Optional[Mapping[str, Account]]\n    seal_engine: str\n    info: Dict[str, str] = field(default_factory=dict)\n    name: str = \"\"\n\n    _json: Dict[str, Any] | None = None\n\n    def __post_init__(self):\n\"\"\"\n        Post init hook to convert to JSON after instantiation.\n        \"\"\"\n        self._json = to_json(self)\n\n    def fill_info(\n        self,\n        t8n: TransitionTool,\n        ref_spec: ReferenceSpec | None,\n    ):\n\"\"\"\n        Fill the info field for this fixture\n        \"\"\"\n        self.info[\"filling-transition-tool\"] = t8n.version()\n        if ref_spec is not None:\n            ref_spec.write_info(self.info)\n
"},{"location":"library/pytest_plugins/test_filler/#ethereum_test_tools.common.types.Fixture.__post_init__","title":"__post_init__()","text":"

Post init hook to convert to JSON after instantiation.

Source code in src/ethereum_test_tools/common/types.py
def __post_init__(self):\n\"\"\"\n    Post init hook to convert to JSON after instantiation.\n    \"\"\"\n    self._json = to_json(self)\n
"},{"location":"library/pytest_plugins/test_filler/#ethereum_test_tools.common.types.Fixture.fill_info","title":"fill_info(t8n, ref_spec)","text":"

Fill the info field for this fixture

Source code in src/ethereum_test_tools/common/types.py
def fill_info(\n    self,\n    t8n: TransitionTool,\n    ref_spec: ReferenceSpec | None,\n):\n\"\"\"\n    Fill the info field for this fixture\n    \"\"\"\n    self.info[\"filling-transition-tool\"] = t8n.version()\n    if ref_spec is not None:\n        ref_spec.write_info(self.info)\n
"},{"location":"library/pytest_plugins/test_filler/#pytest_plugins.test_filler.test_filler.JSONEncoder","title":"JSONEncoder","text":"

Bases: json.JSONEncoder

Custom JSON encoder for ethereum_test types.

Source code in src/ethereum_test_tools/common/types.py
class JSONEncoder(json.JSONEncoder):\n\"\"\"\n    Custom JSON encoder for `ethereum_test` types.\n    \"\"\"\n\n    def default(self, obj: JSONEncoderSupportedType) -> Any:\n\"\"\"\n        Enocdes types defined in this module using basic python facilities.\n        \"\"\"\n        if isinstance(obj, Storage):\n            return obj.to_dict()\n        elif isinstance(obj, Account):\n            account = {\n                \"nonce\": hex_or_none(obj.nonce, hex(0)),\n                \"balance\": hex_or_none(obj.balance, hex(0)),\n                \"code\": code_or_none(obj.code, \"0x\"),\n                \"storage\": to_json_or_none(obj.storage, {}),\n            }\n            return even_padding(account, excluded=[\"storage\"])\n        elif isinstance(obj, AccessList):\n            access_list: Dict[str, Any] = {\n                \"address\": address_or_none(obj.address, \"0x\" + ZeroAddress.hex())\n            }\n            if obj.storage_keys is not None:\n                access_list[\"storageKeys\"] = [hex_or_none(k) for k in obj.storage_keys]\n            return access_list\n        elif isinstance(obj, Transaction):\n            assert obj.ty is not None, \"Transaction type must be set\"\n            tx: Dict[str, Any] = {\n                \"type\": hex(obj.ty),\n                \"chainId\": hex(obj.chain_id),\n                \"nonce\": hex(obj.nonce),\n                \"gasPrice\": hex_or_none(obj.gas_price),\n                \"maxPriorityFeePerGas\": hex_or_none(obj.max_priority_fee_per_gas),\n                \"maxFeePerGas\": hex_or_none(obj.max_fee_per_gas),\n                \"gas\": hex(obj.gas_limit),\n                \"value\": hex(obj.value),\n                \"input\": code_to_hex(obj.data),\n                \"to\": address_or_none(obj.to),\n                \"accessList\": obj.access_list,\n                \"secretKey\": obj.secret_key,\n                \"maxFeePerDataGas\": hex_or_none(obj.max_fee_per_data_gas),\n                \"sender\": address_or_none(obj.sender),\n            }\n\n            if obj.blob_versioned_hashes is not None:\n                tx[\"blobVersionedHashes\"] = [hash_string(h) for h in obj.blob_versioned_hashes]\n\n            if obj.secret_key is None:\n                assert obj.signature is not None\n                assert len(obj.signature) == 3\n                tx[\"v\"] = hex(obj.signature[0])\n                tx[\"r\"] = hex(obj.signature[1])\n                tx[\"s\"] = hex(obj.signature[2])\n            else:\n                tx[\"v\"] = \"\"\n                tx[\"r\"] = \"\"\n                tx[\"s\"] = \"\"\n\n            return {k: v for (k, v) in tx.items() if v is not None}\n        elif isinstance(obj, Withdrawal):\n            withdrawal = {\n                \"index\": hex(obj.index),\n                \"validatorIndex\": hex(obj.validator),\n                \"address\": obj.address,\n                \"amount\": hex(obj.amount),\n            }\n            return withdrawal\n        elif isinstance(obj, Environment):\n            env: Dict[str, Any] = {\n                \"currentCoinbase\": address_or_none(obj.coinbase, \"0x\" + ZeroAddress.hex()),\n                \"currentGasLimit\": str_or_none(obj.gas_limit),\n                \"currentNumber\": str_or_none(obj.number),\n                \"currentTimestamp\": str_or_none(obj.timestamp),\n                \"currentRandom\": str_or_none(obj.prev_randao),\n                \"currentDifficulty\": str_or_none(obj.difficulty),\n                \"parentDifficulty\": str_or_none(obj.parent_difficulty),\n                \"parentBaseFee\": str_or_none(obj.parent_base_fee),\n                \"parentGasUsed\": str_or_none(obj.parent_gas_used),\n                \"parentGasLimit\": str_or_none(obj.parent_gas_limit),\n                \"parentTimestamp\": str_or_none(obj.parent_timestamp),\n                \"blockHashes\": {str(k): hex_or_none(v) for (k, v) in obj.block_hashes.items()},\n                \"ommers\": [],\n                \"withdrawals\": to_json_or_none(obj.withdrawals),\n                \"parentUncleHash\": hash_string(obj.parent_ommers_hash),\n                \"currentBaseFee\": str_or_none(obj.base_fee),\n                \"parentDataGasUsed\": str_or_none(obj.parent_data_gas_used),\n                \"parentExcessDataGas\": str_or_none(obj.parent_excess_data_gas),\n                \"currentExcessDataGas\": str_or_none(obj.excess_data_gas),\n                \"currentDataGasUsed\": str_or_none(obj.data_gas_used),\n            }\n\n            return {k: v for (k, v) in env.items() if v is not None}\n        elif isinstance(obj, FixtureHeader):\n            header = {\n                \"parentHash\": hex_or_none(obj.parent_hash),\n                \"uncleHash\": hex_or_none(obj.ommers_hash),\n                \"coinbase\": hex_or_none(obj.coinbase),\n                \"stateRoot\": hex_or_none(obj.state_root),\n                \"transactionsTrie\": hex_or_none(obj.transactions_root),\n                \"receiptTrie\": hex_or_none(obj.receipt_root),\n                \"bloom\": hex_or_none(obj.bloom),\n                \"difficulty\": hex(obj.difficulty),\n                \"number\": hex(obj.number),\n                \"gasLimit\": hex(obj.gas_limit),\n                \"gasUsed\": hex(obj.gas_used),\n                \"timestamp\": hex(obj.timestamp),\n                \"extraData\": hex_or_none(obj.extra_data),\n                \"mixHash\": hex_or_none(obj.mix_digest),\n                \"nonce\": hex_or_none(obj.nonce),\n            }\n            if obj.base_fee is not None:\n                header[\"baseFeePerGas\"] = hex(obj.base_fee)\n            if obj.hash is not None:\n                header[\"hash\"] = \"0x\" + obj.hash.hex()\n            if obj.withdrawals_root is not None:\n                header[\"withdrawalsRoot\"] = hex_or_none(obj.withdrawals_root)\n            if obj.data_gas_used is not None:\n                header[\"dataGasUsed\"] = hex(obj.data_gas_used)\n            if obj.excess_data_gas is not None:\n                header[\"excessDataGas\"] = hex(obj.excess_data_gas)\n            return even_padding(\n                header,\n                excluded=[\n                    \"parentHash\",\n                    \"uncleHash\",\n                    \"stateRoot\",\n                    \"coinbase\",\n                    \"transactionsTrie\",\n                    \"receiptTrie\",\n                    \"bloom\",\n                    \"nonce\",\n                    \"mixHash\",\n                    \"hash\",\n                    \"withdrawalsRoot\",\n                    \"extraData\",\n                ],\n            )\n        elif isinstance(obj, FixtureTransaction):\n            json_tx = to_json(obj.tx)\n            if json_tx[\"v\"] == \"\":\n                del json_tx[\"v\"]\n                del json_tx[\"r\"]\n                del json_tx[\"s\"]\n            if \"input\" in json_tx:\n                json_tx[\"data\"] = json_tx[\"input\"]\n                del json_tx[\"input\"]\n            if \"gas\" in json_tx:\n                json_tx[\"gasLimit\"] = json_tx[\"gas\"]\n                del json_tx[\"gas\"]\n            if \"to\" not in json_tx:\n                json_tx[\"to\"] = \"\"\n            return even_padding(\n                json_tx,\n                excluded=[\"data\", \"to\", \"accessList\"],\n            )\n        elif isinstance(obj, FixtureExecutionPayload):\n            payload: Dict[str, Any] = {\n                \"parentHash\": hex_or_none(obj.header.parent_hash),\n                \"feeRecipient\": hex_or_none(obj.header.coinbase),\n                \"stateRoot\": hex_or_none(obj.header.state_root),\n                \"receiptsRoot\": hex_or_none(obj.header.receipt_root),\n                \"logsBloom\": hex_or_none(obj.header.bloom),\n                \"prevRandao\": hex_or_none(obj.header.mix_digest),\n                \"blockNumber\": hex(obj.header.number),\n                \"gasLimit\": hex(obj.header.gas_limit),\n                \"gasUsed\": hex(obj.header.gas_used),\n                \"timestamp\": hex(obj.header.timestamp),\n                \"extraData\": hex_or_none(obj.header.extra_data),\n            }\n            if obj.header.base_fee is not None:\n                payload[\"baseFeePerGas\"] = hex(obj.header.base_fee)\n            if obj.header.hash is not None:\n                payload[\"blockHash\"] = \"0x\" + obj.header.hash.hex()\n\n            if obj.transactions is not None:\n                payload[\"transactions\"] = [\n                    hex_or_none(tx.serialized_bytes()) for tx in obj.transactions\n                ]\n            if obj.withdrawals is not None:\n                payload[\"withdrawals\"] = obj.withdrawals\n\n            if obj.header.data_gas_used is not None:\n                payload[\"dataGasUsed\"] = hex(obj.header.data_gas_used)\n            if obj.header.excess_data_gas is not None:\n                payload[\"excessDataGas\"] = hex(obj.header.excess_data_gas)\n\n            return payload\n        elif isinstance(obj, FixtureEngineNewPayload):\n            new_payload: Dict[str, Any] = {\n                \"payload\": to_json(obj.payload),\n                \"version\": str_or_none(obj.version),\n            }\n            if obj.blob_versioned_hashes is not None:\n                new_payload[\"blobVersionedHashes\"] = [\n                    \"0x\" + hash_to_bytes(h).hex() for h in obj.blob_versioned_hashes\n                ]\n            if obj.error_code is not None:\n                new_payload[\"errorCode\"] = str(int(obj.error_code))\n            return new_payload\n\n        elif isinstance(obj, FixtureBlock):\n            b: Dict[str, Any] = {\"rlp\": hex_or_none(obj.rlp)}\n            if obj.block_header is not None:\n                b[\"blockHeader\"] = json.loads(json.dumps(obj.block_header, cls=JSONEncoder))\n            if obj.new_payload is not None:\n                b[\"engineNewPayload\"] = to_json_or_none(obj.new_payload)\n            if obj.expected_exception is not None:\n                b[\"expectException\"] = obj.expected_exception\n            if obj.block_number is not None:\n                b[\"blocknumber\"] = str(obj.block_number)\n            if obj.txs is not None:\n                b[\"transactions\"] = [FixtureTransaction(tx=tx) for tx in obj.txs]\n            if obj.ommers is not None:\n                b[\"uncleHeaders\"] = obj.ommers\n            if obj.withdrawals is not None:\n                b[\"withdrawals\"] = [\n                    even_padding(to_json(wd), excluded=[\"address\"]) for wd in obj.withdrawals\n                ]\n            return b\n\n        elif isinstance(obj, Fixture):\n            if obj._json is not None:\n                obj._json[\"_info\"] = obj.info\n                return obj._json\n\n            f = {\n                \"_info\": obj.info,\n                \"blocks\": [json.loads(json.dumps(b, cls=JSONEncoder)) for b in obj.blocks],\n                \"genesisBlockHeader\": self.default(obj.genesis),\n                \"genesisRLP\": hex_or_none(obj.genesis_rlp),\n                \"lastblockhash\": hex_or_none(obj.head),\n                \"network\": obj.fork,\n                \"pre\": json.loads(json.dumps(obj.pre_state, cls=JSONEncoder)),\n                \"postState\": json.loads(json.dumps(obj.post_state, cls=JSONEncoder)),\n                \"sealEngine\": obj.seal_engine,\n            }\n            if f[\"postState\"] is None:\n                del f[\"postState\"]\n            return f\n        else:\n            return super().default(obj)\n
"},{"location":"library/pytest_plugins/test_filler/#ethereum_test_tools.common.types.JSONEncoder.default","title":"default(obj)","text":"

Enocdes types defined in this module using basic python facilities.

Source code in src/ethereum_test_tools/common/types.py
def default(self, obj: JSONEncoderSupportedType) -> Any:\n\"\"\"\n    Enocdes types defined in this module using basic python facilities.\n    \"\"\"\n    if isinstance(obj, Storage):\n        return obj.to_dict()\n    elif isinstance(obj, Account):\n        account = {\n            \"nonce\": hex_or_none(obj.nonce, hex(0)),\n            \"balance\": hex_or_none(obj.balance, hex(0)),\n            \"code\": code_or_none(obj.code, \"0x\"),\n            \"storage\": to_json_or_none(obj.storage, {}),\n        }\n        return even_padding(account, excluded=[\"storage\"])\n    elif isinstance(obj, AccessList):\n        access_list: Dict[str, Any] = {\n            \"address\": address_or_none(obj.address, \"0x\" + ZeroAddress.hex())\n        }\n        if obj.storage_keys is not None:\n            access_list[\"storageKeys\"] = [hex_or_none(k) for k in obj.storage_keys]\n        return access_list\n    elif isinstance(obj, Transaction):\n        assert obj.ty is not None, \"Transaction type must be set\"\n        tx: Dict[str, Any] = {\n            \"type\": hex(obj.ty),\n            \"chainId\": hex(obj.chain_id),\n            \"nonce\": hex(obj.nonce),\n            \"gasPrice\": hex_or_none(obj.gas_price),\n            \"maxPriorityFeePerGas\": hex_or_none(obj.max_priority_fee_per_gas),\n            \"maxFeePerGas\": hex_or_none(obj.max_fee_per_gas),\n            \"gas\": hex(obj.gas_limit),\n            \"value\": hex(obj.value),\n            \"input\": code_to_hex(obj.data),\n            \"to\": address_or_none(obj.to),\n            \"accessList\": obj.access_list,\n            \"secretKey\": obj.secret_key,\n            \"maxFeePerDataGas\": hex_or_none(obj.max_fee_per_data_gas),\n            \"sender\": address_or_none(obj.sender),\n        }\n\n        if obj.blob_versioned_hashes is not None:\n            tx[\"blobVersionedHashes\"] = [hash_string(h) for h in obj.blob_versioned_hashes]\n\n        if obj.secret_key is None:\n            assert obj.signature is not None\n            assert len(obj.signature) == 3\n            tx[\"v\"] = hex(obj.signature[0])\n            tx[\"r\"] = hex(obj.signature[1])\n            tx[\"s\"] = hex(obj.signature[2])\n        else:\n            tx[\"v\"] = \"\"\n            tx[\"r\"] = \"\"\n            tx[\"s\"] = \"\"\n\n        return {k: v for (k, v) in tx.items() if v is not None}\n    elif isinstance(obj, Withdrawal):\n        withdrawal = {\n            \"index\": hex(obj.index),\n            \"validatorIndex\": hex(obj.validator),\n            \"address\": obj.address,\n            \"amount\": hex(obj.amount),\n        }\n        return withdrawal\n    elif isinstance(obj, Environment):\n        env: Dict[str, Any] = {\n            \"currentCoinbase\": address_or_none(obj.coinbase, \"0x\" + ZeroAddress.hex()),\n            \"currentGasLimit\": str_or_none(obj.gas_limit),\n            \"currentNumber\": str_or_none(obj.number),\n            \"currentTimestamp\": str_or_none(obj.timestamp),\n            \"currentRandom\": str_or_none(obj.prev_randao),\n            \"currentDifficulty\": str_or_none(obj.difficulty),\n            \"parentDifficulty\": str_or_none(obj.parent_difficulty),\n            \"parentBaseFee\": str_or_none(obj.parent_base_fee),\n            \"parentGasUsed\": str_or_none(obj.parent_gas_used),\n            \"parentGasLimit\": str_or_none(obj.parent_gas_limit),\n            \"parentTimestamp\": str_or_none(obj.parent_timestamp),\n            \"blockHashes\": {str(k): hex_or_none(v) for (k, v) in obj.block_hashes.items()},\n            \"ommers\": [],\n            \"withdrawals\": to_json_or_none(obj.withdrawals),\n            \"parentUncleHash\": hash_string(obj.parent_ommers_hash),\n            \"currentBaseFee\": str_or_none(obj.base_fee),\n            \"parentDataGasUsed\": str_or_none(obj.parent_data_gas_used),\n            \"parentExcessDataGas\": str_or_none(obj.parent_excess_data_gas),\n            \"currentExcessDataGas\": str_or_none(obj.excess_data_gas),\n            \"currentDataGasUsed\": str_or_none(obj.data_gas_used),\n        }\n\n        return {k: v for (k, v) in env.items() if v is not None}\n    elif isinstance(obj, FixtureHeader):\n        header = {\n            \"parentHash\": hex_or_none(obj.parent_hash),\n            \"uncleHash\": hex_or_none(obj.ommers_hash),\n            \"coinbase\": hex_or_none(obj.coinbase),\n            \"stateRoot\": hex_or_none(obj.state_root),\n            \"transactionsTrie\": hex_or_none(obj.transactions_root),\n            \"receiptTrie\": hex_or_none(obj.receipt_root),\n            \"bloom\": hex_or_none(obj.bloom),\n            \"difficulty\": hex(obj.difficulty),\n            \"number\": hex(obj.number),\n            \"gasLimit\": hex(obj.gas_limit),\n            \"gasUsed\": hex(obj.gas_used),\n            \"timestamp\": hex(obj.timestamp),\n            \"extraData\": hex_or_none(obj.extra_data),\n            \"mixHash\": hex_or_none(obj.mix_digest),\n            \"nonce\": hex_or_none(obj.nonce),\n        }\n        if obj.base_fee is not None:\n            header[\"baseFeePerGas\"] = hex(obj.base_fee)\n        if obj.hash is not None:\n            header[\"hash\"] = \"0x\" + obj.hash.hex()\n        if obj.withdrawals_root is not None:\n            header[\"withdrawalsRoot\"] = hex_or_none(obj.withdrawals_root)\n        if obj.data_gas_used is not None:\n            header[\"dataGasUsed\"] = hex(obj.data_gas_used)\n        if obj.excess_data_gas is not None:\n            header[\"excessDataGas\"] = hex(obj.excess_data_gas)\n        return even_padding(\n            header,\n            excluded=[\n                \"parentHash\",\n                \"uncleHash\",\n                \"stateRoot\",\n                \"coinbase\",\n                \"transactionsTrie\",\n                \"receiptTrie\",\n                \"bloom\",\n                \"nonce\",\n                \"mixHash\",\n                \"hash\",\n                \"withdrawalsRoot\",\n                \"extraData\",\n            ],\n        )\n    elif isinstance(obj, FixtureTransaction):\n        json_tx = to_json(obj.tx)\n        if json_tx[\"v\"] == \"\":\n            del json_tx[\"v\"]\n            del json_tx[\"r\"]\n            del json_tx[\"s\"]\n        if \"input\" in json_tx:\n            json_tx[\"data\"] = json_tx[\"input\"]\n            del json_tx[\"input\"]\n        if \"gas\" in json_tx:\n            json_tx[\"gasLimit\"] = json_tx[\"gas\"]\n            del json_tx[\"gas\"]\n        if \"to\" not in json_tx:\n            json_tx[\"to\"] = \"\"\n        return even_padding(\n            json_tx,\n            excluded=[\"data\", \"to\", \"accessList\"],\n        )\n    elif isinstance(obj, FixtureExecutionPayload):\n        payload: Dict[str, Any] = {\n            \"parentHash\": hex_or_none(obj.header.parent_hash),\n            \"feeRecipient\": hex_or_none(obj.header.coinbase),\n            \"stateRoot\": hex_or_none(obj.header.state_root),\n            \"receiptsRoot\": hex_or_none(obj.header.receipt_root),\n            \"logsBloom\": hex_or_none(obj.header.bloom),\n            \"prevRandao\": hex_or_none(obj.header.mix_digest),\n            \"blockNumber\": hex(obj.header.number),\n            \"gasLimit\": hex(obj.header.gas_limit),\n            \"gasUsed\": hex(obj.header.gas_used),\n            \"timestamp\": hex(obj.header.timestamp),\n            \"extraData\": hex_or_none(obj.header.extra_data),\n        }\n        if obj.header.base_fee is not None:\n            payload[\"baseFeePerGas\"] = hex(obj.header.base_fee)\n        if obj.header.hash is not None:\n            payload[\"blockHash\"] = \"0x\" + obj.header.hash.hex()\n\n        if obj.transactions is not None:\n            payload[\"transactions\"] = [\n                hex_or_none(tx.serialized_bytes()) for tx in obj.transactions\n            ]\n        if obj.withdrawals is not None:\n            payload[\"withdrawals\"] = obj.withdrawals\n\n        if obj.header.data_gas_used is not None:\n            payload[\"dataGasUsed\"] = hex(obj.header.data_gas_used)\n        if obj.header.excess_data_gas is not None:\n            payload[\"excessDataGas\"] = hex(obj.header.excess_data_gas)\n\n        return payload\n    elif isinstance(obj, FixtureEngineNewPayload):\n        new_payload: Dict[str, Any] = {\n            \"payload\": to_json(obj.payload),\n            \"version\": str_or_none(obj.version),\n        }\n        if obj.blob_versioned_hashes is not None:\n            new_payload[\"blobVersionedHashes\"] = [\n                \"0x\" + hash_to_bytes(h).hex() for h in obj.blob_versioned_hashes\n            ]\n        if obj.error_code is not None:\n            new_payload[\"errorCode\"] = str(int(obj.error_code))\n        return new_payload\n\n    elif isinstance(obj, FixtureBlock):\n        b: Dict[str, Any] = {\"rlp\": hex_or_none(obj.rlp)}\n        if obj.block_header is not None:\n            b[\"blockHeader\"] = json.loads(json.dumps(obj.block_header, cls=JSONEncoder))\n        if obj.new_payload is not None:\n            b[\"engineNewPayload\"] = to_json_or_none(obj.new_payload)\n        if obj.expected_exception is not None:\n            b[\"expectException\"] = obj.expected_exception\n        if obj.block_number is not None:\n            b[\"blocknumber\"] = str(obj.block_number)\n        if obj.txs is not None:\n            b[\"transactions\"] = [FixtureTransaction(tx=tx) for tx in obj.txs]\n        if obj.ommers is not None:\n            b[\"uncleHeaders\"] = obj.ommers\n        if obj.withdrawals is not None:\n            b[\"withdrawals\"] = [\n                even_padding(to_json(wd), excluded=[\"address\"]) for wd in obj.withdrawals\n            ]\n        return b\n\n    elif isinstance(obj, Fixture):\n        if obj._json is not None:\n            obj._json[\"_info\"] = obj.info\n            return obj._json\n\n        f = {\n            \"_info\": obj.info,\n            \"blocks\": [json.loads(json.dumps(b, cls=JSONEncoder)) for b in obj.blocks],\n            \"genesisBlockHeader\": self.default(obj.genesis),\n            \"genesisRLP\": hex_or_none(obj.genesis_rlp),\n            \"lastblockhash\": hex_or_none(obj.head),\n            \"network\": obj.fork,\n            \"pre\": json.loads(json.dumps(obj.pre_state, cls=JSONEncoder)),\n            \"postState\": json.loads(json.dumps(obj.post_state, cls=JSONEncoder)),\n            \"sealEngine\": obj.seal_engine,\n        }\n        if f[\"postState\"] is None:\n            del f[\"postState\"]\n        return f\n    else:\n        return super().default(obj)\n
"},{"location":"tests/","title":"Test case reference","text":"

Documentation for tests.

Generate fixtures for these test cases for all forks deployed to mainnet with:

fill -v tests\n

Generate fixtures for these test cases for Cancun with:

Cancun only:

fill -v tests --fork=Cancun --evm-bin=/path/to/evm-tool-dev-version\n
For all forks up to and including Cancun:
fill -v tests --until=Cancun --evm-bin=/path/to/evm-tool-dev-version\n

Cross-client test cases organized by fork. Each directory underneath tests/ contains test cases corresponding to the fork in which the functionality-under-test was introduced.

"},{"location":"tests/berlin/","title":"Berlin","text":"

Documentation for tests/berlin.

Generate fixtures for these test cases with:

fill -v tests/berlin\n

Test cases for EVM functionality introduced in Berlin.

"},{"location":"tests/berlin/eip2930_access_list/","title":"EIP-2930 Access List","text":"

Documentation for tests/berlin/eip2930_access_list.

Generate fixtures for these test cases with:

fill -v tests/berlin/eip2930_access_list\n
Tests EIP-2930: Optional access lists

Test cases for EIP-2930: Optional access lists.

"},{"location":"tests/berlin/eip2930_access_list/test_acl/","title":"Test ACL","text":"

Documentation for tests/berlin/eip2930_access_list/test_acl.py.

Generate fixtures for these test cases with:

fill -v tests/berlin/eip2930_access_list/test_acl.py\n

Test ACL Transaction Source Code Examples

"},{"location":"tests/berlin/eip2930_access_list/test_acl/#tests.berlin.eip2930_access_list.test_acl.test_access_list","title":"test_access_list(state_test, fork)","text":"

Test type 1 transaction.

Source code in tests/berlin/eip2930_access_list/test_acl.py
@pytest.mark.valid_from(\"Berlin\")\n@pytest.mark.valid_until(\"London\")\ndef test_access_list(state_test: StateTestFiller, fork: Fork):\n\"\"\"\n    Test type 1 transaction.\n    \"\"\"\n    env = Environment()\n\n    pre = {\n        \"0x000000000000000000000000000000000000aaaa\": Account(\n            balance=0x03,\n            code=Op.PC + Op.SLOAD + Op.POP + Op.PC + Op.SLOAD,\n            nonce=1,\n        ),\n        \"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b\": Account(\n            balance=0x300000,\n            nonce=0,\n        ),\n    }\n\n    tx = Transaction(\n        ty=1,\n        chain_id=0x01,\n        nonce=0,\n        to=\"0x000000000000000000000000000000000000aaaa\",\n        value=1,\n        gas_limit=323328,\n        gas_price=7,\n        access_list=[\n            AccessList(\n                address=\"0x0000000000000000000000000000000000000000\",\n                storage_keys=[\n                    \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n                ],\n            )\n        ],\n        secret_key=\"0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8\",\n        protected=True,\n    )\n\n    post = {\n        \"0x000000000000000000000000000000000000aaaa\": Account(\n            code=\"0x5854505854\",\n            balance=4,\n            nonce=1,\n        ),\n        \"0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba\": Account(\n            balance=0x1BC16D674EC80000 if is_fork(fork, London) else 0x1BC16D674ECB26CE,\n        ),\n        \"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b\": Account(\n            balance=0x2CD931,\n            nonce=1,\n        ),\n    }\n    state_test(env=env, pre=pre, post=post, txs=[tx])\n
"},{"location":"tests/berlin/eip2930_access_list/test_acl/index/test_cases/","title":"Test ACL - Test Cases","text":"

Test cases generated from tests/berlin/eip2930_access_list/test_acl.py

Parametrized test cases generated from the test module tests/berlin/eip2930_access_list/test_acl.py:

test_access_list[fork=Berlin]\ntest_access_list[fork=London]\n

This output was extracted from the result of:

fill --collect-only -q --until Cancun tests/berlin/eip2930_access_list/test_acl.py\n
"},{"location":"tests/cancun/","title":"Cancun","text":"

Documentation for tests/cancun.

Generate fixtures for these test cases for Cancun with:

Cancun only:

fill -v tests/cancun --fork=Cancun --evm-bin=/path/to/evm-tool-dev-version\n
For all forks up to and including Cancun:
fill -v tests/cancun --until=Cancun --evm-bin=/path/to/evm-tool-dev-version\n

Test cases for EVM functionality introduced in Cancun.

"},{"location":"tests/cancun/eip4844_blobs/","title":"EIP-4844 Blobs","text":"

Documentation for tests/cancun/eip4844_blobs.

Generate fixtures for these test cases for Cancun with:

Cancun only:

fill -v tests/cancun/eip4844_blobs --fork=Cancun --evm-bin=/path/to/evm-tool-dev-version\n
For all forks up to and including Cancun:
fill -v tests/cancun/eip4844_blobs --until=Cancun --evm-bin=/path/to/evm-tool-dev-version\n

Cross-client EIP-4844 Tests

"},{"location":"tests/cancun/eip4844_blobs/point_evaluation_vectors/README_./","title":"KZG Point Evaluation Test Vectors","text":"

This directory contains test vectors for the KZG point evaluation algorithm, compiled from different sources.

Each file must contain a JSON list of objects, each with the following fields: - name: a string describing the test case - input: object containing commitment, proof, z and y - output: expected output of the evaluation, true, false or null.

The files are loaded and used throughout different test tests.

Current files and their sources: - go_kzg_4844_verify_kzg_proof.json: test vectors from the go-kzg-4844 repository.

"},{"location":"tests/cancun/eip4844_blobs/spec/","title":"Spec","text":"

Documentation for tests/cancun/eip4844_blobs/spec.py.

Defines EIP-4844 specification constants and functions.

"},{"location":"tests/cancun/eip4844_blobs/spec/#tests.cancun.eip4844_blobs.spec.Spec","title":"Spec dataclass","text":"

Parameters from the EIP-4844 specifications as defined at https://eips.ethereum.org/EIPS/eip-4844#parameters

If the parameter is not currently used within the tests, it is commented out.

Source code in tests/cancun/eip4844_blobs/spec.py
@dataclass(frozen=True)\nclass Spec:\n\"\"\"\n    Parameters from the EIP-4844 specifications as defined at\n    https://eips.ethereum.org/EIPS/eip-4844#parameters\n\n    If the parameter is not currently used within the tests, it is commented\n    out.\n    \"\"\"\n\n    BLOB_TX_TYPE = 0x03\n    FIELD_ELEMENTS_PER_BLOB = 4096\n    BLS_MODULUS = 0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001\n    BLOB_COMMITMENT_VERSION_KZG = 1\n    POINT_EVALUATION_PRECOMPILE_ADDRESS = 20\n    POINT_EVALUATION_PRECOMPILE_GAS = 50_000\n    MAX_DATA_GAS_PER_BLOCK = 786432\n    TARGET_DATA_GAS_PER_BLOCK = 393216\n    MIN_DATA_GASPRICE = 1\n    DATA_GASPRICE_UPDATE_FRACTION = 3338477\n    # MAX_VERSIONED_HASHES_LIST_SIZE = 2**24\n    # MAX_CALLDATA_SIZE = 2**24\n    # MAX_ACCESS_LIST_SIZE = 2**24\n    # MAX_ACCESS_LIST_STORAGE_KEYS = 2**24\n    # MAX_TX_WRAP_COMMITMENTS = 2**12\n    # LIMIT_BLOBS_PER_TX = 2**12\n    DATA_GAS_PER_BLOB = 2**17\n    HASH_OPCODE_BYTE = 0x49\n    HASH_GAS_COST = 3\n\n    @classmethod\n    def kzg_to_versioned_hash(\n        cls,\n        kzg_commitment: bytes | int,  # 48 bytes\n        blob_commitment_version_kzg: Optional[bytes | int] = None,\n    ) -> bytes:\n\"\"\"\n        Calculates the versioned hash for a given KZG commitment.\n        \"\"\"\n        if blob_commitment_version_kzg is None:\n            blob_commitment_version_kzg = cls.BLOB_COMMITMENT_VERSION_KZG\n        if isinstance(kzg_commitment, int):\n            kzg_commitment = kzg_commitment.to_bytes(48, \"big\")\n        if isinstance(blob_commitment_version_kzg, int):\n            blob_commitment_version_kzg = blob_commitment_version_kzg.to_bytes(1, \"big\")\n        return blob_commitment_version_kzg + sha256(kzg_commitment).digest()[1:]\n\n    @classmethod\n    def fake_exponential(cls, factor: int, numerator: int, denominator: int) -> int:\n\"\"\"\n        Used to calculate the data gas cost.\n        \"\"\"\n        i = 1\n        output = 0\n        numerator_accumulator = factor * denominator\n        while numerator_accumulator > 0:\n            output += numerator_accumulator\n            numerator_accumulator = (numerator_accumulator * numerator) // (denominator * i)\n            i += 1\n        return output // denominator\n\n    @classmethod\n    def calc_excess_data_gas(cls, parent: BlockHeaderDataGasFields) -> int:\n\"\"\"\n        Calculate the excess data gas for a block given the excess data gas\n        and data gas used from the parent block header.\n        \"\"\"\n        if parent.excess_data_gas + parent.data_gas_used < cls.TARGET_DATA_GAS_PER_BLOCK:\n            return 0\n        else:\n            return parent.excess_data_gas + parent.data_gas_used - cls.TARGET_DATA_GAS_PER_BLOCK\n\n    # Note: Currently unused.\n    # @classmethod\n    # def get_total_data_gas(cls, tx: Transaction) -> int:\n    #     \"\"\"\n    #     Calculate the total data gas for a transaction.\n    #     \"\"\"\n    #     if tx.blob_versioned_hashes is None:\n    #         return 0\n    #     return cls.DATA_GAS_PER_BLOB * len(tx.blob_versioned_hashes)\n\n    @classmethod\n    def get_data_gasprice(cls, *, excess_data_gas: int) -> int:\n\"\"\"\n        Calculate the data gas price from the excess.\n        \"\"\"\n        return cls.fake_exponential(\n            cls.MIN_DATA_GASPRICE,\n            excess_data_gas,\n            cls.DATA_GASPRICE_UPDATE_FRACTION,\n        )\n
"},{"location":"tests/cancun/eip4844_blobs/spec/#tests.cancun.eip4844_blobs.spec.SpecHelpers","title":"SpecHelpers dataclass","text":"

Define parameters and helper functions that are tightly coupled to the 4844 spec but not strictly part of it.

Source code in tests/cancun/eip4844_blobs/spec.py
@dataclass(frozen=True)\nclass SpecHelpers:\n\"\"\"\n    Define parameters and helper functions that are tightly coupled to the 4844\n    spec but not strictly part of it.\n    \"\"\"\n\n    BYTES_PER_FIELD_ELEMENT = 32\n\n    @classmethod\n    def max_blobs_per_block(cls) -> int:  # MAX_BLOBS_PER_BLOCK =\n\"\"\"\n        Returns the maximum number of blobs per block.\n        \"\"\"\n        return Spec.MAX_DATA_GAS_PER_BLOCK // Spec.DATA_GAS_PER_BLOB\n\n    @classmethod\n    def target_blobs_per_block(cls) -> int:\n\"\"\"\n        Returns the target number of blobs per block.\n        \"\"\"\n        return Spec.TARGET_DATA_GAS_PER_BLOCK // Spec.DATA_GAS_PER_BLOB\n\n    @classmethod\n    def calc_excess_data_gas_from_blob_count(\n        cls, parent_excess_data_gas: int, parent_blob_count: int\n    ) -> int:\n\"\"\"\n        Calculate the excess data gas for a block given the parent excess data gas\n        and the number of blobs in the block.\n        \"\"\"\n        parent_consumed_data_gas = parent_blob_count * Spec.DATA_GAS_PER_BLOB\n        return Spec.calc_excess_data_gas(\n            BlockHeaderDataGasFields(parent_excess_data_gas, parent_consumed_data_gas)\n        )\n\n    @classmethod\n    def get_min_excess_data_gas_for_data_gas_price(cls, data_gas_price: int) -> int:\n\"\"\"\n        Gets the minimum required excess data gas value to get a given data gas cost in a block\n        \"\"\"\n        current_excess_data_gas = 0\n        current_data_gas_price = 1\n        while current_data_gas_price < data_gas_price:\n            current_excess_data_gas += Spec.DATA_GAS_PER_BLOB\n            current_data_gas_price = Spec.get_data_gasprice(\n                excess_data_gas=current_excess_data_gas\n            )\n        return current_excess_data_gas\n\n    @classmethod\n    def get_min_excess_data_blobs_for_data_gas_price(cls, data_gas_price: int) -> int:\n\"\"\"\n        Gets the minimum required excess data blobs to get a given data gas cost in a block\n        \"\"\"\n        return (\n            cls.get_min_excess_data_gas_for_data_gas_price(data_gas_price)\n            // Spec.DATA_GAS_PER_BLOB\n        )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs/","title":"Test Blob Txs","text":"

Documentation for tests/cancun/eip4844_blobs/test_blob_txs.py.

Generate fixtures for these test cases for Cancun with:

Cancun only:

fill -v tests/cancun/eip4844_blobs/test_blob_txs.py --fork=Cancun --evm-bin=/path/to/evm-tool-dev-version\n
For all forks up to and including Cancun:
fill -v tests/cancun/eip4844_blobs/test_blob_txs.py --until=Cancun --evm-bin=/path/to/evm-tool-dev-version\n

Tests blob type transactions for EIP-4844: Shard Blob Transactions

Test blob type transactions for EIP-4844: Shard Blob Transactions.

Adding a new test

Add a function that is named test_<test_name> and takes at least the following arguments:

  • blockchain_test
  • pre
  • env
  • blocks

All other pytest.fixture fixtures can be parametrized to generate new combinations and test cases.

"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs/#tests.cancun.eip4844_blobs.test_blob_txs.Spec","title":"Spec dataclass","text":"

Parameters from the EIP-4844 specifications as defined at https://eips.ethereum.org/EIPS/eip-4844#parameters

If the parameter is not currently used within the tests, it is commented out.

Source code in tests/cancun/eip4844_blobs/spec.py
@dataclass(frozen=True)\nclass Spec:\n\"\"\"\n    Parameters from the EIP-4844 specifications as defined at\n    https://eips.ethereum.org/EIPS/eip-4844#parameters\n\n    If the parameter is not currently used within the tests, it is commented\n    out.\n    \"\"\"\n\n    BLOB_TX_TYPE = 0x03\n    FIELD_ELEMENTS_PER_BLOB = 4096\n    BLS_MODULUS = 0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001\n    BLOB_COMMITMENT_VERSION_KZG = 1\n    POINT_EVALUATION_PRECOMPILE_ADDRESS = 20\n    POINT_EVALUATION_PRECOMPILE_GAS = 50_000\n    MAX_DATA_GAS_PER_BLOCK = 786432\n    TARGET_DATA_GAS_PER_BLOCK = 393216\n    MIN_DATA_GASPRICE = 1\n    DATA_GASPRICE_UPDATE_FRACTION = 3338477\n    # MAX_VERSIONED_HASHES_LIST_SIZE = 2**24\n    # MAX_CALLDATA_SIZE = 2**24\n    # MAX_ACCESS_LIST_SIZE = 2**24\n    # MAX_ACCESS_LIST_STORAGE_KEYS = 2**24\n    # MAX_TX_WRAP_COMMITMENTS = 2**12\n    # LIMIT_BLOBS_PER_TX = 2**12\n    DATA_GAS_PER_BLOB = 2**17\n    HASH_OPCODE_BYTE = 0x49\n    HASH_GAS_COST = 3\n\n    @classmethod\n    def kzg_to_versioned_hash(\n        cls,\n        kzg_commitment: bytes | int,  # 48 bytes\n        blob_commitment_version_kzg: Optional[bytes | int] = None,\n    ) -> bytes:\n\"\"\"\n        Calculates the versioned hash for a given KZG commitment.\n        \"\"\"\n        if blob_commitment_version_kzg is None:\n            blob_commitment_version_kzg = cls.BLOB_COMMITMENT_VERSION_KZG\n        if isinstance(kzg_commitment, int):\n            kzg_commitment = kzg_commitment.to_bytes(48, \"big\")\n        if isinstance(blob_commitment_version_kzg, int):\n            blob_commitment_version_kzg = blob_commitment_version_kzg.to_bytes(1, \"big\")\n        return blob_commitment_version_kzg + sha256(kzg_commitment).digest()[1:]\n\n    @classmethod\n    def fake_exponential(cls, factor: int, numerator: int, denominator: int) -> int:\n\"\"\"\n        Used to calculate the data gas cost.\n        \"\"\"\n        i = 1\n        output = 0\n        numerator_accumulator = factor * denominator\n        while numerator_accumulator > 0:\n            output += numerator_accumulator\n            numerator_accumulator = (numerator_accumulator * numerator) // (denominator * i)\n            i += 1\n        return output // denominator\n\n    @classmethod\n    def calc_excess_data_gas(cls, parent: BlockHeaderDataGasFields) -> int:\n\"\"\"\n        Calculate the excess data gas for a block given the excess data gas\n        and data gas used from the parent block header.\n        \"\"\"\n        if parent.excess_data_gas + parent.data_gas_used < cls.TARGET_DATA_GAS_PER_BLOCK:\n            return 0\n        else:\n            return parent.excess_data_gas + parent.data_gas_used - cls.TARGET_DATA_GAS_PER_BLOCK\n\n    # Note: Currently unused.\n    # @classmethod\n    # def get_total_data_gas(cls, tx: Transaction) -> int:\n    #     \"\"\"\n    #     Calculate the total data gas for a transaction.\n    #     \"\"\"\n    #     if tx.blob_versioned_hashes is None:\n    #         return 0\n    #     return cls.DATA_GAS_PER_BLOB * len(tx.blob_versioned_hashes)\n\n    @classmethod\n    def get_data_gasprice(cls, *, excess_data_gas: int) -> int:\n\"\"\"\n        Calculate the data gas price from the excess.\n        \"\"\"\n        return cls.fake_exponential(\n            cls.MIN_DATA_GASPRICE,\n            excess_data_gas,\n            cls.DATA_GASPRICE_UPDATE_FRACTION,\n        )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs/#tests.cancun.eip4844_blobs.test_blob_txs.SpecHelpers","title":"SpecHelpers dataclass","text":"

Define parameters and helper functions that are tightly coupled to the 4844 spec but not strictly part of it.

Source code in tests/cancun/eip4844_blobs/spec.py
@dataclass(frozen=True)\nclass SpecHelpers:\n\"\"\"\n    Define parameters and helper functions that are tightly coupled to the 4844\n    spec but not strictly part of it.\n    \"\"\"\n\n    BYTES_PER_FIELD_ELEMENT = 32\n\n    @classmethod\n    def max_blobs_per_block(cls) -> int:  # MAX_BLOBS_PER_BLOCK =\n\"\"\"\n        Returns the maximum number of blobs per block.\n        \"\"\"\n        return Spec.MAX_DATA_GAS_PER_BLOCK // Spec.DATA_GAS_PER_BLOB\n\n    @classmethod\n    def target_blobs_per_block(cls) -> int:\n\"\"\"\n        Returns the target number of blobs per block.\n        \"\"\"\n        return Spec.TARGET_DATA_GAS_PER_BLOCK // Spec.DATA_GAS_PER_BLOB\n\n    @classmethod\n    def calc_excess_data_gas_from_blob_count(\n        cls, parent_excess_data_gas: int, parent_blob_count: int\n    ) -> int:\n\"\"\"\n        Calculate the excess data gas for a block given the parent excess data gas\n        and the number of blobs in the block.\n        \"\"\"\n        parent_consumed_data_gas = parent_blob_count * Spec.DATA_GAS_PER_BLOB\n        return Spec.calc_excess_data_gas(\n            BlockHeaderDataGasFields(parent_excess_data_gas, parent_consumed_data_gas)\n        )\n\n    @classmethod\n    def get_min_excess_data_gas_for_data_gas_price(cls, data_gas_price: int) -> int:\n\"\"\"\n        Gets the minimum required excess data gas value to get a given data gas cost in a block\n        \"\"\"\n        current_excess_data_gas = 0\n        current_data_gas_price = 1\n        while current_data_gas_price < data_gas_price:\n            current_excess_data_gas += Spec.DATA_GAS_PER_BLOB\n            current_data_gas_price = Spec.get_data_gasprice(\n                excess_data_gas=current_excess_data_gas\n            )\n        return current_excess_data_gas\n\n    @classmethod\n    def get_min_excess_data_blobs_for_data_gas_price(cls, data_gas_price: int) -> int:\n\"\"\"\n        Gets the minimum required excess data blobs to get a given data gas cost in a block\n        \"\"\"\n        return (\n            cls.get_min_excess_data_gas_for_data_gas_price(data_gas_price)\n            // Spec.DATA_GAS_PER_BLOB\n        )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs/#tests.cancun.eip4844_blobs.test_blob_txs.test_valid_blob_tx_combinations","title":"test_valid_blob_tx_combinations(blockchain_test, pre, env, blocks)","text":"

Test all valid blob combinations in a single block, assuming a given value of MAX_BLOBS_PER_BLOCK.

This assumes a block can include from 1 and up to MAX_BLOBS_PER_BLOCK transactions where all transactions contain at least 1 blob, and the sum of all blobs in a block is at most MAX_BLOBS_PER_BLOCK.

This test is parametrized with all valid blob transaction combinations for a given block, and therefore if value of MAX_BLOBS_PER_BLOCK changes, this test is automatically updated.

Source code in tests/cancun/eip4844_blobs/test_blob_txs.py
@pytest.mark.parametrize(\n    \"blobs_per_tx\",\n    all_valid_blob_combinations(),\n)\n@pytest.mark.valid_from(\"Cancun\")\ndef test_valid_blob_tx_combinations(\n    blockchain_test: BlockchainTestFiller,\n    pre: Dict,\n    env: Environment,\n    blocks: List[Block],\n):\n\"\"\"\n    Test all valid blob combinations in a single block, assuming a given value of\n    `MAX_BLOBS_PER_BLOCK`.\n\n    This assumes a block can include from 1 and up to `MAX_BLOBS_PER_BLOCK` transactions where all\n    transactions contain at least 1 blob, and the sum of all blobs in a block is at\n    most `MAX_BLOBS_PER_BLOCK`.\n\n    This test is parametrized with all valid blob transaction combinations for a given block, and\n    therefore if value of `MAX_BLOBS_PER_BLOCK` changes, this test is automatically updated.\n    \"\"\"\n    blockchain_test(\n        pre=pre,\n        post={},\n        blocks=blocks,\n        genesis_environment=env,\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs/#tests.cancun.eip4844_blobs.test_blob_txs.test_invalid_tx_max_fee_per_data_gas","title":"test_invalid_tx_max_fee_per_data_gas(blockchain_test, pre, env, blocks, parent_blobs, block_intermediate)","text":"

Reject blocks with invalid blob txs due to:

  • tx max_fee_per_data_gas is barely not enough
  • tx max_fee_per_data_gas is zero
Source code in tests/cancun/eip4844_blobs/test_blob_txs.py
@pytest.mark.parametrize(\n    \"parent_excess_blobs,parent_blobs,tx_max_fee_per_data_gas,tx_error\",\n    [\n        # tx max_data_gas_cost of the transaction is not enough\n        (\n            SpecHelpers.get_min_excess_data_blobs_for_data_gas_price(2) - 1,  # data gas price is 1\n            SpecHelpers.target_blobs_per_block() + 1,  # data gas cost increases to 2\n            1,  # tx max_data_gas_cost is 1\n            \"insufficient max fee per data gas\",\n        ),\n        # tx max_data_gas_cost of the transaction is zero, which is invalid\n        (\n            0,  # data gas price is 1\n            0,  # data gas cost stays put at 1\n            0,  # tx max_data_gas_cost is 0\n            \"invalid max fee per data gas\",\n        ),\n    ],\n    ids=[\"insufficient_max_fee_per_data_gas\", \"invalid_max_fee_per_data_gas\"],\n)\n@pytest.mark.valid_from(\"Cancun\")\ndef test_invalid_tx_max_fee_per_data_gas(\n    blockchain_test: BlockchainTestFiller,\n    pre: Dict,\n    env: Environment,\n    blocks: List[Block],\n    parent_blobs: int,\n    block_intermediate: Block,\n):\n\"\"\"\n    Reject blocks with invalid blob txs due to:\n\n    - tx max_fee_per_data_gas is barely not enough\n    - tx max_fee_per_data_gas is zero\n    \"\"\"\n    if parent_blobs:\n        pre[TestAddress2] = Account(balance=10**9)\n        blocks.insert(0, block_intermediate)\n        if env.excess_data_gas is not None:\n            env.excess_data_gas += Spec.TARGET_DATA_GAS_PER_BLOCK\n    blockchain_test(\n        pre=pre,\n        post={},\n        blocks=blocks,\n        genesis_environment=env,\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs/#tests.cancun.eip4844_blobs.test_blob_txs.test_invalid_normal_gas","title":"test_invalid_normal_gas(blockchain_test, pre, env, blocks)","text":"

Reject blocks with invalid blob txs due to:

  • Sufficient max fee per data gas, but insufficient max fee per gas
Source code in tests/cancun/eip4844_blobs/test_blob_txs.py
@pytest.mark.parametrize(\n    \"tx_max_fee_per_gas,tx_error\",\n    [\n        # max data gas is ok, but max fee per gas is less than base fee per gas\n        (\n            6,\n            \"insufficient max fee per gas\",\n        ),\n    ],\n    ids=[\"insufficient_max_fee_per_gas\"],\n)\n@pytest.mark.valid_from(\"Cancun\")\ndef test_invalid_normal_gas(\n    blockchain_test: BlockchainTestFiller,\n    pre: Dict,\n    env: Environment,\n    blocks: List[Block],\n):\n\"\"\"\n    Reject blocks with invalid blob txs due to:\n\n    - Sufficient max fee per data gas, but insufficient max fee per gas\n    \"\"\"\n    blockchain_test(\n        pre=pre,\n        post={},\n        blocks=blocks,\n        genesis_environment=env,\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs/#tests.cancun.eip4844_blobs.test_blob_txs.test_invalid_block_blob_count","title":"test_invalid_block_blob_count(blockchain_test, pre, env, blocks)","text":"

Test all invalid blob combinations in a single block, where the sum of all blobs in a block is at MAX_BLOBS_PER_BLOCK + 1.

This test is parametrized with all blob transaction combinations exceeding MAX_BLOBS_PER_BLOCK by one for a given block, and therefore if value of MAX_BLOBS_PER_BLOCK changes, this test is automatically updated.

Source code in tests/cancun/eip4844_blobs/test_blob_txs.py
@pytest.mark.parametrize(\n    \"blobs_per_tx\",\n    invalid_blob_combinations(),\n)\n@pytest.mark.parametrize(\"tx_error\", [\"invalid_blob_count\"])\n@pytest.mark.valid_from(\"Cancun\")\ndef test_invalid_block_blob_count(\n    blockchain_test: BlockchainTestFiller,\n    pre: Dict,\n    env: Environment,\n    blocks: List[Block],\n):\n\"\"\"\n    Test all invalid blob combinations in a single block, where the sum of all blobs in a block is\n    at `MAX_BLOBS_PER_BLOCK + 1`.\n\n    This test is parametrized with all blob transaction combinations exceeding\n    `MAX_BLOBS_PER_BLOCK` by one for a given block, and\n    therefore if value of `MAX_BLOBS_PER_BLOCK` changes, this test is automatically updated.\n    \"\"\"\n    blockchain_test(\n        pre=pre,\n        post={},\n        blocks=blocks,\n        genesis_environment=env,\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs/#tests.cancun.eip4844_blobs.test_blob_txs.test_insufficient_balance_blob_tx","title":"test_insufficient_balance_blob_tx(blockchain_test, pre, env, blocks)","text":"

Reject blocks where user cannot afford the data gas specified (but max_fee_per_gas would be enough for current block), including:

  • Transactions with and without priority fee
  • Transactions with and without value
  • Transactions with and without calldata
  • Transactions with max fee per data gas lower or higher than the priority fee
Source code in tests/cancun/eip4844_blobs/test_blob_txs.py
@pytest.mark.parametrize(\"tx_max_priority_fee_per_gas\", [0, 8])\n@pytest.mark.parametrize(\"tx_value\", [0, 1])\n@pytest.mark.parametrize(\n    \"tx_calldata\",\n    [b\"\", b\"\\x00\", b\"\\x01\"],\n    ids=[\"no_calldata\", \"single_zero_calldata\", \"single_one_calldata\"],\n)\n@pytest.mark.parametrize(\"tx_max_fee_per_data_gas\", [1, 100, 10000])\n@pytest.mark.parametrize(\"account_balance_modifier\", [-1], ids=[\"exact_balance_minus_1\"])\n@pytest.mark.parametrize(\"tx_error\", [\"insufficient_account_balance\"], ids=[\"\"])\n@pytest.mark.valid_from(\"Cancun\")\ndef test_insufficient_balance_blob_tx(\n    blockchain_test: BlockchainTestFiller,\n    pre: Dict,\n    env: Environment,\n    blocks: List[Block],\n):\n\"\"\"\n    Reject blocks where user cannot afford the data gas specified (but\n    max_fee_per_gas would be enough for current block), including:\n\n    - Transactions with and without priority fee\n    - Transactions with and without value\n    - Transactions with and without calldata\n    - Transactions with max fee per data gas lower or higher than the priority fee\n    \"\"\"\n    blockchain_test(\n        pre=pre,\n        post={},\n        blocks=blocks,\n        genesis_environment=env,\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs/#tests.cancun.eip4844_blobs.test_blob_txs.test_insufficient_balance_blob_tx_combinations","title":"test_insufficient_balance_blob_tx_combinations(blockchain_test, pre, env, blocks)","text":"

Reject all valid blob transaction combinations in a block, but block is invalid due to:

  • The amount of blobs is correct but the user cannot afford the transaction total cost
Source code in tests/cancun/eip4844_blobs/test_blob_txs.py
@pytest.mark.parametrize(\n    \"blobs_per_tx\",\n    all_valid_blob_combinations(),\n)\n@pytest.mark.parametrize(\"account_balance_modifier\", [-1], ids=[\"exact_balance_minus_1\"])\n@pytest.mark.parametrize(\"tx_error\", [\"insufficient_account_balance\"], ids=[\"\"])\n@pytest.mark.valid_from(\"Cancun\")\ndef test_insufficient_balance_blob_tx_combinations(\n    blockchain_test: BlockchainTestFiller,\n    pre: Dict,\n    env: Environment,\n    blocks: List[Block],\n):\n\"\"\"\n    Reject all valid blob transaction combinations in a block, but block is invalid due to:\n\n    - The amount of blobs is correct but the user cannot afford the\n            transaction total cost\n    \"\"\"\n    blockchain_test(\n        pre=pre,\n        post={},\n        blocks=blocks,\n        genesis_environment=env,\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs/#tests.cancun.eip4844_blobs.test_blob_txs.test_invalid_tx_blob_count","title":"test_invalid_tx_blob_count(blockchain_test, pre, env, blocks)","text":"

Reject blocks that include blob transactions with invalid blob counts:

  • blob count == 0 in type 3 transaction
  • blob count > MAX_BLOBS_PER_BLOCK in type 3 transaction
Source code in tests/cancun/eip4844_blobs/test_blob_txs.py
@pytest.mark.parametrize(\n    \"blobs_per_tx,tx_error\",\n    [\n        ([0], \"zero_blob_tx\"),\n        ([SpecHelpers.max_blobs_per_block() + 1], \"too_many_blobs_tx\"),\n    ],\n    ids=[\"too_few_blobs\", \"too_many_blobs\"],\n)\n@pytest.mark.valid_from(\"Cancun\")\ndef test_invalid_tx_blob_count(\n    blockchain_test: BlockchainTestFiller,\n    pre: Dict,\n    env: Environment,\n    blocks: List[Block],\n):\n\"\"\"\n    Reject blocks that include blob transactions with invalid blob counts:\n\n    - `blob count == 0` in type 3 transaction\n    - `blob count > MAX_BLOBS_PER_BLOCK` in type 3 transaction\n    \"\"\"\n    blockchain_test(\n        pre=pre,\n        post={},\n        blocks=blocks,\n        genesis_environment=env,\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs/#tests.cancun.eip4844_blobs.test_blob_txs.test_invalid_blob_hash_versioning","title":"test_invalid_blob_hash_versioning(blockchain_test, pre, env, blocks)","text":"

Reject blocks that include blob transactions with invalid blob hash version, including:

  • Single blob transaction with single blob with invalid version
  • Single blob transaction with multiple blobs all with invalid version
  • Single blob transaction with multiple blobs either with invalid version
  • Multiple blob transactions with single blob all with invalid version
  • Multiple blob transactions with multiple blobs all with invalid version
  • Multiple blob transactions with multiple blobs only one with invalid version
Source code in tests/cancun/eip4844_blobs/test_blob_txs.py
@pytest.mark.parametrize(\n    \"blob_hashes_per_tx\",\n    [\n        [[to_hash_bytes(1)]],\n        [[to_hash_bytes(x) for x in range(2)]],\n        [\n            add_kzg_version([to_hash_bytes(1)], Spec.BLOB_COMMITMENT_VERSION_KZG)\n            + [to_hash_bytes(2)]\n        ],\n        [\n            [to_hash_bytes(1)]\n            + add_kzg_version([to_hash_bytes(2)], Spec.BLOB_COMMITMENT_VERSION_KZG)\n        ],\n        [\n            add_kzg_version([to_hash_bytes(1)], Spec.BLOB_COMMITMENT_VERSION_KZG),\n            [to_hash_bytes(2)],\n        ],\n        [\n            add_kzg_version([to_hash_bytes(1)], Spec.BLOB_COMMITMENT_VERSION_KZG),\n            [to_hash_bytes(x) for x in range(1, 3)],\n        ],\n        [\n            add_kzg_version([to_hash_bytes(1)], Spec.BLOB_COMMITMENT_VERSION_KZG),\n            [to_hash_bytes(2)]\n            + add_kzg_version([to_hash_bytes(3)], Spec.BLOB_COMMITMENT_VERSION_KZG),\n        ],\n        [\n            add_kzg_version([to_hash_bytes(1)], Spec.BLOB_COMMITMENT_VERSION_KZG),\n            add_kzg_version([to_hash_bytes(2)], Spec.BLOB_COMMITMENT_VERSION_KZG),\n            [to_hash_bytes(3)],\n        ],\n    ],\n    ids=[\n        \"single_tx_single_blob\",\n        \"single_tx_multiple_blobs\",\n        \"single_tx_multiple_blobs_single_bad_hash_1\",\n        \"single_tx_multiple_blobs_single_bad_hash_2\",\n        \"multiple_txs_single_blob\",\n        \"multiple_txs_multiple_blobs\",\n        \"multiple_txs_multiple_blobs_single_bad_hash_1\",\n        \"multiple_txs_multiple_blobs_single_bad_hash_2\",\n    ],\n)\n@pytest.mark.parametrize(\"tx_error\", [\"invalid_versioned_hash\"], ids=[\"\"])\n@pytest.mark.valid_from(\"Cancun\")\ndef test_invalid_blob_hash_versioning(\n    blockchain_test: BlockchainTestFiller,\n    pre: Dict,\n    env: Environment,\n    blocks: List[Block],\n):\n\"\"\"\n    Reject blocks that include blob transactions with invalid blob hash\n    version, including:\n\n    - Single blob transaction with single blob with invalid version\n    - Single blob transaction with multiple blobs all with invalid version\n    - Single blob transaction with multiple blobs either with invalid version\n    - Multiple blob transactions with single blob all with invalid version\n    - Multiple blob transactions with multiple blobs all with invalid version\n    - Multiple blob transactions with multiple blobs only one with invalid version\n    \"\"\"\n    blockchain_test(\n        pre=pre,\n        post={},\n        blocks=blocks,\n        genesis_environment=env,\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs/#tests.cancun.eip4844_blobs.test_blob_txs.test_invalid_blob_tx_contract_creation","title":"test_invalid_blob_tx_contract_creation(blockchain_test, pre, env, blocks)","text":"

Reject blocks that include blob transactions that have nil to value (contract creating).

Source code in tests/cancun/eip4844_blobs/test_blob_txs.py
@pytest.mark.parametrize(\n    \"destination_account,tx_error\", [(None, \"no_contract_creating_blob_txs\")], ids=[\"\"]\n)\n@pytest.mark.valid_from(\"Cancun\")\ndef test_invalid_blob_tx_contract_creation(\n    blockchain_test: BlockchainTestFiller,\n    pre: Dict,\n    env: Environment,\n    blocks: List[Block],\n):\n\"\"\"\n    Reject blocks that include blob transactions that have nil to value (contract creating).\n    \"\"\"\n    blockchain_test(\n        pre=pre,\n        post={},\n        blocks=blocks,\n        genesis_environment=env,\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs/#tests.cancun.eip4844_blobs.test_blob_txs.test_blob_tx_attribute_opcodes","title":"test_blob_tx_attribute_opcodes(blockchain_test, pre, opcode, env, blocks, destination_account)","text":"

Test opcodes that read transaction attributes work properly for blob type transactions:

  • ORIGIN
  • CALLER
Source code in tests/cancun/eip4844_blobs/test_blob_txs.py
@pytest.mark.parametrize(\n    \"opcode\",\n    [Op.ORIGIN, Op.CALLER],\n    indirect=[\"opcode\"],\n)\n@pytest.mark.parametrize(\"tx_gas\", [500_000])\n@pytest.mark.valid_from(\"Cancun\")\ndef test_blob_tx_attribute_opcodes(\n    blockchain_test: BlockchainTestFiller,\n    pre: Dict,\n    opcode: Tuple[bytes, Storage.StorageDictType],\n    env: Environment,\n    blocks: List[Block],\n    destination_account: str,\n):\n\"\"\"\n    Test opcodes that read transaction attributes work properly for blob type transactions:\n\n    - ORIGIN\n    - CALLER\n    \"\"\"\n    code, storage = opcode\n    pre[destination_account] = Account(code=code)\n    post = {\n        destination_account: Account(\n            storage=storage,\n        )\n    }\n    blockchain_test(\n        pre=pre,\n        post=post,\n        blocks=blocks,\n        genesis_environment=env,\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs/#tests.cancun.eip4844_blobs.test_blob_txs.test_blob_tx_attribute_value_opcode","title":"test_blob_tx_attribute_value_opcode(blockchain_test, pre, opcode, env, blocks, tx_value, destination_account)","text":"

Test the VALUE opcode with different blob type transaction value amounts.

Source code in tests/cancun/eip4844_blobs/test_blob_txs.py
@pytest.mark.parametrize(\"opcode\", [Op.CALLVALUE], indirect=[\"opcode\"])\n@pytest.mark.parametrize(\"tx_value\", [0, 1, int(1e18)])\n@pytest.mark.parametrize(\"tx_gas\", [500_000])\n@pytest.mark.valid_from(\"Cancun\")\ndef test_blob_tx_attribute_value_opcode(\n    blockchain_test: BlockchainTestFiller,\n    pre: Dict,\n    opcode: Tuple[bytes, Storage.StorageDictType],\n    env: Environment,\n    blocks: List[Block],\n    tx_value: int,\n    destination_account: str,\n):\n\"\"\"\n    Test the VALUE opcode with different blob type transaction value amounts.\n    \"\"\"\n    code, storage = opcode\n    pre[destination_account] = Account(code=code)\n    post = {\n        destination_account: Account(\n            storage=storage,\n            balance=tx_value,\n        )\n    }\n    blockchain_test(\n        pre=pre,\n        post=post,\n        blocks=blocks,\n        genesis_environment=env,\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs/#tests.cancun.eip4844_blobs.test_blob_txs.test_blob_tx_attribute_calldata_opcodes","title":"test_blob_tx_attribute_calldata_opcodes(blockchain_test, pre, opcode, env, blocks, destination_account)","text":"

Test calldata related opcodes to verify their behavior is not affected by blobs:

  • CALLDATALOAD
  • CALLDATASIZE
  • CALLDATACOPY
Source code in tests/cancun/eip4844_blobs/test_blob_txs.py
@pytest.mark.parametrize(\n    \"opcode\",\n    [\n        Op.CALLDATALOAD,\n        Op.CALLDATASIZE,\n        Op.CALLDATACOPY,\n    ],\n    indirect=True,\n)\n@pytest.mark.parametrize(\n    \"tx_calldata\",\n    [\n        b\"\",\n        b\"\\x01\",\n        b\"\\x00\\x01\" * 16,\n    ],\n    ids=[\"empty\", \"single_byte\", \"word\"],\n)\n@pytest.mark.parametrize(\"tx_gas\", [500_000])\n@pytest.mark.valid_from(\"Cancun\")\ndef test_blob_tx_attribute_calldata_opcodes(\n    blockchain_test: BlockchainTestFiller,\n    pre: Dict,\n    opcode: Tuple[bytes, Storage.StorageDictType],\n    env: Environment,\n    blocks: List[Block],\n    destination_account: str,\n):\n\"\"\"\n    Test calldata related opcodes to verify their behavior is not affected by blobs:\n\n    - CALLDATALOAD\n    - CALLDATASIZE\n    - CALLDATACOPY\n    \"\"\"\n    code, storage = opcode\n    pre[destination_account] = Account(code=code)\n    post = {\n        destination_account: Account(\n            storage=storage,\n        )\n    }\n    blockchain_test(\n        pre=pre,\n        post=post,\n        blocks=blocks,\n        genesis_environment=env,\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs/#tests.cancun.eip4844_blobs.test_blob_txs.test_blob_tx_attribute_gasprice_opcode","title":"test_blob_tx_attribute_gasprice_opcode(blockchain_test, pre, opcode, env, blocks, destination_account)","text":"

Test GASPRICE opcode to sanity check that the data fee per gas does not affect its calculation:

  • No priority fee
  • Priority fee below data fee
  • Priority fee above data fee
Source code in tests/cancun/eip4844_blobs/test_blob_txs.py
@pytest.mark.parametrize(\"tx_max_priority_fee_per_gas\", [0, 2])  # always below data fee\n@pytest.mark.parametrize(\"tx_max_fee_per_data_gas\", [1, 3])  # normal and above priority fee\n@pytest.mark.parametrize(\"tx_max_fee_per_gas\", [100])  # always above priority fee\n@pytest.mark.parametrize(\"opcode\", [Op.GASPRICE], indirect=True)\n@pytest.mark.parametrize(\"tx_gas\", [500_000])\n@pytest.mark.valid_from(\"Cancun\")\ndef test_blob_tx_attribute_gasprice_opcode(\n    blockchain_test: BlockchainTestFiller,\n    pre: Dict,\n    opcode: Tuple[bytes, Storage.StorageDictType],\n    env: Environment,\n    blocks: List[Block],\n    destination_account: str,\n):\n\"\"\"\n    Test GASPRICE opcode to sanity check that the data fee per gas does not affect\n    its calculation:\n\n    - No priority fee\n    - Priority fee below data fee\n    - Priority fee above data fee\n    \"\"\"\n    code, storage = opcode\n    pre[destination_account] = Account(code=code)\n    post = {\n        destination_account: Account(\n            storage=storage,\n        )\n    }\n    blockchain_test(\n        pre=pre,\n        post=post,\n        blocks=blocks,\n        genesis_environment=env,\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs/#tests.cancun.eip4844_blobs.test_blob_txs.test_blob_type_tx_pre_fork","title":"test_blob_type_tx_pre_fork(blockchain_test, pre, blocks)","text":"

Reject blocks with blob type transactions before Cancun fork

Source code in tests/cancun/eip4844_blobs/test_blob_txs.py
@pytest.mark.parametrize(\n    [\n        \"blobs_per_tx\",\n        \"parent_excess_blobs\",\n        \"tx_max_fee_per_data_gas\",\n        \"tx_error\",\n    ],\n    [\n        ([0], None, 1, \"tx_type_3_not_allowed_yet\"),\n        ([1], None, 1, \"tx_type_3_not_allowed_yet\"),\n    ],\n    ids=[\"no_blob_tx\", \"one_blob_tx\"],\n)\n@pytest.mark.valid_at_transition_to(\"Cancun\")\ndef test_blob_type_tx_pre_fork(\n    blockchain_test: BlockchainTestFiller,\n    pre: Dict,\n    blocks: List[Block],\n):\n\"\"\"\n    Reject blocks with blob type transactions before Cancun fork\n    \"\"\"\n    blockchain_test(\n        pre=pre,\n        post={},\n        blocks=blocks,\n        genesis_environment=Environment(),  # `env` fixture has blob fields\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs/index/test_cases/","title":"Test Blob Txs - Test Cases","text":"

Test cases generated from tests/cancun/eip4844_blobs/test_blob_txs.py

Parametrized test cases generated from the test module tests/cancun/eip4844_blobs/test_blob_txs.py:

test_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(1, 1, 1, 1, 1, 1)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(1, 1, 1, 1, 1)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(1, 1, 1, 1, 2)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(1, 1, 1, 1)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(1, 1, 1, 2)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(1, 1, 1, 3)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(1, 1, 2, 2)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(1, 1, 1)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(1, 1, 2)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(1, 1, 3)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(1, 1, 4)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(1, 2, 2)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(1, 2, 3)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(2, 2, 2)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(1, 1)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(1, 2)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(1, 3)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(1, 4)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(1, 5)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(2, 2)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(2, 3)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(2, 4)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(3, 3)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(1,)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(2,)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(3,)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(4,)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(5,)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(6,)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(2, 1, 1, 1, 1)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(2, 1, 1, 1)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(3, 1, 1, 1)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(2, 2, 1, 1)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(2, 1, 1)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(3, 1, 1)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(4, 1, 1)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(2, 2, 1)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(3, 2, 1)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(2, 1)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(3, 1)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(4, 1)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(5, 1)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(3, 2)]\ntest_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(4, 2)]\ntest_invalid_tx_max_fee_per_data_gas[fork=Cancun-insufficient_max_fee_per_data_gas]\ntest_invalid_tx_max_fee_per_data_gas[fork=Cancun-invalid_max_fee_per_data_gas]\ntest_invalid_normal_gas[fork=Cancun-insufficient_max_fee_per_gas]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(1, 1, 1, 1, 1, 1, 1)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(1, 1, 1, 1, 1, 2)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(1, 1, 1, 1, 3)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(1, 1, 1, 2, 2)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(1, 1, 1, 4)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(1, 1, 2, 3)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(1, 2, 2, 2)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(1, 1, 5)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(1, 2, 4)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(1, 3, 3)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(2, 2, 3)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(1, 6)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(2, 5)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(3, 4)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(7,)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(2, 1, 1, 1, 1, 1)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(3, 1, 1, 1, 1)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(2, 2, 1, 1, 1)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(4, 1, 1, 1)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(3, 2, 1, 1)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(2, 2, 2, 1)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(5, 1, 1)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(4, 2, 1)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(3, 3, 1)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(3, 2, 2)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(6, 1)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(5, 2)]\ntest_invalid_block_blob_count[fork=Cancun-tx_error=invalid_blob_count-blobs_per_tx=(4, 3)]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=1-no_calldata-tx_value=0-tx_max_priority_fee_per_gas=0]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=1-no_calldata-tx_value=0-tx_max_priority_fee_per_gas=8]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=1-no_calldata-tx_value=1-tx_max_priority_fee_per_gas=0]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=1-no_calldata-tx_value=1-tx_max_priority_fee_per_gas=8]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=1-single_zero_calldata-tx_value=0-tx_max_priority_fee_per_gas=0]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=1-single_zero_calldata-tx_value=0-tx_max_priority_fee_per_gas=8]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=1-single_zero_calldata-tx_value=1-tx_max_priority_fee_per_gas=0]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=1-single_zero_calldata-tx_value=1-tx_max_priority_fee_per_gas=8]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=1-single_one_calldata-tx_value=0-tx_max_priority_fee_per_gas=0]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=1-single_one_calldata-tx_value=0-tx_max_priority_fee_per_gas=8]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=1-single_one_calldata-tx_value=1-tx_max_priority_fee_per_gas=0]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=1-single_one_calldata-tx_value=1-tx_max_priority_fee_per_gas=8]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=100-no_calldata-tx_value=0-tx_max_priority_fee_per_gas=0]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=100-no_calldata-tx_value=0-tx_max_priority_fee_per_gas=8]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=100-no_calldata-tx_value=1-tx_max_priority_fee_per_gas=0]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=100-no_calldata-tx_value=1-tx_max_priority_fee_per_gas=8]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=100-single_zero_calldata-tx_value=0-tx_max_priority_fee_per_gas=0]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=100-single_zero_calldata-tx_value=0-tx_max_priority_fee_per_gas=8]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=100-single_zero_calldata-tx_value=1-tx_max_priority_fee_per_gas=0]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=100-single_zero_calldata-tx_value=1-tx_max_priority_fee_per_gas=8]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=100-single_one_calldata-tx_value=0-tx_max_priority_fee_per_gas=0]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=100-single_one_calldata-tx_value=0-tx_max_priority_fee_per_gas=8]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=100-single_one_calldata-tx_value=1-tx_max_priority_fee_per_gas=0]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=100-single_one_calldata-tx_value=1-tx_max_priority_fee_per_gas=8]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=10000-no_calldata-tx_value=0-tx_max_priority_fee_per_gas=0]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=10000-no_calldata-tx_value=0-tx_max_priority_fee_per_gas=8]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=10000-no_calldata-tx_value=1-tx_max_priority_fee_per_gas=0]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=10000-no_calldata-tx_value=1-tx_max_priority_fee_per_gas=8]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=10000-single_zero_calldata-tx_value=0-tx_max_priority_fee_per_gas=0]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=10000-single_zero_calldata-tx_value=0-tx_max_priority_fee_per_gas=8]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=10000-single_zero_calldata-tx_value=1-tx_max_priority_fee_per_gas=0]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=10000-single_zero_calldata-tx_value=1-tx_max_priority_fee_per_gas=8]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=10000-single_one_calldata-tx_value=0-tx_max_priority_fee_per_gas=0]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=10000-single_one_calldata-tx_value=0-tx_max_priority_fee_per_gas=8]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=10000-single_one_calldata-tx_value=1-tx_max_priority_fee_per_gas=0]\ntest_insufficient_balance_blob_tx[fork=Cancun--exact_balance_minus_1-tx_max_fee_per_data_gas=10000-single_one_calldata-tx_value=1-tx_max_priority_fee_per_gas=8]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(1, 1, 1, 1, 1, 1)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(1, 1, 1, 1, 1)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(1, 1, 1, 1, 2)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(1, 1, 1, 1)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(1, 1, 1, 2)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(1, 1, 1, 3)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(1, 1, 2, 2)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(1, 1, 1)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(1, 1, 2)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(1, 1, 3)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(1, 1, 4)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(1, 2, 2)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(1, 2, 3)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(2, 2, 2)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(1, 1)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(1, 2)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(1, 3)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(1, 4)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(1, 5)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(2, 2)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(2, 3)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(2, 4)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(3, 3)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(1,)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(2,)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(3,)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(4,)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(5,)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(6,)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(2, 1, 1, 1, 1)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(2, 1, 1, 1)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(3, 1, 1, 1)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(2, 2, 1, 1)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(2, 1, 1)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(3, 1, 1)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(4, 1, 1)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(2, 2, 1)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(3, 2, 1)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(2, 1)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(3, 1)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(4, 1)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(5, 1)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(3, 2)]\ntest_insufficient_balance_blob_tx_combinations[fork=Cancun--exact_balance_minus_1-blobs_per_tx=(4, 2)]\ntest_invalid_tx_blob_count[fork=Cancun-too_few_blobs]\ntest_invalid_tx_blob_count[fork=Cancun-too_many_blobs]\ntest_invalid_blob_hash_versioning[fork=Cancun--single_tx_single_blob]\ntest_invalid_blob_hash_versioning[fork=Cancun--single_tx_multiple_blobs]\ntest_invalid_blob_hash_versioning[fork=Cancun--single_tx_multiple_blobs_single_bad_hash_1]\ntest_invalid_blob_hash_versioning[fork=Cancun--single_tx_multiple_blobs_single_bad_hash_2]\ntest_invalid_blob_hash_versioning[fork=Cancun--multiple_txs_single_blob]\ntest_invalid_blob_hash_versioning[fork=Cancun--multiple_txs_multiple_blobs]\ntest_invalid_blob_hash_versioning[fork=Cancun--multiple_txs_multiple_blobs_single_bad_hash_1]\ntest_invalid_blob_hash_versioning[fork=Cancun--multiple_txs_multiple_blobs_single_bad_hash_2]\ntest_invalid_blob_tx_contract_creation[fork=Cancun-]\ntest_blob_tx_attribute_opcodes[fork=Cancun-tx_gas=500000-opcode=ORIGIN]\ntest_blob_tx_attribute_opcodes[fork=Cancun-tx_gas=500000-opcode=CALLER]\ntest_blob_tx_attribute_value_opcode[fork=Cancun-tx_gas=500000-tx_value=0-opcode=CALLVALUE]\ntest_blob_tx_attribute_value_opcode[fork=Cancun-tx_gas=500000-tx_value=1-opcode=CALLVALUE]\ntest_blob_tx_attribute_value_opcode[fork=Cancun-tx_gas=500000-tx_value=1000000000000000000-opcode=CALLVALUE]\ntest_blob_tx_attribute_calldata_opcodes[fork=Cancun-tx_gas=500000-empty-opcode=CALLDATALOAD]\ntest_blob_tx_attribute_calldata_opcodes[fork=Cancun-tx_gas=500000-empty-opcode=CALLDATASIZE]\ntest_blob_tx_attribute_calldata_opcodes[fork=Cancun-tx_gas=500000-empty-opcode=CALLDATACOPY]\ntest_blob_tx_attribute_calldata_opcodes[fork=Cancun-tx_gas=500000-single_byte-opcode=CALLDATALOAD]\ntest_blob_tx_attribute_calldata_opcodes[fork=Cancun-tx_gas=500000-single_byte-opcode=CALLDATASIZE]\ntest_blob_tx_attribute_calldata_opcodes[fork=Cancun-tx_gas=500000-single_byte-opcode=CALLDATACOPY]\ntest_blob_tx_attribute_calldata_opcodes[fork=Cancun-tx_gas=500000-word-opcode=CALLDATALOAD]\ntest_blob_tx_attribute_calldata_opcodes[fork=Cancun-tx_gas=500000-word-opcode=CALLDATASIZE]\ntest_blob_tx_attribute_calldata_opcodes[fork=Cancun-tx_gas=500000-word-opcode=CALLDATACOPY]\ntest_blob_tx_attribute_gasprice_opcode[fork=Cancun-tx_gas=500000-opcode=GASPRICE-tx_max_fee_per_gas=100-tx_max_fee_per_data_gas=1-tx_max_priority_fee_per_gas=0]\ntest_blob_tx_attribute_gasprice_opcode[fork=Cancun-tx_gas=500000-opcode=GASPRICE-tx_max_fee_per_gas=100-tx_max_fee_per_data_gas=1-tx_max_priority_fee_per_gas=2]\ntest_blob_tx_attribute_gasprice_opcode[fork=Cancun-tx_gas=500000-opcode=GASPRICE-tx_max_fee_per_gas=100-tx_max_fee_per_data_gas=3-tx_max_priority_fee_per_gas=0]\ntest_blob_tx_attribute_gasprice_opcode[fork=Cancun-tx_gas=500000-opcode=GASPRICE-tx_max_fee_per_gas=100-tx_max_fee_per_data_gas=3-tx_max_priority_fee_per_gas=2]\ntest_blob_type_tx_pre_fork[fork=ShanghaiToCancunAtTime15k-no_blob_tx]\ntest_blob_type_tx_pre_fork[fork=ShanghaiToCancunAtTime15k-one_blob_tx]\n

This output was extracted from the result of:

fill --collect-only -q --until Cancun tests/cancun/eip4844_blobs/test_blob_txs.py\n
"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs_full/","title":"Test Blob Txs Full","text":"

Documentation for tests/cancun/eip4844_blobs/test_blob_txs_full.py.

Generate fixtures for these test cases for Cancun with:

Cancun only:

fill -v tests/cancun/eip4844_blobs/test_blob_txs_full.py --fork=Cancun --evm-bin=/path/to/evm-tool-dev-version\n
For all forks up to and including Cancun:
fill -v tests/cancun/eip4844_blobs/test_blob_txs_full.py --until=Cancun --evm-bin=/path/to/evm-tool-dev-version\n

Tests full blob type transactions for EIP-4844: Shard Blob Transactions

Test full blob type transactions for EIP-4844: Shard Blob Transactions.

"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs_full/#tests.cancun.eip4844_blobs.test_blob_txs_full.Spec","title":"Spec dataclass","text":"

Parameters from the EIP-4844 specifications as defined at https://eips.ethereum.org/EIPS/eip-4844#parameters

If the parameter is not currently used within the tests, it is commented out.

Source code in tests/cancun/eip4844_blobs/spec.py
@dataclass(frozen=True)\nclass Spec:\n\"\"\"\n    Parameters from the EIP-4844 specifications as defined at\n    https://eips.ethereum.org/EIPS/eip-4844#parameters\n\n    If the parameter is not currently used within the tests, it is commented\n    out.\n    \"\"\"\n\n    BLOB_TX_TYPE = 0x03\n    FIELD_ELEMENTS_PER_BLOB = 4096\n    BLS_MODULUS = 0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001\n    BLOB_COMMITMENT_VERSION_KZG = 1\n    POINT_EVALUATION_PRECOMPILE_ADDRESS = 20\n    POINT_EVALUATION_PRECOMPILE_GAS = 50_000\n    MAX_DATA_GAS_PER_BLOCK = 786432\n    TARGET_DATA_GAS_PER_BLOCK = 393216\n    MIN_DATA_GASPRICE = 1\n    DATA_GASPRICE_UPDATE_FRACTION = 3338477\n    # MAX_VERSIONED_HASHES_LIST_SIZE = 2**24\n    # MAX_CALLDATA_SIZE = 2**24\n    # MAX_ACCESS_LIST_SIZE = 2**24\n    # MAX_ACCESS_LIST_STORAGE_KEYS = 2**24\n    # MAX_TX_WRAP_COMMITMENTS = 2**12\n    # LIMIT_BLOBS_PER_TX = 2**12\n    DATA_GAS_PER_BLOB = 2**17\n    HASH_OPCODE_BYTE = 0x49\n    HASH_GAS_COST = 3\n\n    @classmethod\n    def kzg_to_versioned_hash(\n        cls,\n        kzg_commitment: bytes | int,  # 48 bytes\n        blob_commitment_version_kzg: Optional[bytes | int] = None,\n    ) -> bytes:\n\"\"\"\n        Calculates the versioned hash for a given KZG commitment.\n        \"\"\"\n        if blob_commitment_version_kzg is None:\n            blob_commitment_version_kzg = cls.BLOB_COMMITMENT_VERSION_KZG\n        if isinstance(kzg_commitment, int):\n            kzg_commitment = kzg_commitment.to_bytes(48, \"big\")\n        if isinstance(blob_commitment_version_kzg, int):\n            blob_commitment_version_kzg = blob_commitment_version_kzg.to_bytes(1, \"big\")\n        return blob_commitment_version_kzg + sha256(kzg_commitment).digest()[1:]\n\n    @classmethod\n    def fake_exponential(cls, factor: int, numerator: int, denominator: int) -> int:\n\"\"\"\n        Used to calculate the data gas cost.\n        \"\"\"\n        i = 1\n        output = 0\n        numerator_accumulator = factor * denominator\n        while numerator_accumulator > 0:\n            output += numerator_accumulator\n            numerator_accumulator = (numerator_accumulator * numerator) // (denominator * i)\n            i += 1\n        return output // denominator\n\n    @classmethod\n    def calc_excess_data_gas(cls, parent: BlockHeaderDataGasFields) -> int:\n\"\"\"\n        Calculate the excess data gas for a block given the excess data gas\n        and data gas used from the parent block header.\n        \"\"\"\n        if parent.excess_data_gas + parent.data_gas_used < cls.TARGET_DATA_GAS_PER_BLOCK:\n            return 0\n        else:\n            return parent.excess_data_gas + parent.data_gas_used - cls.TARGET_DATA_GAS_PER_BLOCK\n\n    # Note: Currently unused.\n    # @classmethod\n    # def get_total_data_gas(cls, tx: Transaction) -> int:\n    #     \"\"\"\n    #     Calculate the total data gas for a transaction.\n    #     \"\"\"\n    #     if tx.blob_versioned_hashes is None:\n    #         return 0\n    #     return cls.DATA_GAS_PER_BLOB * len(tx.blob_versioned_hashes)\n\n    @classmethod\n    def get_data_gasprice(cls, *, excess_data_gas: int) -> int:\n\"\"\"\n        Calculate the data gas price from the excess.\n        \"\"\"\n        return cls.fake_exponential(\n            cls.MIN_DATA_GASPRICE,\n            excess_data_gas,\n            cls.DATA_GASPRICE_UPDATE_FRACTION,\n        )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs_full/#tests.cancun.eip4844_blobs.test_blob_txs_full.SpecHelpers","title":"SpecHelpers dataclass","text":"

Define parameters and helper functions that are tightly coupled to the 4844 spec but not strictly part of it.

Source code in tests/cancun/eip4844_blobs/spec.py
@dataclass(frozen=True)\nclass SpecHelpers:\n\"\"\"\n    Define parameters and helper functions that are tightly coupled to the 4844\n    spec but not strictly part of it.\n    \"\"\"\n\n    BYTES_PER_FIELD_ELEMENT = 32\n\n    @classmethod\n    def max_blobs_per_block(cls) -> int:  # MAX_BLOBS_PER_BLOCK =\n\"\"\"\n        Returns the maximum number of blobs per block.\n        \"\"\"\n        return Spec.MAX_DATA_GAS_PER_BLOCK // Spec.DATA_GAS_PER_BLOB\n\n    @classmethod\n    def target_blobs_per_block(cls) -> int:\n\"\"\"\n        Returns the target number of blobs per block.\n        \"\"\"\n        return Spec.TARGET_DATA_GAS_PER_BLOCK // Spec.DATA_GAS_PER_BLOB\n\n    @classmethod\n    def calc_excess_data_gas_from_blob_count(\n        cls, parent_excess_data_gas: int, parent_blob_count: int\n    ) -> int:\n\"\"\"\n        Calculate the excess data gas for a block given the parent excess data gas\n        and the number of blobs in the block.\n        \"\"\"\n        parent_consumed_data_gas = parent_blob_count * Spec.DATA_GAS_PER_BLOB\n        return Spec.calc_excess_data_gas(\n            BlockHeaderDataGasFields(parent_excess_data_gas, parent_consumed_data_gas)\n        )\n\n    @classmethod\n    def get_min_excess_data_gas_for_data_gas_price(cls, data_gas_price: int) -> int:\n\"\"\"\n        Gets the minimum required excess data gas value to get a given data gas cost in a block\n        \"\"\"\n        current_excess_data_gas = 0\n        current_data_gas_price = 1\n        while current_data_gas_price < data_gas_price:\n            current_excess_data_gas += Spec.DATA_GAS_PER_BLOB\n            current_data_gas_price = Spec.get_data_gasprice(\n                excess_data_gas=current_excess_data_gas\n            )\n        return current_excess_data_gas\n\n    @classmethod\n    def get_min_excess_data_blobs_for_data_gas_price(cls, data_gas_price: int) -> int:\n\"\"\"\n        Gets the minimum required excess data blobs to get a given data gas cost in a block\n        \"\"\"\n        return (\n            cls.get_min_excess_data_gas_for_data_gas_price(data_gas_price)\n            // Spec.DATA_GAS_PER_BLOB\n        )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs_full/#tests.cancun.eip4844_blobs.test_blob_txs_full.test_reject_valid_full_blob_in_block_rlp","title":"test_reject_valid_full_blob_in_block_rlp(blockchain_test, pre, env, blocks)","text":"

Test valid blob combinations where one or more txs in the block serialized version contain a full blob (network version) tx.

Source code in tests/cancun/eip4844_blobs/test_blob_txs_full.py
@pytest.mark.parametrize(\n    \"txs_blobs,txs_wrapped_blobs\",\n    [\n        (\n            [  # Txs\n                [  # Blobs per transaction\n                    Blob(\n                        blob=bytes(\n                            Spec.FIELD_ELEMENTS_PER_BLOB * SpecHelpers.BYTES_PER_FIELD_ELEMENT\n                        ),\n                        kzg_commitment=INF_POINT,\n                        kzg_proof=INF_POINT,\n                    ),\n                ]\n            ],\n            [True],\n        ),\n        (\n            [  # Txs\n                [  # Blobs per transaction\n                    Blob(\n                        blob=bytes(\n                            Spec.FIELD_ELEMENTS_PER_BLOB * SpecHelpers.BYTES_PER_FIELD_ELEMENT\n                        ),\n                        kzg_commitment=INF_POINT,\n                        kzg_proof=INF_POINT,\n                    )\n                ]\n                for _ in range(SpecHelpers.max_blobs_per_block())\n            ],\n            [True] + ([False] * (SpecHelpers.max_blobs_per_block() - 1)),\n        ),\n        (\n            [  # Txs\n                [  # Blobs per transaction\n                    Blob(\n                        blob=bytes(\n                            Spec.FIELD_ELEMENTS_PER_BLOB * SpecHelpers.BYTES_PER_FIELD_ELEMENT\n                        ),\n                        kzg_commitment=INF_POINT,\n                        kzg_proof=INF_POINT,\n                    )\n                ]\n                for _ in range(SpecHelpers.max_blobs_per_block())\n            ],\n            ([False] * (SpecHelpers.max_blobs_per_block() - 1)) + [True],\n        ),\n    ],\n    ids=[\n        \"one_full_blob_one_tx\",\n        \"one_full_blob_max_txs\",\n        \"one_full_blob_at_the_end_max_txs\",\n    ],\n)\n@pytest.mark.valid_from(\"Cancun\")\ndef test_reject_valid_full_blob_in_block_rlp(\n    blockchain_test: BlockchainTestFiller,\n    pre: Dict,\n    env: Environment,\n    blocks: List[Block],\n):\n\"\"\"\n    Test valid blob combinations where one or more txs in the block\n    serialized version contain a full blob (network version) tx.\n    \"\"\"\n    blockchain_test(\n        pre=pre,\n        post={},\n        blocks=blocks,\n        genesis_environment=env,\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blob_txs_full/index/test_cases/","title":"Test Blob Txs Full - Test Cases","text":"

Test cases generated from tests/cancun/eip4844_blobs/test_blob_txs_full.py

Parametrized test cases generated from the test module tests/cancun/eip4844_blobs/test_blob_txs_full.py:

test_reject_valid_full_blob_in_block_rlp[fork=Cancun-one_full_blob_one_tx]\ntest_reject_valid_full_blob_in_block_rlp[fork=Cancun-one_full_blob_max_txs]\ntest_reject_valid_full_blob_in_block_rlp[fork=Cancun-one_full_blob_at_the_end_max_txs]\n

This output was extracted from the result of:

fill --collect-only -q --until Cancun tests/cancun/eip4844_blobs/test_blob_txs_full.py\n
"},{"location":"tests/cancun/eip4844_blobs/test_blobhash_opcode/","title":"Test Blobhash Opcode","text":"

Documentation for tests/cancun/eip4844_blobs/test_blobhash_opcode.py.

Generate fixtures for these test cases for Cancun with:

Cancun only:

fill -v tests/cancun/eip4844_blobs/test_blobhash_opcode.py --fork=Cancun --evm-bin=/path/to/evm-tool-dev-version\n
For all forks up to and including Cancun:
fill -v tests/cancun/eip4844_blobs/test_blobhash_opcode.py --until=Cancun --evm-bin=/path/to/evm-tool-dev-version\n

Tests BLOBHASH opcode in EIP-4844: Shard Blob Transactions

Test cases for the BLOBHASH opcode in EIP-4844: Shard Blob Transactions.

Adding a new test

Add a function that is named test_<test_name> and takes at least the following arguments:

  • blockchain_test
  • pre
  • tx
  • post

Additional custom pytest.fixture fixtures can be added and parametrized for new test cases.

There is no specific structure to follow within this test module.

"},{"location":"tests/cancun/eip4844_blobs/test_blobhash_opcode/#tests.cancun.eip4844_blobs.test_blobhash_opcode.Spec","title":"Spec dataclass","text":"

Parameters from the EIP-4844 specifications as defined at https://eips.ethereum.org/EIPS/eip-4844#parameters

If the parameter is not currently used within the tests, it is commented out.

Source code in tests/cancun/eip4844_blobs/spec.py
@dataclass(frozen=True)\nclass Spec:\n\"\"\"\n    Parameters from the EIP-4844 specifications as defined at\n    https://eips.ethereum.org/EIPS/eip-4844#parameters\n\n    If the parameter is not currently used within the tests, it is commented\n    out.\n    \"\"\"\n\n    BLOB_TX_TYPE = 0x03\n    FIELD_ELEMENTS_PER_BLOB = 4096\n    BLS_MODULUS = 0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001\n    BLOB_COMMITMENT_VERSION_KZG = 1\n    POINT_EVALUATION_PRECOMPILE_ADDRESS = 20\n    POINT_EVALUATION_PRECOMPILE_GAS = 50_000\n    MAX_DATA_GAS_PER_BLOCK = 786432\n    TARGET_DATA_GAS_PER_BLOCK = 393216\n    MIN_DATA_GASPRICE = 1\n    DATA_GASPRICE_UPDATE_FRACTION = 3338477\n    # MAX_VERSIONED_HASHES_LIST_SIZE = 2**24\n    # MAX_CALLDATA_SIZE = 2**24\n    # MAX_ACCESS_LIST_SIZE = 2**24\n    # MAX_ACCESS_LIST_STORAGE_KEYS = 2**24\n    # MAX_TX_WRAP_COMMITMENTS = 2**12\n    # LIMIT_BLOBS_PER_TX = 2**12\n    DATA_GAS_PER_BLOB = 2**17\n    HASH_OPCODE_BYTE = 0x49\n    HASH_GAS_COST = 3\n\n    @classmethod\n    def kzg_to_versioned_hash(\n        cls,\n        kzg_commitment: bytes | int,  # 48 bytes\n        blob_commitment_version_kzg: Optional[bytes | int] = None,\n    ) -> bytes:\n\"\"\"\n        Calculates the versioned hash for a given KZG commitment.\n        \"\"\"\n        if blob_commitment_version_kzg is None:\n            blob_commitment_version_kzg = cls.BLOB_COMMITMENT_VERSION_KZG\n        if isinstance(kzg_commitment, int):\n            kzg_commitment = kzg_commitment.to_bytes(48, \"big\")\n        if isinstance(blob_commitment_version_kzg, int):\n            blob_commitment_version_kzg = blob_commitment_version_kzg.to_bytes(1, \"big\")\n        return blob_commitment_version_kzg + sha256(kzg_commitment).digest()[1:]\n\n    @classmethod\n    def fake_exponential(cls, factor: int, numerator: int, denominator: int) -> int:\n\"\"\"\n        Used to calculate the data gas cost.\n        \"\"\"\n        i = 1\n        output = 0\n        numerator_accumulator = factor * denominator\n        while numerator_accumulator > 0:\n            output += numerator_accumulator\n            numerator_accumulator = (numerator_accumulator * numerator) // (denominator * i)\n            i += 1\n        return output // denominator\n\n    @classmethod\n    def calc_excess_data_gas(cls, parent: BlockHeaderDataGasFields) -> int:\n\"\"\"\n        Calculate the excess data gas for a block given the excess data gas\n        and data gas used from the parent block header.\n        \"\"\"\n        if parent.excess_data_gas + parent.data_gas_used < cls.TARGET_DATA_GAS_PER_BLOCK:\n            return 0\n        else:\n            return parent.excess_data_gas + parent.data_gas_used - cls.TARGET_DATA_GAS_PER_BLOCK\n\n    # Note: Currently unused.\n    # @classmethod\n    # def get_total_data_gas(cls, tx: Transaction) -> int:\n    #     \"\"\"\n    #     Calculate the total data gas for a transaction.\n    #     \"\"\"\n    #     if tx.blob_versioned_hashes is None:\n    #         return 0\n    #     return cls.DATA_GAS_PER_BLOB * len(tx.blob_versioned_hashes)\n\n    @classmethod\n    def get_data_gasprice(cls, *, excess_data_gas: int) -> int:\n\"\"\"\n        Calculate the data gas price from the excess.\n        \"\"\"\n        return cls.fake_exponential(\n            cls.MIN_DATA_GASPRICE,\n            excess_data_gas,\n            cls.DATA_GASPRICE_UPDATE_FRACTION,\n        )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blobhash_opcode/#tests.cancun.eip4844_blobs.test_blobhash_opcode.test_blobhash_gas_cost","title":"test_blobhash_gas_cost(pre, template_tx, blocks, post, tx_type, blockchain_test)","text":"

Tests BLOBHASH opcode gas cost using a variety of indexes.

Asserts that the gas consumption of the BLOBHASH opcode is correct by ensuring it matches HASH_OPCODE_GAS = 3. Includes both valid and invalid random index sizes from the range [0, 2**256-1], for tx types 2 and 3.

Source code in tests/cancun/eip4844_blobs/test_blobhash_opcode.py
@pytest.mark.parametrize(\"tx_type\", [0, 1, 2, 3])\ndef test_blobhash_gas_cost(\n    pre,\n    template_tx,\n    blocks,\n    post,\n    tx_type,\n    blockchain_test: BlockchainTestFiller,\n):\n\"\"\"\n    Tests `BLOBHASH` opcode gas cost using a variety of indexes.\n\n    Asserts that the gas consumption of the `BLOBHASH` opcode is correct by ensuring\n    it matches `HASH_OPCODE_GAS = 3`. Includes both valid and invalid random\n    index sizes from the range `[0, 2**256-1]`, for tx types 2 and 3.\n    \"\"\"\n    assert (\n        Op.BLOBHASH.int() == Spec.HASH_OPCODE_BYTE\n    ), \"Opcodes blobhash byte doesn't match that defined in the spec\"\n    gas_measures_code = [\n        CodeGasMeasure(\n            code=Op.BLOBHASH(i),\n            overhead_cost=3,\n            extra_stack_items=1,\n        )\n        for i in blobhash_index_values\n    ]\n    for i, gas_code in enumerate(gas_measures_code):\n        address = to_address(0x100 + i * 0x100)\n        pre[address] = Account(code=gas_code)\n        blocks.append(\n            Block(\n                txs=[\n                    template_tx.with_fields(\n                        ty=tx_type,\n                        nonce=i,\n                        to=address,\n                        gas_price=10 if tx_type < 2 else None,\n                        access_list=[] if tx_type >= 2 else None,\n                        max_priority_fee_per_gas=10 if tx_type >= 2 else None,\n                        blob_versioned_hashes=random_blob_hashes[\n                            0 : SpecHelpers.target_blobs_per_block()\n                        ]\n                        if tx_type >= 3\n                        else None,\n                    )\n                ]\n            )\n        )\n        post[address] = Account(storage={0: Spec.HASH_GAS_COST})\n    blockchain_test(\n        pre=pre,\n        blocks=blocks,\n        post=post,\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blobhash_opcode/#tests.cancun.eip4844_blobs.test_blobhash_opcode.SpecHelpers","title":"SpecHelpers dataclass","text":"

Define parameters and helper functions that are tightly coupled to the 4844 spec but not strictly part of it.

Source code in tests/cancun/eip4844_blobs/spec.py
@dataclass(frozen=True)\nclass SpecHelpers:\n\"\"\"\n    Define parameters and helper functions that are tightly coupled to the 4844\n    spec but not strictly part of it.\n    \"\"\"\n\n    BYTES_PER_FIELD_ELEMENT = 32\n\n    @classmethod\n    def max_blobs_per_block(cls) -> int:  # MAX_BLOBS_PER_BLOCK =\n\"\"\"\n        Returns the maximum number of blobs per block.\n        \"\"\"\n        return Spec.MAX_DATA_GAS_PER_BLOCK // Spec.DATA_GAS_PER_BLOB\n\n    @classmethod\n    def target_blobs_per_block(cls) -> int:\n\"\"\"\n        Returns the target number of blobs per block.\n        \"\"\"\n        return Spec.TARGET_DATA_GAS_PER_BLOCK // Spec.DATA_GAS_PER_BLOB\n\n    @classmethod\n    def calc_excess_data_gas_from_blob_count(\n        cls, parent_excess_data_gas: int, parent_blob_count: int\n    ) -> int:\n\"\"\"\n        Calculate the excess data gas for a block given the parent excess data gas\n        and the number of blobs in the block.\n        \"\"\"\n        parent_consumed_data_gas = parent_blob_count * Spec.DATA_GAS_PER_BLOB\n        return Spec.calc_excess_data_gas(\n            BlockHeaderDataGasFields(parent_excess_data_gas, parent_consumed_data_gas)\n        )\n\n    @classmethod\n    def get_min_excess_data_gas_for_data_gas_price(cls, data_gas_price: int) -> int:\n\"\"\"\n        Gets the minimum required excess data gas value to get a given data gas cost in a block\n        \"\"\"\n        current_excess_data_gas = 0\n        current_data_gas_price = 1\n        while current_data_gas_price < data_gas_price:\n            current_excess_data_gas += Spec.DATA_GAS_PER_BLOB\n            current_data_gas_price = Spec.get_data_gasprice(\n                excess_data_gas=current_excess_data_gas\n            )\n        return current_excess_data_gas\n\n    @classmethod\n    def get_min_excess_data_blobs_for_data_gas_price(cls, data_gas_price: int) -> int:\n\"\"\"\n        Gets the minimum required excess data blobs to get a given data gas cost in a block\n        \"\"\"\n        return (\n            cls.get_min_excess_data_gas_for_data_gas_price(data_gas_price)\n            // Spec.DATA_GAS_PER_BLOB\n        )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blobhash_opcode/#tests.cancun.eip4844_blobs.test_blobhash_opcode.test_blobhash_scenarios","title":"test_blobhash_scenarios(pre, template_tx, blocks, post, scenario, blockchain_test)","text":"

Tests that the BLOBHASH opcode returns the correct versioned hash for various valid indexes.

Covers various scenarios with random blob_versioned_hash values within the valid range [0, 2**256-1].

Source code in tests/cancun/eip4844_blobs/test_blobhash_opcode.py
@pytest.mark.parametrize(\n    \"scenario\",\n    [\n        \"single_valid\",\n        \"repeated_valid\",\n        \"valid_invalid\",\n        \"varied_valid\",\n    ],\n)\ndef test_blobhash_scenarios(\n    pre,\n    template_tx,\n    blocks,\n    post,\n    scenario: str,\n    blockchain_test: BlockchainTestFiller,\n):\n\"\"\"\n    Tests that the `BLOBHASH` opcode returns the correct versioned hash for\n    various valid indexes.\n\n    Covers various scenarios with random `blob_versioned_hash` values within\n    the valid range `[0, 2**256-1]`.\n    \"\"\"\n    TOTAL_BLOCKS = 5\n    b_hashes_list = BlobhashScenario.create_blob_hashes_list(length=TOTAL_BLOCKS)\n    blobhash_calls = BlobhashScenario.generate_blobhash_bytecode(scenario)\n    for i in range(TOTAL_BLOCKS):\n        address = to_address(0x100 + i * 0x100)\n        pre[address] = Account(code=blobhash_calls)\n        blocks.append(\n            Block(\n                txs=[\n                    template_tx.with_fields(\n                        ty=Spec.BLOB_TX_TYPE,\n                        nonce=i,\n                        to=address,\n                        access_list=[],\n                        max_priority_fee_per_gas=10,\n                        blob_versioned_hashes=b_hashes_list[i],\n                    )\n                ]\n            )\n        )\n        post[address] = Account(\n            storage={\n                index: b_hashes_list[i][index]\n                for index in range(SpecHelpers.max_blobs_per_block())\n            }\n        )\n    blockchain_test(\n        pre=pre,\n        blocks=blocks,\n        post=post,\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blobhash_opcode/#tests.cancun.eip4844_blobs.test_blobhash_opcode.test_blobhash_invalid_blob_index","title":"test_blobhash_invalid_blob_index(pre, template_tx, blocks, post, blockchain_test, scenario)","text":"

Tests that the BLOBHASH opcode returns a zeroed bytes32 value for invalid indexes.

Includes cases where the index is negative (index < 0) or exceeds the maximum number of blob_versioned_hash values stored: (index >= len(tx.message.blob_versioned_hashes)).

It confirms that the returned value is a zeroed bytes32 for each case.

Source code in tests/cancun/eip4844_blobs/test_blobhash_opcode.py
@pytest.mark.parametrize(\n    \"scenario\",\n    [\n        \"invalid_calls\",\n    ],\n)\ndef test_blobhash_invalid_blob_index(\n    pre,\n    template_tx,\n    blocks,\n    post,\n    blockchain_test: BlockchainTestFiller,\n    scenario,\n):\n\"\"\"\n    Tests that the `BLOBHASH` opcode returns a zeroed `bytes32` value for invalid\n    indexes.\n\n    Includes cases where the index is negative (`index < 0`) or\n    exceeds the maximum number of `blob_versioned_hash` values stored:\n    (`index >= len(tx.message.blob_versioned_hashes)`).\n\n    It confirms that the returned value is a zeroed `bytes32` for each case.\n    \"\"\"\n    TOTAL_BLOCKS = 5\n    blobhash_calls = BlobhashScenario.generate_blobhash_bytecode(scenario)\n    for i in range(TOTAL_BLOCKS):\n        address = to_address(0x100 + i * 0x100)\n        pre[address] = Account(code=blobhash_calls)\n        blob_per_block = (i % SpecHelpers.max_blobs_per_block()) + 1\n        blobs = [random_blob_hashes[blob] for blob in range(blob_per_block)]\n        blocks.append(\n            Block(\n                txs=[\n                    template_tx.with_fields(\n                        ty=Spec.BLOB_TX_TYPE,\n                        nonce=i,\n                        to=address,\n                        access_list=[],\n                        max_priority_fee_per_gas=10,\n                        blob_versioned_hashes=blobs,\n                    )\n                ]\n            )\n        )\n        post[address] = Account(\n            storage={\n                index: (0 if index < 0 or index >= blob_per_block else blobs[index])\n                for index in range(\n                    -TOTAL_BLOCKS,\n                    blob_per_block + (TOTAL_BLOCKS - (i % SpecHelpers.max_blobs_per_block())),\n                )\n            }\n        )\n    blockchain_test(\n        pre=pre,\n        blocks=blocks,\n        post=post,\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blobhash_opcode/#tests.cancun.eip4844_blobs.test_blobhash_opcode.test_blobhash_multiple_txs_in_block","title":"test_blobhash_multiple_txs_in_block(pre, blob_tx, post, blockchain_test)","text":"

Tests that the BLOBHASH opcode returns the appropriate values when there is more than 1 blob tx type within a block (for tx types 2 and 3).

Scenarios involve tx type 3 followed by tx type 2 running the same code within a block, including the opposite.

Source code in tests/cancun/eip4844_blobs/test_blobhash_opcode.py
def test_blobhash_multiple_txs_in_block(\n    pre,\n    blob_tx,\n    post,\n    blockchain_test: BlockchainTestFiller,\n):\n\"\"\"\n    Tests that the `BLOBHASH` opcode returns the appropriate values when there\n    is more than 1 blob tx type within a block (for tx types 2 and 3).\n\n    Scenarios involve tx type 3 followed by tx type 2 running the same code\n    within a block, including the opposite.\n    \"\"\"\n    blobhash_bytecode = BlobhashScenario.generate_blobhash_bytecode(\"single_valid\")\n    pre = {\n        **pre,\n        **{\n            to_address(address): Account(code=blobhash_bytecode)\n            for address in range(0x100, 0x500, 0x100)\n        },\n    }\n    blocks = [\n        Block(\n            txs=[\n                blob_tx(address=to_address(0x100), type=3, nonce=0),\n                blob_tx(address=to_address(0x100), type=2, nonce=1),\n            ]\n        ),\n        Block(\n            txs=[\n                blob_tx(address=to_address(0x200), type=2, nonce=2),\n                blob_tx(address=to_address(0x200), type=3, nonce=3),\n            ]\n        ),\n        Block(\n            txs=[\n                blob_tx(address=to_address(0x300), type=2, nonce=4),\n                blob_tx(address=to_address(0x400), type=3, nonce=5),\n            ],\n        ),\n    ]\n    post = {\n        to_address(address): Account(\n            storage={i: random_blob_hashes[i] for i in range(SpecHelpers.max_blobs_per_block())}\n        )\n        if address in (0x200, 0x400)\n        else Account(storage={i: 0 for i in range(SpecHelpers.max_blobs_per_block())})\n        for address in range(0x100, 0x500, 0x100)\n    }\n    blockchain_test(\n        pre=pre,\n        blocks=blocks,\n        post=post,\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blobhash_opcode/index/test_cases/","title":"Test Blobhash Opcode - Test Cases","text":"

Test cases generated from tests/cancun/eip4844_blobs/test_blobhash_opcode.py

Parametrized test cases generated from the test module tests/cancun/eip4844_blobs/test_blobhash_opcode.py:

test_blobhash_gas_cost[fork=Cancun-tx_type=0]\ntest_blobhash_gas_cost[fork=Cancun-tx_type=1]\ntest_blobhash_gas_cost[fork=Cancun-tx_type=2]\ntest_blobhash_gas_cost[fork=Cancun-tx_type=3]\ntest_blobhash_scenarios[fork=Cancun-scenario=single_valid]\ntest_blobhash_scenarios[fork=Cancun-scenario=repeated_valid]\ntest_blobhash_scenarios[fork=Cancun-scenario=valid_invalid]\ntest_blobhash_scenarios[fork=Cancun-scenario=varied_valid]\ntest_blobhash_invalid_blob_index[fork=Cancun-scenario=invalid_calls]\ntest_blobhash_multiple_txs_in_block[fork=Cancun]\n

This output was extracted from the result of:

fill --collect-only -q --until Cancun tests/cancun/eip4844_blobs/test_blobhash_opcode.py\n
"},{"location":"tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts/","title":"Test Blobhash Opcode Contexts","text":"

Documentation for tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts.py.

Generate fixtures for these test cases for Cancun with:

Cancun only:

fill -v tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts.py --fork=Cancun --evm-bin=/path/to/evm-tool-dev-version\n
For all forks up to and including Cancun:
fill -v tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts.py --until=Cancun --evm-bin=/path/to/evm-tool-dev-version\n

Tests BLOBHASH opcode in EIP-4844: Shard Blob Transactions

Test case for BLOBHASH opcode calls across different contexts in EIP-4844: Shard Blob Transactions.

"},{"location":"tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts/#tests.cancun.eip4844_blobs.test_blobhash_opcode_contexts.Spec","title":"Spec dataclass","text":"

Parameters from the EIP-4844 specifications as defined at https://eips.ethereum.org/EIPS/eip-4844#parameters

If the parameter is not currently used within the tests, it is commented out.

Source code in tests/cancun/eip4844_blobs/spec.py
@dataclass(frozen=True)\nclass Spec:\n\"\"\"\n    Parameters from the EIP-4844 specifications as defined at\n    https://eips.ethereum.org/EIPS/eip-4844#parameters\n\n    If the parameter is not currently used within the tests, it is commented\n    out.\n    \"\"\"\n\n    BLOB_TX_TYPE = 0x03\n    FIELD_ELEMENTS_PER_BLOB = 4096\n    BLS_MODULUS = 0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001\n    BLOB_COMMITMENT_VERSION_KZG = 1\n    POINT_EVALUATION_PRECOMPILE_ADDRESS = 20\n    POINT_EVALUATION_PRECOMPILE_GAS = 50_000\n    MAX_DATA_GAS_PER_BLOCK = 786432\n    TARGET_DATA_GAS_PER_BLOCK = 393216\n    MIN_DATA_GASPRICE = 1\n    DATA_GASPRICE_UPDATE_FRACTION = 3338477\n    # MAX_VERSIONED_HASHES_LIST_SIZE = 2**24\n    # MAX_CALLDATA_SIZE = 2**24\n    # MAX_ACCESS_LIST_SIZE = 2**24\n    # MAX_ACCESS_LIST_STORAGE_KEYS = 2**24\n    # MAX_TX_WRAP_COMMITMENTS = 2**12\n    # LIMIT_BLOBS_PER_TX = 2**12\n    DATA_GAS_PER_BLOB = 2**17\n    HASH_OPCODE_BYTE = 0x49\n    HASH_GAS_COST = 3\n\n    @classmethod\n    def kzg_to_versioned_hash(\n        cls,\n        kzg_commitment: bytes | int,  # 48 bytes\n        blob_commitment_version_kzg: Optional[bytes | int] = None,\n    ) -> bytes:\n\"\"\"\n        Calculates the versioned hash for a given KZG commitment.\n        \"\"\"\n        if blob_commitment_version_kzg is None:\n            blob_commitment_version_kzg = cls.BLOB_COMMITMENT_VERSION_KZG\n        if isinstance(kzg_commitment, int):\n            kzg_commitment = kzg_commitment.to_bytes(48, \"big\")\n        if isinstance(blob_commitment_version_kzg, int):\n            blob_commitment_version_kzg = blob_commitment_version_kzg.to_bytes(1, \"big\")\n        return blob_commitment_version_kzg + sha256(kzg_commitment).digest()[1:]\n\n    @classmethod\n    def fake_exponential(cls, factor: int, numerator: int, denominator: int) -> int:\n\"\"\"\n        Used to calculate the data gas cost.\n        \"\"\"\n        i = 1\n        output = 0\n        numerator_accumulator = factor * denominator\n        while numerator_accumulator > 0:\n            output += numerator_accumulator\n            numerator_accumulator = (numerator_accumulator * numerator) // (denominator * i)\n            i += 1\n        return output // denominator\n\n    @classmethod\n    def calc_excess_data_gas(cls, parent: BlockHeaderDataGasFields) -> int:\n\"\"\"\n        Calculate the excess data gas for a block given the excess data gas\n        and data gas used from the parent block header.\n        \"\"\"\n        if parent.excess_data_gas + parent.data_gas_used < cls.TARGET_DATA_GAS_PER_BLOCK:\n            return 0\n        else:\n            return parent.excess_data_gas + parent.data_gas_used - cls.TARGET_DATA_GAS_PER_BLOCK\n\n    # Note: Currently unused.\n    # @classmethod\n    # def get_total_data_gas(cls, tx: Transaction) -> int:\n    #     \"\"\"\n    #     Calculate the total data gas for a transaction.\n    #     \"\"\"\n    #     if tx.blob_versioned_hashes is None:\n    #         return 0\n    #     return cls.DATA_GAS_PER_BLOB * len(tx.blob_versioned_hashes)\n\n    @classmethod\n    def get_data_gasprice(cls, *, excess_data_gas: int) -> int:\n\"\"\"\n        Calculate the data gas price from the excess.\n        \"\"\"\n        return cls.fake_exponential(\n            cls.MIN_DATA_GASPRICE,\n            excess_data_gas,\n            cls.DATA_GASPRICE_UPDATE_FRACTION,\n        )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts/#tests.cancun.eip4844_blobs.test_blobhash_opcode_contexts.SpecHelpers","title":"SpecHelpers dataclass","text":"

Define parameters and helper functions that are tightly coupled to the 4844 spec but not strictly part of it.

Source code in tests/cancun/eip4844_blobs/spec.py
@dataclass(frozen=True)\nclass SpecHelpers:\n\"\"\"\n    Define parameters and helper functions that are tightly coupled to the 4844\n    spec but not strictly part of it.\n    \"\"\"\n\n    BYTES_PER_FIELD_ELEMENT = 32\n\n    @classmethod\n    def max_blobs_per_block(cls) -> int:  # MAX_BLOBS_PER_BLOCK =\n\"\"\"\n        Returns the maximum number of blobs per block.\n        \"\"\"\n        return Spec.MAX_DATA_GAS_PER_BLOCK // Spec.DATA_GAS_PER_BLOB\n\n    @classmethod\n    def target_blobs_per_block(cls) -> int:\n\"\"\"\n        Returns the target number of blobs per block.\n        \"\"\"\n        return Spec.TARGET_DATA_GAS_PER_BLOCK // Spec.DATA_GAS_PER_BLOB\n\n    @classmethod\n    def calc_excess_data_gas_from_blob_count(\n        cls, parent_excess_data_gas: int, parent_blob_count: int\n    ) -> int:\n\"\"\"\n        Calculate the excess data gas for a block given the parent excess data gas\n        and the number of blobs in the block.\n        \"\"\"\n        parent_consumed_data_gas = parent_blob_count * Spec.DATA_GAS_PER_BLOB\n        return Spec.calc_excess_data_gas(\n            BlockHeaderDataGasFields(parent_excess_data_gas, parent_consumed_data_gas)\n        )\n\n    @classmethod\n    def get_min_excess_data_gas_for_data_gas_price(cls, data_gas_price: int) -> int:\n\"\"\"\n        Gets the minimum required excess data gas value to get a given data gas cost in a block\n        \"\"\"\n        current_excess_data_gas = 0\n        current_data_gas_price = 1\n        while current_data_gas_price < data_gas_price:\n            current_excess_data_gas += Spec.DATA_GAS_PER_BLOB\n            current_data_gas_price = Spec.get_data_gasprice(\n                excess_data_gas=current_excess_data_gas\n            )\n        return current_excess_data_gas\n\n    @classmethod\n    def get_min_excess_data_blobs_for_data_gas_price(cls, data_gas_price: int) -> int:\n\"\"\"\n        Gets the minimum required excess data blobs to get a given data gas cost in a block\n        \"\"\"\n        return (\n            cls.get_min_excess_data_gas_for_data_gas_price(data_gas_price)\n            // Spec.DATA_GAS_PER_BLOB\n        )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts/#tests.cancun.eip4844_blobs.test_blobhash_opcode_contexts.test_blobhash_opcode_contexts","title":"test_blobhash_opcode_contexts(opcode_context, blockchain_test)","text":"

Tests that the BLOBHASH opcode functions correctly when called in different contexts including:

  • BLOBHASH opcode on the top level of the call stack.
  • BLOBHASH opcode on the max value.
  • BLOBHASH opcode on CALL, DELEGATECALL, STATICCALL, and CALLCODE.
  • BLOBHASH opcode on Initcode.
  • BLOBHASH opcode on CREATE and CREATE2.
  • BLOBHASH opcode on transaction types 0, 1 and 2.
Source code in tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts.py
@pytest.mark.compile_yul_with(\"Shanghai\")\ndef test_blobhash_opcode_contexts(opcode_context, blockchain_test: BlockchainTestFiller):\n\"\"\"\n    Tests that the `BLOBHASH` opcode functions correctly when called in different\n    contexts including:\n\n    - `BLOBHASH` opcode on the top level of the call stack.\n    - `BLOBHASH` opcode on the max value.\n    - `BLOBHASH` opcode on `CALL`, `DELEGATECALL`, `STATICCALL`, and `CALLCODE`.\n    - `BLOBHASH` opcode on Initcode.\n    - `BLOBHASH` opcode on `CREATE` and `CREATE2`.\n    - `BLOBHASH` opcode on transaction types 0, 1 and 2.\n    \"\"\"\n    blockchain_test(\n        pre=opcode_context.get(\"pre\"),\n        blocks=[Block(txs=[opcode_context.get(\"tx\")])],\n        post=opcode_context.get(\"post\"),\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts/index/test_cases/","title":"Test Blobhash Opcode Contexts - Test Cases","text":"

Test cases generated from tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts.py

Parametrized test cases generated from the test module tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts.py:

test_blobhash_opcode_contexts[opcode_context=on_top_level_call_stack-fork=Cancun]\ntest_blobhash_opcode_contexts[opcode_context=on_max_value-fork=Cancun]\ntest_blobhash_opcode_contexts[opcode_context=on_CALL-fork=Cancun]\ntest_blobhash_opcode_contexts[opcode_context=on_DELEGATECALL-fork=Cancun]\ntest_blobhash_opcode_contexts[opcode_context=on_STATICCALL-fork=Cancun]\ntest_blobhash_opcode_contexts[opcode_context=on_CALLCODE-fork=Cancun]\ntest_blobhash_opcode_contexts[opcode_context=on_CREATE-fork=Cancun]\ntest_blobhash_opcode_contexts[opcode_context=on_CREATE2-fork=Cancun]\ntest_blobhash_opcode_contexts[opcode_context=on_type_2_tx-fork=Cancun]\ntest_blobhash_opcode_contexts[opcode_context=on_type_1_tx-fork=Cancun]\ntest_blobhash_opcode_contexts[opcode_context=on_type_0_tx-fork=Cancun]\n

This output was extracted from the result of:

fill --collect-only -q --until Cancun tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts.py\n
"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas/","title":"Test Excess Data Gas","text":"

Documentation for tests/cancun/eip4844_blobs/test_excess_data_gas.py.

Generate fixtures for these test cases for Cancun with:

Cancun only:

fill -v tests/cancun/eip4844_blobs/test_excess_data_gas.py --fork=Cancun --evm-bin=/path/to/evm-tool-dev-version\n
For all forks up to and including Cancun:
fill -v tests/cancun/eip4844_blobs/test_excess_data_gas.py --until=Cancun --evm-bin=/path/to/evm-tool-dev-version\n

Tests excessDataGas and dataGasUsed block fields for EIP-4844: Shard Blob Transactions

Test excessDataGas and dataGasUsed block fields for EIP-4844: Shard Blob Transactions.

Adding a new test

Add a function that is named test_<test_name> and takes at least the following arguments:

  • blockchain_test
  • env
  • pre
  • blocks
  • post
  • correct_excess_data_gas

The following arguments need to be parametrized or the test will not be generated:

  • new_blobs

All other pytest.fixture fixtures can be parametrized to generate new combinations and test cases.

"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas/#tests.cancun.eip4844_blobs.test_excess_data_gas.Spec","title":"Spec dataclass","text":"

Parameters from the EIP-4844 specifications as defined at https://eips.ethereum.org/EIPS/eip-4844#parameters

If the parameter is not currently used within the tests, it is commented out.

Source code in tests/cancun/eip4844_blobs/spec.py
@dataclass(frozen=True)\nclass Spec:\n\"\"\"\n    Parameters from the EIP-4844 specifications as defined at\n    https://eips.ethereum.org/EIPS/eip-4844#parameters\n\n    If the parameter is not currently used within the tests, it is commented\n    out.\n    \"\"\"\n\n    BLOB_TX_TYPE = 0x03\n    FIELD_ELEMENTS_PER_BLOB = 4096\n    BLS_MODULUS = 0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001\n    BLOB_COMMITMENT_VERSION_KZG = 1\n    POINT_EVALUATION_PRECOMPILE_ADDRESS = 20\n    POINT_EVALUATION_PRECOMPILE_GAS = 50_000\n    MAX_DATA_GAS_PER_BLOCK = 786432\n    TARGET_DATA_GAS_PER_BLOCK = 393216\n    MIN_DATA_GASPRICE = 1\n    DATA_GASPRICE_UPDATE_FRACTION = 3338477\n    # MAX_VERSIONED_HASHES_LIST_SIZE = 2**24\n    # MAX_CALLDATA_SIZE = 2**24\n    # MAX_ACCESS_LIST_SIZE = 2**24\n    # MAX_ACCESS_LIST_STORAGE_KEYS = 2**24\n    # MAX_TX_WRAP_COMMITMENTS = 2**12\n    # LIMIT_BLOBS_PER_TX = 2**12\n    DATA_GAS_PER_BLOB = 2**17\n    HASH_OPCODE_BYTE = 0x49\n    HASH_GAS_COST = 3\n\n    @classmethod\n    def kzg_to_versioned_hash(\n        cls,\n        kzg_commitment: bytes | int,  # 48 bytes\n        blob_commitment_version_kzg: Optional[bytes | int] = None,\n    ) -> bytes:\n\"\"\"\n        Calculates the versioned hash for a given KZG commitment.\n        \"\"\"\n        if blob_commitment_version_kzg is None:\n            blob_commitment_version_kzg = cls.BLOB_COMMITMENT_VERSION_KZG\n        if isinstance(kzg_commitment, int):\n            kzg_commitment = kzg_commitment.to_bytes(48, \"big\")\n        if isinstance(blob_commitment_version_kzg, int):\n            blob_commitment_version_kzg = blob_commitment_version_kzg.to_bytes(1, \"big\")\n        return blob_commitment_version_kzg + sha256(kzg_commitment).digest()[1:]\n\n    @classmethod\n    def fake_exponential(cls, factor: int, numerator: int, denominator: int) -> int:\n\"\"\"\n        Used to calculate the data gas cost.\n        \"\"\"\n        i = 1\n        output = 0\n        numerator_accumulator = factor * denominator\n        while numerator_accumulator > 0:\n            output += numerator_accumulator\n            numerator_accumulator = (numerator_accumulator * numerator) // (denominator * i)\n            i += 1\n        return output // denominator\n\n    @classmethod\n    def calc_excess_data_gas(cls, parent: BlockHeaderDataGasFields) -> int:\n\"\"\"\n        Calculate the excess data gas for a block given the excess data gas\n        and data gas used from the parent block header.\n        \"\"\"\n        if parent.excess_data_gas + parent.data_gas_used < cls.TARGET_DATA_GAS_PER_BLOCK:\n            return 0\n        else:\n            return parent.excess_data_gas + parent.data_gas_used - cls.TARGET_DATA_GAS_PER_BLOCK\n\n    # Note: Currently unused.\n    # @classmethod\n    # def get_total_data_gas(cls, tx: Transaction) -> int:\n    #     \"\"\"\n    #     Calculate the total data gas for a transaction.\n    #     \"\"\"\n    #     if tx.blob_versioned_hashes is None:\n    #         return 0\n    #     return cls.DATA_GAS_PER_BLOB * len(tx.blob_versioned_hashes)\n\n    @classmethod\n    def get_data_gasprice(cls, *, excess_data_gas: int) -> int:\n\"\"\"\n        Calculate the data gas price from the excess.\n        \"\"\"\n        return cls.fake_exponential(\n            cls.MIN_DATA_GASPRICE,\n            excess_data_gas,\n            cls.DATA_GASPRICE_UPDATE_FRACTION,\n        )\n
"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas/#tests.cancun.eip4844_blobs.test_excess_data_gas.SpecHelpers","title":"SpecHelpers dataclass","text":"

Define parameters and helper functions that are tightly coupled to the 4844 spec but not strictly part of it.

Source code in tests/cancun/eip4844_blobs/spec.py
@dataclass(frozen=True)\nclass SpecHelpers:\n\"\"\"\n    Define parameters and helper functions that are tightly coupled to the 4844\n    spec but not strictly part of it.\n    \"\"\"\n\n    BYTES_PER_FIELD_ELEMENT = 32\n\n    @classmethod\n    def max_blobs_per_block(cls) -> int:  # MAX_BLOBS_PER_BLOCK =\n\"\"\"\n        Returns the maximum number of blobs per block.\n        \"\"\"\n        return Spec.MAX_DATA_GAS_PER_BLOCK // Spec.DATA_GAS_PER_BLOB\n\n    @classmethod\n    def target_blobs_per_block(cls) -> int:\n\"\"\"\n        Returns the target number of blobs per block.\n        \"\"\"\n        return Spec.TARGET_DATA_GAS_PER_BLOCK // Spec.DATA_GAS_PER_BLOB\n\n    @classmethod\n    def calc_excess_data_gas_from_blob_count(\n        cls, parent_excess_data_gas: int, parent_blob_count: int\n    ) -> int:\n\"\"\"\n        Calculate the excess data gas for a block given the parent excess data gas\n        and the number of blobs in the block.\n        \"\"\"\n        parent_consumed_data_gas = parent_blob_count * Spec.DATA_GAS_PER_BLOB\n        return Spec.calc_excess_data_gas(\n            BlockHeaderDataGasFields(parent_excess_data_gas, parent_consumed_data_gas)\n        )\n\n    @classmethod\n    def get_min_excess_data_gas_for_data_gas_price(cls, data_gas_price: int) -> int:\n\"\"\"\n        Gets the minimum required excess data gas value to get a given data gas cost in a block\n        \"\"\"\n        current_excess_data_gas = 0\n        current_data_gas_price = 1\n        while current_data_gas_price < data_gas_price:\n            current_excess_data_gas += Spec.DATA_GAS_PER_BLOB\n            current_data_gas_price = Spec.get_data_gasprice(\n                excess_data_gas=current_excess_data_gas\n            )\n        return current_excess_data_gas\n\n    @classmethod\n    def get_min_excess_data_blobs_for_data_gas_price(cls, data_gas_price: int) -> int:\n\"\"\"\n        Gets the minimum required excess data blobs to get a given data gas cost in a block\n        \"\"\"\n        return (\n            cls.get_min_excess_data_gas_for_data_gas_price(data_gas_price)\n            // Spec.DATA_GAS_PER_BLOB\n        )\n
"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas/#tests.cancun.eip4844_blobs.test_excess_data_gas.test_correct_excess_data_gas_calculation","title":"test_correct_excess_data_gas_calculation(blockchain_test, env, pre, blocks, post, correct_excess_data_gas)","text":"

Test calculation of the excessDataGas increase/decrease across multiple blocks with and without blobs:

  • With parent block containing [0, MAX_BLOBS_PER_BLOCK] blobs
  • With parent block containing [0, TARGET_BLOBS_PER_BLOCK] equivalent value of excess data gas
Source code in tests/cancun/eip4844_blobs/test_excess_data_gas.py
@pytest.mark.parametrize(\"parent_blobs\", range(0, SpecHelpers.max_blobs_per_block() + 1))\n@pytest.mark.parametrize(\"parent_excess_blobs\", range(0, SpecHelpers.target_blobs_per_block() + 1))\n@pytest.mark.parametrize(\"new_blobs\", [1])\ndef test_correct_excess_data_gas_calculation(\n    blockchain_test: BlockchainTestFiller,\n    env: Environment,\n    pre: Mapping[str, Account],\n    blocks: List[Block],\n    post: Mapping[str, Account],\n    correct_excess_data_gas: int,\n):\n\"\"\"\n    Test calculation of the `excessDataGas` increase/decrease across\n    multiple blocks with and without blobs:\n\n    - With parent block containing `[0, MAX_BLOBS_PER_BLOCK]` blobs\n    - With parent block containing `[0, TARGET_BLOBS_PER_BLOCK]` equivalent value of excess data gas\n    \"\"\"  # noqa: E501\n    blockchain_test(\n        pre=pre,\n        post=post,\n        blocks=blocks,\n        genesis_environment=env,\n        tag=f\"expected_excess_data_gas:{hex(correct_excess_data_gas)}\",\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas/#tests.cancun.eip4844_blobs.test_excess_data_gas.test_correct_increasing_data_gas_costs","title":"test_correct_increasing_data_gas_costs(blockchain_test, env, pre, blocks, post, correct_excess_data_gas)","text":"

Test calculation of the excessDataGas and data gas tx costs at value points where the cost increases to interesting amounts:

  • At the first data gas cost increase (1 to 2)
  • At total transaction data cost increase to > 2^32
  • At data gas wei cost increase to > 2^32
  • At total transaction data cost increase to > 2^64
  • At data gas wei cost increase to > 2^64
  • At data gas wei cost increase of around current total Ether supply
Source code in tests/cancun/eip4844_blobs/test_excess_data_gas.py
@pytest.mark.parametrize(\n    \"parent_excess_blobs\",\n    [g - 1 for g in DATA_GAS_COST_INCREASES],\n)\n@pytest.mark.parametrize(\"parent_blobs\", [SpecHelpers.target_blobs_per_block() + 1])\n@pytest.mark.parametrize(\"new_blobs\", [1])\ndef test_correct_increasing_data_gas_costs(\n    blockchain_test: BlockchainTestFiller,\n    env: Environment,\n    pre: Mapping[str, Account],\n    blocks: List[Block],\n    post: Mapping[str, Account],\n    correct_excess_data_gas: int,\n):\n\"\"\"\n    Test calculation of the `excessDataGas` and data gas tx costs at\n    value points where the cost increases to interesting amounts:\n\n    - At the first data gas cost increase (1 to 2)\n    - At total transaction data cost increase to `> 2^32`\n    - At data gas wei cost increase to `> 2^32`\n    - At total transaction data cost increase to `> 2^64`\n    - At data gas wei cost increase to `> 2^64`\n    - At data gas wei cost increase of around current total Ether supply\n    \"\"\"\n    blockchain_test(\n        pre=pre,\n        post=post,\n        blocks=blocks,\n        genesis_environment=env,\n        tag=f\"expected_excess_data_gas:{hex(correct_excess_data_gas)}\",\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas/#tests.cancun.eip4844_blobs.test_excess_data_gas.test_correct_decreasing_data_gas_costs","title":"test_correct_decreasing_data_gas_costs(blockchain_test, env, pre, blocks, post, correct_excess_data_gas)","text":"

Test calculation of the excessDataGas and data gas tx costs at value points where the cost decreases to interesting amounts.

See test_correct_increasing_data_gas_costs.

Source code in tests/cancun/eip4844_blobs/test_excess_data_gas.py
@pytest.mark.parametrize(\n    \"parent_excess_blobs\",\n    [g for g in DATA_GAS_COST_INCREASES],\n)\n@pytest.mark.parametrize(\"parent_blobs\", [SpecHelpers.target_blobs_per_block() - 1])\n@pytest.mark.parametrize(\"new_blobs\", [1])\ndef test_correct_decreasing_data_gas_costs(\n    blockchain_test: BlockchainTestFiller,\n    env: Environment,\n    pre: Mapping[str, Account],\n    blocks: List[Block],\n    post: Mapping[str, Account],\n    correct_excess_data_gas: int,\n):\n\"\"\"\n    Test calculation of the `excessDataGas` and data gas tx costs at\n    value points where the cost decreases to interesting amounts.\n\n    See test_correct_increasing_data_gas_costs.\n    \"\"\"\n    blockchain_test(\n        pre=pre,\n        post=post,\n        blocks=blocks,\n        genesis_environment=env,\n        tag=f\"expected_excess_data_gas:{hex(correct_excess_data_gas)}\",\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas/#tests.cancun.eip4844_blobs.test_excess_data_gas.test_invalid_zero_excess_data_gas_in_header","title":"test_invalid_zero_excess_data_gas_in_header(blockchain_test, env, pre, blocks, correct_excess_data_gas, header_excess_data_gas)","text":"

Test rejection of blocks where the excessDataGas in the header drops to zero in a block with or without data blobs, but the excess blobs in the parent are greater than target.

Source code in tests/cancun/eip4844_blobs/test_excess_data_gas.py
@pytest.mark.parametrize(\"header_excess_data_gas\", [0])\n@pytest.mark.parametrize(\"new_blobs\", [0, 1])\n@pytest.mark.parametrize(\"parent_blobs\", range(0, SpecHelpers.max_blobs_per_block() + 1))\ndef test_invalid_zero_excess_data_gas_in_header(\n    blockchain_test: BlockchainTestFiller,\n    env: Environment,\n    pre: Mapping[str, Account],\n    blocks: List[Block],\n    correct_excess_data_gas: int,\n    header_excess_data_gas: Optional[int],\n):\n\"\"\"\n    Test rejection of blocks where the `excessDataGas` in the header drops to\n    zero in a block with or without data blobs, but the excess blobs in the parent are\n    greater than target.\n    \"\"\"\n    if header_excess_data_gas is None:\n        raise Exception(\"test case is badly formatted\")\n\n    if header_excess_data_gas == correct_excess_data_gas:\n        raise Exception(\"invalid test case\")\n\n    blockchain_test(\n        pre=pre,\n        post={},\n        blocks=blocks,\n        genesis_environment=env,\n        tag=\"-\".join(\n            [\n                f\"correct:{hex(correct_excess_data_gas)}\",\n                f\"header:{hex(header_excess_data_gas)}\",\n            ]\n        ),\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas/#tests.cancun.eip4844_blobs.test_excess_data_gas.test_invalid_data_gas_used_in_header","title":"test_invalid_data_gas_used_in_header(blockchain_test, env, pre, blocks, new_blobs, header_data_gas_used)","text":"

Test rejection of blocks where the dataGasUsed in the header is invalid:

  • dataGasUsed is not equal to the number of data blobs in the block
  • dataGasUsed is the max uint64 value
Source code in tests/cancun/eip4844_blobs/test_excess_data_gas.py
@pytest.mark.parametrize(\n    \"new_blobs,header_data_gas_used\",\n    all_invalid_data_gas_used_combinations(),\n)\n@pytest.mark.parametrize(\"parent_blobs\", [0])\ndef test_invalid_data_gas_used_in_header(\n    blockchain_test: BlockchainTestFiller,\n    env: Environment,\n    pre: Mapping[str, Account],\n    blocks: List[Block],\n    new_blobs: int,\n    header_data_gas_used: Optional[int],\n):\n\"\"\"\n    Test rejection of blocks where the `dataGasUsed` in the header is invalid:\n\n    - `dataGasUsed` is not equal to the number of data blobs in the block\n    - `dataGasUsed` is the max uint64 value\n    \"\"\"\n    if header_data_gas_used is None:\n        raise Exception(\"test case is badly formatted\")\n    blockchain_test(\n        pre=pre,\n        post={},\n        blocks=blocks,\n        genesis_environment=env,\n        tag=\"-\".join(\n            [\n                f\"correct:{hex(new_blobs *Spec.DATA_GAS_PER_BLOB)}\",\n                f\"header:{hex(header_data_gas_used)}\",\n            ]\n        ),\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas/#tests.cancun.eip4844_blobs.test_excess_data_gas.test_invalid_excess_data_gas_above_target_change","title":"test_invalid_excess_data_gas_above_target_change(blockchain_test, env, pre, blocks, correct_excess_data_gas, header_excess_data_gas)","text":"

Test rejection of blocks where the excessDataGas

  • decreases more than TARGET_DATA_GAS_PER_BLOCK in a single block with zero blobs
  • increases more than TARGET_DATA_GAS_PER_BLOCK in a single block with max blobs
Source code in tests/cancun/eip4844_blobs/test_excess_data_gas.py
@pytest.mark.parametrize(\n    \"header_excess_blobs_delta,parent_blobs\",\n    [\n        (-1, 0),\n        (+1, SpecHelpers.max_blobs_per_block()),\n    ],\n    ids=[\"zero_blobs_decrease_more_than_expected\", \"max_blobs_increase_more_than_expected\"],\n)\n@pytest.mark.parametrize(\"new_blobs\", [1])\ndef test_invalid_excess_data_gas_above_target_change(\n    blockchain_test: BlockchainTestFiller,\n    env: Environment,\n    pre: Mapping[str, Account],\n    blocks: List[Block],\n    correct_excess_data_gas: int,\n    header_excess_data_gas: Optional[int],\n):\n\"\"\"\n    Test rejection of blocks where the `excessDataGas`\n\n    - decreases more than `TARGET_DATA_GAS_PER_BLOCK` in a single block with zero blobs\n    - increases more than `TARGET_DATA_GAS_PER_BLOCK` in a single block with max blobs\n    \"\"\"\n    if header_excess_data_gas is None:\n        raise Exception(\"test case is badly formatted\")\n\n    if header_excess_data_gas == correct_excess_data_gas:\n        raise Exception(\"invalid test case\")\n\n    blockchain_test(\n        pre=pre,\n        post={},\n        blocks=blocks,\n        genesis_environment=env,\n        tag=\"-\".join(\n            [\n                f\"correct:{hex(correct_excess_data_gas)}\",\n                f\"header:{hex(header_excess_data_gas)}\",\n            ]\n        ),\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas/#tests.cancun.eip4844_blobs.test_excess_data_gas.test_invalid_static_excess_data_gas","title":"test_invalid_static_excess_data_gas(blockchain_test, env, pre, blocks, correct_excess_data_gas, parent_excess_data_gas)","text":"

Test rejection of blocks where the excessDataGas remains unchanged but the parent blobs included are not TARGET_BLOBS_PER_BLOCK.

Test is parametrized to MAX_BLOBS_PER_BLOCK and TARGET_BLOBS_PER_BLOCK.

Source code in tests/cancun/eip4844_blobs/test_excess_data_gas.py
@pytest.mark.parametrize(\n    \"parent_blobs\",\n    [\n        b\n        for b in range(0, SpecHelpers.max_blobs_per_block() + 1)\n        if b != SpecHelpers.target_blobs_per_block()\n    ],\n)\n@pytest.mark.parametrize(\"parent_excess_blobs\", [1, SpecHelpers.target_blobs_per_block()])\n@pytest.mark.parametrize(\"new_blobs\", [1])\ndef test_invalid_static_excess_data_gas(\n    blockchain_test: BlockchainTestFiller,\n    env: Environment,\n    pre: Mapping[str, Account],\n    blocks: List[Block],\n    correct_excess_data_gas: int,\n    parent_excess_data_gas: int,\n):\n\"\"\"\n    Test rejection of blocks where the `excessDataGas` remains unchanged\n    but the parent blobs included are not `TARGET_BLOBS_PER_BLOCK`.\n\n    Test is parametrized to `MAX_BLOBS_PER_BLOCK` and `TARGET_BLOBS_PER_BLOCK`.\n    \"\"\"\n    blocks[-1].rlp_modifier = Header(excess_data_gas=parent_excess_data_gas)\n    blocks[-1].exception = \"invalid excessDataGas\"\n    blockchain_test(\n        pre=pre,\n        post={},\n        blocks=blocks,\n        genesis_environment=env,\n        tag=\"-\".join(\n            [\n                f\"correct:{hex(correct_excess_data_gas)}\",\n                f\"header:{hex(parent_excess_data_gas)}\",\n            ]\n        ),\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas/#tests.cancun.eip4844_blobs.test_excess_data_gas.test_invalid_excess_data_gas_target_blobs_increase_from_zero","title":"test_invalid_excess_data_gas_target_blobs_increase_from_zero(blockchain_test, env, pre, blocks, correct_excess_data_gas, header_excess_data_gas)","text":"

Test rejection of blocks where the excessDataGas increases from zero, even when the included blobs are on or below target.

Test is parametrized according to [0, TARGET_BLOBS_PER_BLOCK new blobs.

Source code in tests/cancun/eip4844_blobs/test_excess_data_gas.py
@pytest.mark.parametrize(\"header_excess_blobs_delta\", range(1, SpecHelpers.max_blobs_per_block()))\n@pytest.mark.parametrize(\"parent_blobs\", range(0, SpecHelpers.target_blobs_per_block() + 1))\n@pytest.mark.parametrize(\"parent_excess_blobs\", [0])  # Start at 0\n@pytest.mark.parametrize(\"new_blobs\", [1])\ndef test_invalid_excess_data_gas_target_blobs_increase_from_zero(\n    blockchain_test: BlockchainTestFiller,\n    env: Environment,\n    pre: Mapping[str, Account],\n    blocks: List[Block],\n    correct_excess_data_gas: int,\n    header_excess_data_gas: Optional[int],\n):\n\"\"\"\n    Test rejection of blocks where the `excessDataGas` increases from zero,\n    even when the included blobs are on or below target.\n\n    Test is parametrized according to `[0, TARGET_BLOBS_PER_BLOCK` new blobs.\n    \"\"\"\n    if header_excess_data_gas is None:\n        raise Exception(\"test case is badly formatted\")\n\n    if header_excess_data_gas == correct_excess_data_gas:\n        raise Exception(\"invalid test case\")\n\n    blockchain_test(\n        pre=pre,\n        post={},\n        blocks=blocks,\n        genesis_environment=env,\n        tag=\"-\".join(\n            [\n                f\"correct:{hex(correct_excess_data_gas)}\",\n                f\"header:{hex(header_excess_data_gas)}\",\n            ]\n        ),\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas/#tests.cancun.eip4844_blobs.test_excess_data_gas.test_invalid_static_excess_data_gas_from_zero_on_blobs_above_target","title":"test_invalid_static_excess_data_gas_from_zero_on_blobs_above_target(blockchain_test, env, pre, blocks, correct_excess_data_gas, header_excess_data_gas)","text":"

Test rejection of blocks where the excessDataGas does not increase from zero, even when the included blobs is above target.

Test is parametrized to [TARGET_BLOBS_PER_BLOCK+1, MAX_BLOBS_PER_BLOCK] new blobs.

Source code in tests/cancun/eip4844_blobs/test_excess_data_gas.py
@pytest.mark.parametrize(\"header_excess_data_gas\", [0])\n@pytest.mark.parametrize(\n    \"parent_blobs\",\n    range(SpecHelpers.target_blobs_per_block() + 1, SpecHelpers.max_blobs_per_block() + 1),\n)\n@pytest.mark.parametrize(\"parent_excess_blobs\", [0])  # Start at 0\n@pytest.mark.parametrize(\"new_blobs\", [1])\ndef test_invalid_static_excess_data_gas_from_zero_on_blobs_above_target(\n    blockchain_test: BlockchainTestFiller,\n    env: Environment,\n    pre: Mapping[str, Account],\n    blocks: List[Block],\n    correct_excess_data_gas: int,\n    header_excess_data_gas: Optional[int],\n):\n\"\"\"\n    Test rejection of blocks where the `excessDataGas` does not increase from\n    zero, even when the included blobs is above target.\n\n    Test is parametrized to `[TARGET_BLOBS_PER_BLOCK+1, MAX_BLOBS_PER_BLOCK]` new blobs.\n    \"\"\"\n    if header_excess_data_gas is None:\n        raise Exception(\"test case is badly formatted\")\n\n    if header_excess_data_gas == correct_excess_data_gas:\n        raise Exception(\"invalid test case\")\n\n    blockchain_test(\n        pre=pre,\n        post={},\n        blocks=blocks,\n        genesis_environment=env,\n        tag=\"-\".join(\n            [\n                f\"correct:{hex(correct_excess_data_gas)}\",\n                f\"header:{hex(header_excess_data_gas)}\",\n            ]\n        ),\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas/#tests.cancun.eip4844_blobs.test_excess_data_gas.test_invalid_excess_data_gas_change","title":"test_invalid_excess_data_gas_change(blockchain_test, env, pre, blocks, correct_excess_data_gas, header_excess_data_gas)","text":"

Test rejection of blocks where the excessDataGas changes to an invalid value.

Given a parent block containing [0, MAX_BLOBS_PER_BLOCK] blobs, test an invalid excessDataGas value by changing it by [-TARGET_BLOBS_PER_BLOCK, TARGET_BLOBS_PER_BLOCK] from the correct value.

Source code in tests/cancun/eip4844_blobs/test_excess_data_gas.py
@pytest.mark.parametrize(\n    \"parent_blobs,header_excess_blobs_delta\",\n    itertools.product(\n        # parent_blobs\n        range(0, SpecHelpers.max_blobs_per_block() + 1),\n        # header_excess_blobs_delta (from correct value)\n        [\n            x\n            for x in range(\n                -SpecHelpers.target_blobs_per_block(), SpecHelpers.target_blobs_per_block() + 1\n            )\n            if x != 0\n        ],\n    ),\n)\n@pytest.mark.parametrize(\"new_blobs\", [1])\ndef test_invalid_excess_data_gas_change(\n    blockchain_test: BlockchainTestFiller,\n    env: Environment,\n    pre: Mapping[str, Account],\n    blocks: List[Block],\n    correct_excess_data_gas: int,\n    header_excess_data_gas: Optional[int],\n):\n\"\"\"\n    Test rejection of blocks where the `excessDataGas` changes to an invalid\n    value.\n\n    Given a parent block containing `[0, MAX_BLOBS_PER_BLOCK]` blobs, test an invalid\n    `excessDataGas` value by changing it by `[-TARGET_BLOBS_PER_BLOCK, TARGET_BLOBS_PER_BLOCK]`\n    from the correct value.\n    \"\"\"\n    if header_excess_data_gas is None:\n        raise Exception(\"test case is badly formatted\")\n\n    if header_excess_data_gas == correct_excess_data_gas:\n        raise Exception(\"invalid test case\")\n\n    blockchain_test(\n        pre=pre,\n        post={},\n        blocks=blocks,\n        genesis_environment=env,\n        tag=\"-\".join(\n            [\n                f\"correct:{hex(correct_excess_data_gas)}\",\n                f\"header:{hex(header_excess_data_gas)}\",\n            ]\n        ),\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas/#tests.cancun.eip4844_blobs.test_excess_data_gas.test_invalid_negative_excess_data_gas","title":"test_invalid_negative_excess_data_gas(blockchain_test, env, pre, blocks, correct_excess_data_gas, header_excess_data_gas)","text":"

Test rejection of blocks where the excessDataGas changes to the two's complement equivalent of the negative value after subtracting target blobs.

Reasoning is that the excessDataGas is a uint64, so it cannot be negative, and we test for a potential underflow here.

Source code in tests/cancun/eip4844_blobs/test_excess_data_gas.py
@pytest.mark.parametrize(\n    \"header_excess_data_gas\",\n    [\n        (2**64 + (x * Spec.DATA_GAS_PER_BLOB))\n        for x in range(-SpecHelpers.target_blobs_per_block(), 0)\n    ],\n)\n@pytest.mark.parametrize(\"parent_blobs\", range(SpecHelpers.target_blobs_per_block()))\n@pytest.mark.parametrize(\"new_blobs\", [1])\n@pytest.mark.parametrize(\"parent_excess_blobs\", range(SpecHelpers.target_blobs_per_block()))\ndef test_invalid_negative_excess_data_gas(\n    blockchain_test: BlockchainTestFiller,\n    env: Environment,\n    pre: Mapping[str, Account],\n    blocks: List[Block],\n    correct_excess_data_gas: int,\n    header_excess_data_gas: Optional[int],\n):\n\"\"\"\n    Test rejection of blocks where the `excessDataGas` changes to the two's\n    complement equivalent of the negative value after subtracting target blobs.\n\n    Reasoning is that the `excessDataGas` is a `uint64`, so it cannot be negative, and\n    we test for a potential underflow here.\n    \"\"\"\n    if header_excess_data_gas is None:\n        raise Exception(\"test case is badly formatted\")\n\n    if header_excess_data_gas == correct_excess_data_gas:\n        raise Exception(\"invalid test case\")\n\n    blockchain_test(\n        pre=pre,\n        post={},\n        blocks=blocks,\n        genesis_environment=env,\n        tag=\"-\".join(\n            [\n                f\"correct:{hex(correct_excess_data_gas)}\",\n                f\"header:{hex(header_excess_data_gas)}\",\n            ]\n        ),\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas/#tests.cancun.eip4844_blobs.test_excess_data_gas.test_invalid_non_multiple_excess_data_gas","title":"test_invalid_non_multiple_excess_data_gas(blockchain_test, env, pre, blocks, correct_excess_data_gas, header_excess_data_gas)","text":"

Test rejection of blocks where the excessDataGas changes to a value that is not a multiple of Spec.DATA_GAS_PER_BLOB`:

  • Parent block contains TARGET_BLOBS_PER_BLOCK + 1 blobs, but excessDataGas is off by \u00b11
  • Parent block contains TARGET_BLOBS_PER_BLOCK - 1 blobs, but excessDataGas is off by \u00b11
Source code in tests/cancun/eip4844_blobs/test_excess_data_gas.py
@pytest.mark.parametrize(\n    \"parent_blobs,header_excess_data_gas_delta\",\n    [\n        (SpecHelpers.target_blobs_per_block() + 1, 1),\n        (SpecHelpers.target_blobs_per_block() + 1, Spec.DATA_GAS_PER_BLOB - 1),\n        (SpecHelpers.target_blobs_per_block() - 1, -1),\n        (SpecHelpers.target_blobs_per_block() - 1, -(Spec.DATA_GAS_PER_BLOB - 1)),\n    ],\n)\n@pytest.mark.parametrize(\"new_blobs\", [1])\n@pytest.mark.parametrize(\"parent_excess_blobs\", [SpecHelpers.target_blobs_per_block() + 1])\ndef test_invalid_non_multiple_excess_data_gas(\n    blockchain_test: BlockchainTestFiller,\n    env: Environment,\n    pre: Mapping[str, Account],\n    blocks: List[Block],\n    correct_excess_data_gas: int,\n    header_excess_data_gas: Optional[int],\n):\n\"\"\"\n    Test rejection of blocks where the `excessDataGas` changes to a value that\n    is not a multiple of Spec.DATA_GAS_PER_BLOB`:\n\n    - Parent block contains `TARGET_BLOBS_PER_BLOCK + 1` blobs, but `excessDataGas` is off by +/-1\n    - Parent block contains `TARGET_BLOBS_PER_BLOCK - 1` blobs, but `excessDataGas` is off by +/-1\n    \"\"\"\n    if header_excess_data_gas is None:\n        raise Exception(\"test case is badly formatted\")\n\n    if header_excess_data_gas == correct_excess_data_gas:\n        raise Exception(\"invalid test case\")\n\n    blockchain_test(\n        pre=pre,\n        post={},\n        blocks=blocks,\n        genesis_environment=env,\n        tag=\"-\".join(\n            [\n                f\"correct:{hex(correct_excess_data_gas)}\",\n                f\"header:{hex(header_excess_data_gas)}\",\n            ]\n        ),\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas/index/test_cases/","title":"Test Excess Data Gas - Test Cases","text":"

Test cases generated from tests/cancun/eip4844_blobs/test_excess_data_gas.py

Parametrized test cases generated from the test module tests/cancun/eip4844_blobs/test_excess_data_gas.py:

test_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=0]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=1]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=2]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=3]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=4]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=5]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=6]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=1-parent_blobs=0]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=1-parent_blobs=1]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=1-parent_blobs=2]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=1-parent_blobs=3]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=1-parent_blobs=4]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=1-parent_blobs=5]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=1-parent_blobs=6]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=2-parent_blobs=0]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=2-parent_blobs=1]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=2-parent_blobs=2]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=2-parent_blobs=3]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=2-parent_blobs=4]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=2-parent_blobs=5]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=2-parent_blobs=6]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=3-parent_blobs=0]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=3-parent_blobs=1]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=3-parent_blobs=2]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=3-parent_blobs=3]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=3-parent_blobs=4]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=3-parent_blobs=5]\ntest_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=3-parent_blobs=6]\ntest_correct_increasing_data_gas_costs[fork=Cancun-new_blobs=1-parent_blobs=4-parent_excess_blobs=17]\ntest_correct_increasing_data_gas_costs[fork=Cancun-new_blobs=1-parent_blobs=4-parent_excess_blobs=264]\ntest_correct_increasing_data_gas_costs[fork=Cancun-new_blobs=1-parent_blobs=4-parent_excess_blobs=564]\ntest_correct_increasing_data_gas_costs[fork=Cancun-new_blobs=1-parent_blobs=4-parent_excess_blobs=829]\ntest_correct_increasing_data_gas_costs[fork=Cancun-new_blobs=1-parent_blobs=4-parent_excess_blobs=1129]\ntest_correct_increasing_data_gas_costs[fork=Cancun-new_blobs=1-parent_blobs=4-parent_excess_blobs=1229]\ntest_correct_decreasing_data_gas_costs[fork=Cancun-new_blobs=1-parent_blobs=2-parent_excess_blobs=18]\ntest_correct_decreasing_data_gas_costs[fork=Cancun-new_blobs=1-parent_blobs=2-parent_excess_blobs=265]\ntest_correct_decreasing_data_gas_costs[fork=Cancun-new_blobs=1-parent_blobs=2-parent_excess_blobs=565]\ntest_correct_decreasing_data_gas_costs[fork=Cancun-new_blobs=1-parent_blobs=2-parent_excess_blobs=830]\ntest_correct_decreasing_data_gas_costs[fork=Cancun-new_blobs=1-parent_blobs=2-parent_excess_blobs=1130]\ntest_correct_decreasing_data_gas_costs[fork=Cancun-new_blobs=1-parent_blobs=2-parent_excess_blobs=1230]\ntest_invalid_zero_excess_data_gas_in_header[fork=Cancun-parent_blobs=0-new_blobs=0-header_excess_data_gas=0]\ntest_invalid_zero_excess_data_gas_in_header[fork=Cancun-parent_blobs=0-new_blobs=1-header_excess_data_gas=0]\ntest_invalid_zero_excess_data_gas_in_header[fork=Cancun-parent_blobs=1-new_blobs=0-header_excess_data_gas=0]\ntest_invalid_zero_excess_data_gas_in_header[fork=Cancun-parent_blobs=1-new_blobs=1-header_excess_data_gas=0]\ntest_invalid_zero_excess_data_gas_in_header[fork=Cancun-parent_blobs=2-new_blobs=0-header_excess_data_gas=0]\ntest_invalid_zero_excess_data_gas_in_header[fork=Cancun-parent_blobs=2-new_blobs=1-header_excess_data_gas=0]\ntest_invalid_zero_excess_data_gas_in_header[fork=Cancun-parent_blobs=3-new_blobs=0-header_excess_data_gas=0]\ntest_invalid_zero_excess_data_gas_in_header[fork=Cancun-parent_blobs=3-new_blobs=1-header_excess_data_gas=0]\ntest_invalid_zero_excess_data_gas_in_header[fork=Cancun-parent_blobs=4-new_blobs=0-header_excess_data_gas=0]\ntest_invalid_zero_excess_data_gas_in_header[fork=Cancun-parent_blobs=4-new_blobs=1-header_excess_data_gas=0]\ntest_invalid_zero_excess_data_gas_in_header[fork=Cancun-parent_blobs=5-new_blobs=0-header_excess_data_gas=0]\ntest_invalid_zero_excess_data_gas_in_header[fork=Cancun-parent_blobs=5-new_blobs=1-header_excess_data_gas=0]\ntest_invalid_zero_excess_data_gas_in_header[fork=Cancun-parent_blobs=6-new_blobs=0-header_excess_data_gas=0]\ntest_invalid_zero_excess_data_gas_in_header[fork=Cancun-parent_blobs=6-new_blobs=1-header_excess_data_gas=0]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=0-header_data_gas_used=131072]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=0-header_data_gas_used=262144]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=0-header_data_gas_used=393216]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=0-header_data_gas_used=524288]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=0-header_data_gas_used=655360]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=0-header_data_gas_used=786432]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=0-header_data_gas_used=18446744073709551615]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=1-header_data_gas_used=0]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=1-header_data_gas_used=262144]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=1-header_data_gas_used=393216]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=1-header_data_gas_used=524288]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=1-header_data_gas_used=655360]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=1-header_data_gas_used=786432]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=1-header_data_gas_used=18446744073709551615]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=2-header_data_gas_used=0]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=2-header_data_gas_used=131072]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=2-header_data_gas_used=393216]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=2-header_data_gas_used=524288]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=2-header_data_gas_used=655360]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=2-header_data_gas_used=786432]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=2-header_data_gas_used=18446744073709551615]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=3-header_data_gas_used=0]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=3-header_data_gas_used=131072]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=3-header_data_gas_used=262144]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=3-header_data_gas_used=524288]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=3-header_data_gas_used=655360]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=3-header_data_gas_used=786432]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=3-header_data_gas_used=18446744073709551615]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=4-header_data_gas_used=0]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=4-header_data_gas_used=131072]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=4-header_data_gas_used=262144]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=4-header_data_gas_used=393216]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=4-header_data_gas_used=655360]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=4-header_data_gas_used=786432]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=4-header_data_gas_used=18446744073709551615]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=5-header_data_gas_used=0]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=5-header_data_gas_used=131072]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=5-header_data_gas_used=262144]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=5-header_data_gas_used=393216]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=5-header_data_gas_used=524288]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=5-header_data_gas_used=786432]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=5-header_data_gas_used=18446744073709551615]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=6-header_data_gas_used=0]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=6-header_data_gas_used=131072]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=6-header_data_gas_used=262144]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=6-header_data_gas_used=393216]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=6-header_data_gas_used=524288]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=6-header_data_gas_used=655360]\ntest_invalid_data_gas_used_in_header[fork=Cancun-parent_blobs=0-new_blobs=6-header_data_gas_used=18446744073709551615]\ntest_invalid_excess_data_gas_above_target_change[fork=Cancun-new_blobs=1-zero_blobs_decrease_more_than_expected]\ntest_invalid_excess_data_gas_above_target_change[fork=Cancun-new_blobs=1-max_blobs_increase_more_than_expected]\ntest_invalid_static_excess_data_gas[fork=Cancun-new_blobs=1-parent_excess_blobs=1-parent_blobs=0]\ntest_invalid_static_excess_data_gas[fork=Cancun-new_blobs=1-parent_excess_blobs=1-parent_blobs=1]\ntest_invalid_static_excess_data_gas[fork=Cancun-new_blobs=1-parent_excess_blobs=1-parent_blobs=2]\ntest_invalid_static_excess_data_gas[fork=Cancun-new_blobs=1-parent_excess_blobs=1-parent_blobs=4]\ntest_invalid_static_excess_data_gas[fork=Cancun-new_blobs=1-parent_excess_blobs=1-parent_blobs=5]\ntest_invalid_static_excess_data_gas[fork=Cancun-new_blobs=1-parent_excess_blobs=1-parent_blobs=6]\ntest_invalid_static_excess_data_gas[fork=Cancun-new_blobs=1-parent_excess_blobs=3-parent_blobs=0]\ntest_invalid_static_excess_data_gas[fork=Cancun-new_blobs=1-parent_excess_blobs=3-parent_blobs=1]\ntest_invalid_static_excess_data_gas[fork=Cancun-new_blobs=1-parent_excess_blobs=3-parent_blobs=2]\ntest_invalid_static_excess_data_gas[fork=Cancun-new_blobs=1-parent_excess_blobs=3-parent_blobs=4]\ntest_invalid_static_excess_data_gas[fork=Cancun-new_blobs=1-parent_excess_blobs=3-parent_blobs=5]\ntest_invalid_static_excess_data_gas[fork=Cancun-new_blobs=1-parent_excess_blobs=3-parent_blobs=6]\ntest_invalid_excess_data_gas_target_blobs_increase_from_zero[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=0-header_excess_blobs_delta=1]\ntest_invalid_excess_data_gas_target_blobs_increase_from_zero[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=0-header_excess_blobs_delta=2]\ntest_invalid_excess_data_gas_target_blobs_increase_from_zero[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=0-header_excess_blobs_delta=3]\ntest_invalid_excess_data_gas_target_blobs_increase_from_zero[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=0-header_excess_blobs_delta=4]\ntest_invalid_excess_data_gas_target_blobs_increase_from_zero[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=0-header_excess_blobs_delta=5]\ntest_invalid_excess_data_gas_target_blobs_increase_from_zero[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=1-header_excess_blobs_delta=1]\ntest_invalid_excess_data_gas_target_blobs_increase_from_zero[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=1-header_excess_blobs_delta=2]\ntest_invalid_excess_data_gas_target_blobs_increase_from_zero[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=1-header_excess_blobs_delta=3]\ntest_invalid_excess_data_gas_target_blobs_increase_from_zero[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=1-header_excess_blobs_delta=4]\ntest_invalid_excess_data_gas_target_blobs_increase_from_zero[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=1-header_excess_blobs_delta=5]\ntest_invalid_excess_data_gas_target_blobs_increase_from_zero[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=2-header_excess_blobs_delta=1]\ntest_invalid_excess_data_gas_target_blobs_increase_from_zero[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=2-header_excess_blobs_delta=2]\ntest_invalid_excess_data_gas_target_blobs_increase_from_zero[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=2-header_excess_blobs_delta=3]\ntest_invalid_excess_data_gas_target_blobs_increase_from_zero[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=2-header_excess_blobs_delta=4]\ntest_invalid_excess_data_gas_target_blobs_increase_from_zero[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=2-header_excess_blobs_delta=5]\ntest_invalid_excess_data_gas_target_blobs_increase_from_zero[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=3-header_excess_blobs_delta=1]\ntest_invalid_excess_data_gas_target_blobs_increase_from_zero[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=3-header_excess_blobs_delta=2]\ntest_invalid_excess_data_gas_target_blobs_increase_from_zero[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=3-header_excess_blobs_delta=3]\ntest_invalid_excess_data_gas_target_blobs_increase_from_zero[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=3-header_excess_blobs_delta=4]\ntest_invalid_excess_data_gas_target_blobs_increase_from_zero[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=3-header_excess_blobs_delta=5]\ntest_invalid_static_excess_data_gas_from_zero_on_blobs_above_target[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=4-header_excess_data_gas=0]\ntest_invalid_static_excess_data_gas_from_zero_on_blobs_above_target[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=5-header_excess_data_gas=0]\ntest_invalid_static_excess_data_gas_from_zero_on_blobs_above_target[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=6-header_excess_data_gas=0]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=0-header_excess_blobs_delta=-3]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=0-header_excess_blobs_delta=-2]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=0-header_excess_blobs_delta=-1]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=0-header_excess_blobs_delta=1]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=0-header_excess_blobs_delta=2]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=0-header_excess_blobs_delta=3]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=1-header_excess_blobs_delta=-3]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=1-header_excess_blobs_delta=-2]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=1-header_excess_blobs_delta=-1]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=1-header_excess_blobs_delta=1]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=1-header_excess_blobs_delta=2]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=1-header_excess_blobs_delta=3]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=2-header_excess_blobs_delta=-3]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=2-header_excess_blobs_delta=-2]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=2-header_excess_blobs_delta=-1]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=2-header_excess_blobs_delta=1]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=2-header_excess_blobs_delta=2]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=2-header_excess_blobs_delta=3]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=3-header_excess_blobs_delta=-3]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=3-header_excess_blobs_delta=-2]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=3-header_excess_blobs_delta=-1]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=3-header_excess_blobs_delta=1]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=3-header_excess_blobs_delta=2]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=3-header_excess_blobs_delta=3]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=4-header_excess_blobs_delta=-3]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=4-header_excess_blobs_delta=-2]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=4-header_excess_blobs_delta=-1]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=4-header_excess_blobs_delta=1]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=4-header_excess_blobs_delta=2]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=4-header_excess_blobs_delta=3]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=5-header_excess_blobs_delta=-3]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=5-header_excess_blobs_delta=-2]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=5-header_excess_blobs_delta=-1]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=5-header_excess_blobs_delta=1]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=5-header_excess_blobs_delta=2]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=5-header_excess_blobs_delta=3]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=6-header_excess_blobs_delta=-3]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=6-header_excess_blobs_delta=-2]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=6-header_excess_blobs_delta=-1]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=6-header_excess_blobs_delta=1]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=6-header_excess_blobs_delta=2]\ntest_invalid_excess_data_gas_change[fork=Cancun-new_blobs=1-parent_blobs=6-header_excess_blobs_delta=3]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=0-new_blobs=1-parent_blobs=0-header_excess_data_gas=18446744073709158400]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=0-new_blobs=1-parent_blobs=0-header_excess_data_gas=18446744073709289472]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=0-new_blobs=1-parent_blobs=0-header_excess_data_gas=18446744073709420544]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=0-new_blobs=1-parent_blobs=1-header_excess_data_gas=18446744073709158400]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=0-new_blobs=1-parent_blobs=1-header_excess_data_gas=18446744073709289472]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=0-new_blobs=1-parent_blobs=1-header_excess_data_gas=18446744073709420544]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=0-new_blobs=1-parent_blobs=2-header_excess_data_gas=18446744073709158400]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=0-new_blobs=1-parent_blobs=2-header_excess_data_gas=18446744073709289472]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=0-new_blobs=1-parent_blobs=2-header_excess_data_gas=18446744073709420544]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=1-new_blobs=1-parent_blobs=0-header_excess_data_gas=18446744073709158400]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=1-new_blobs=1-parent_blobs=0-header_excess_data_gas=18446744073709289472]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=1-new_blobs=1-parent_blobs=0-header_excess_data_gas=18446744073709420544]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=1-new_blobs=1-parent_blobs=1-header_excess_data_gas=18446744073709158400]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=1-new_blobs=1-parent_blobs=1-header_excess_data_gas=18446744073709289472]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=1-new_blobs=1-parent_blobs=1-header_excess_data_gas=18446744073709420544]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=1-new_blobs=1-parent_blobs=2-header_excess_data_gas=18446744073709158400]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=1-new_blobs=1-parent_blobs=2-header_excess_data_gas=18446744073709289472]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=1-new_blobs=1-parent_blobs=2-header_excess_data_gas=18446744073709420544]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=2-new_blobs=1-parent_blobs=0-header_excess_data_gas=18446744073709158400]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=2-new_blobs=1-parent_blobs=0-header_excess_data_gas=18446744073709289472]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=2-new_blobs=1-parent_blobs=0-header_excess_data_gas=18446744073709420544]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=2-new_blobs=1-parent_blobs=1-header_excess_data_gas=18446744073709158400]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=2-new_blobs=1-parent_blobs=1-header_excess_data_gas=18446744073709289472]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=2-new_blobs=1-parent_blobs=1-header_excess_data_gas=18446744073709420544]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=2-new_blobs=1-parent_blobs=2-header_excess_data_gas=18446744073709158400]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=2-new_blobs=1-parent_blobs=2-header_excess_data_gas=18446744073709289472]\ntest_invalid_negative_excess_data_gas[fork=Cancun-parent_excess_blobs=2-new_blobs=1-parent_blobs=2-header_excess_data_gas=18446744073709420544]\ntest_invalid_non_multiple_excess_data_gas[fork=Cancun-parent_excess_blobs=4-new_blobs=1-parent_blobs=4-header_excess_data_gas_delta=1]\ntest_invalid_non_multiple_excess_data_gas[fork=Cancun-parent_excess_blobs=4-new_blobs=1-parent_blobs=4-header_excess_data_gas_delta=131071]\ntest_invalid_non_multiple_excess_data_gas[fork=Cancun-parent_excess_blobs=4-new_blobs=1-parent_blobs=2-header_excess_data_gas_delta=-1]\ntest_invalid_non_multiple_excess_data_gas[fork=Cancun-parent_excess_blobs=4-new_blobs=1-parent_blobs=2-header_excess_data_gas_delta=-131071]\n

This output was extracted from the result of:

fill --collect-only -q --until Cancun tests/cancun/eip4844_blobs/test_excess_data_gas.py\n
"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition/","title":"Test Excess Data Gas Fork Transition","text":"

Documentation for tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition.py.

Generate fixtures for these test cases for Cancun with:

Cancun only:

fill -v tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition.py --fork=Cancun --evm-bin=/path/to/evm-tool-dev-version\n
For all forks up to and including Cancun:
fill -v tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition.py --until=Cancun --evm-bin=/path/to/evm-tool-dev-version\n

Tests excessDataGas and dataGasUsed block fields for EIP-4844: Shard Blob Transactions at fork transition.

Test excessDataGas and dataGasUsed block fields for EIP-4844: Shard Blob Transactions at fork transition.

"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition/#tests.cancun.eip4844_blobs.test_excess_data_gas_fork_transition.Spec","title":"Spec dataclass","text":"

Parameters from the EIP-4844 specifications as defined at https://eips.ethereum.org/EIPS/eip-4844#parameters

If the parameter is not currently used within the tests, it is commented out.

Source code in tests/cancun/eip4844_blobs/spec.py
@dataclass(frozen=True)\nclass Spec:\n\"\"\"\n    Parameters from the EIP-4844 specifications as defined at\n    https://eips.ethereum.org/EIPS/eip-4844#parameters\n\n    If the parameter is not currently used within the tests, it is commented\n    out.\n    \"\"\"\n\n    BLOB_TX_TYPE = 0x03\n    FIELD_ELEMENTS_PER_BLOB = 4096\n    BLS_MODULUS = 0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001\n    BLOB_COMMITMENT_VERSION_KZG = 1\n    POINT_EVALUATION_PRECOMPILE_ADDRESS = 20\n    POINT_EVALUATION_PRECOMPILE_GAS = 50_000\n    MAX_DATA_GAS_PER_BLOCK = 786432\n    TARGET_DATA_GAS_PER_BLOCK = 393216\n    MIN_DATA_GASPRICE = 1\n    DATA_GASPRICE_UPDATE_FRACTION = 3338477\n    # MAX_VERSIONED_HASHES_LIST_SIZE = 2**24\n    # MAX_CALLDATA_SIZE = 2**24\n    # MAX_ACCESS_LIST_SIZE = 2**24\n    # MAX_ACCESS_LIST_STORAGE_KEYS = 2**24\n    # MAX_TX_WRAP_COMMITMENTS = 2**12\n    # LIMIT_BLOBS_PER_TX = 2**12\n    DATA_GAS_PER_BLOB = 2**17\n    HASH_OPCODE_BYTE = 0x49\n    HASH_GAS_COST = 3\n\n    @classmethod\n    def kzg_to_versioned_hash(\n        cls,\n        kzg_commitment: bytes | int,  # 48 bytes\n        blob_commitment_version_kzg: Optional[bytes | int] = None,\n    ) -> bytes:\n\"\"\"\n        Calculates the versioned hash for a given KZG commitment.\n        \"\"\"\n        if blob_commitment_version_kzg is None:\n            blob_commitment_version_kzg = cls.BLOB_COMMITMENT_VERSION_KZG\n        if isinstance(kzg_commitment, int):\n            kzg_commitment = kzg_commitment.to_bytes(48, \"big\")\n        if isinstance(blob_commitment_version_kzg, int):\n            blob_commitment_version_kzg = blob_commitment_version_kzg.to_bytes(1, \"big\")\n        return blob_commitment_version_kzg + sha256(kzg_commitment).digest()[1:]\n\n    @classmethod\n    def fake_exponential(cls, factor: int, numerator: int, denominator: int) -> int:\n\"\"\"\n        Used to calculate the data gas cost.\n        \"\"\"\n        i = 1\n        output = 0\n        numerator_accumulator = factor * denominator\n        while numerator_accumulator > 0:\n            output += numerator_accumulator\n            numerator_accumulator = (numerator_accumulator * numerator) // (denominator * i)\n            i += 1\n        return output // denominator\n\n    @classmethod\n    def calc_excess_data_gas(cls, parent: BlockHeaderDataGasFields) -> int:\n\"\"\"\n        Calculate the excess data gas for a block given the excess data gas\n        and data gas used from the parent block header.\n        \"\"\"\n        if parent.excess_data_gas + parent.data_gas_used < cls.TARGET_DATA_GAS_PER_BLOCK:\n            return 0\n        else:\n            return parent.excess_data_gas + parent.data_gas_used - cls.TARGET_DATA_GAS_PER_BLOCK\n\n    # Note: Currently unused.\n    # @classmethod\n    # def get_total_data_gas(cls, tx: Transaction) -> int:\n    #     \"\"\"\n    #     Calculate the total data gas for a transaction.\n    #     \"\"\"\n    #     if tx.blob_versioned_hashes is None:\n    #         return 0\n    #     return cls.DATA_GAS_PER_BLOB * len(tx.blob_versioned_hashes)\n\n    @classmethod\n    def get_data_gasprice(cls, *, excess_data_gas: int) -> int:\n\"\"\"\n        Calculate the data gas price from the excess.\n        \"\"\"\n        return cls.fake_exponential(\n            cls.MIN_DATA_GASPRICE,\n            excess_data_gas,\n            cls.DATA_GASPRICE_UPDATE_FRACTION,\n        )\n
"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition/#tests.cancun.eip4844_blobs.test_excess_data_gas_fork_transition.SpecHelpers","title":"SpecHelpers dataclass","text":"

Define parameters and helper functions that are tightly coupled to the 4844 spec but not strictly part of it.

Source code in tests/cancun/eip4844_blobs/spec.py
@dataclass(frozen=True)\nclass SpecHelpers:\n\"\"\"\n    Define parameters and helper functions that are tightly coupled to the 4844\n    spec but not strictly part of it.\n    \"\"\"\n\n    BYTES_PER_FIELD_ELEMENT = 32\n\n    @classmethod\n    def max_blobs_per_block(cls) -> int:  # MAX_BLOBS_PER_BLOCK =\n\"\"\"\n        Returns the maximum number of blobs per block.\n        \"\"\"\n        return Spec.MAX_DATA_GAS_PER_BLOCK // Spec.DATA_GAS_PER_BLOB\n\n    @classmethod\n    def target_blobs_per_block(cls) -> int:\n\"\"\"\n        Returns the target number of blobs per block.\n        \"\"\"\n        return Spec.TARGET_DATA_GAS_PER_BLOCK // Spec.DATA_GAS_PER_BLOB\n\n    @classmethod\n    def calc_excess_data_gas_from_blob_count(\n        cls, parent_excess_data_gas: int, parent_blob_count: int\n    ) -> int:\n\"\"\"\n        Calculate the excess data gas for a block given the parent excess data gas\n        and the number of blobs in the block.\n        \"\"\"\n        parent_consumed_data_gas = parent_blob_count * Spec.DATA_GAS_PER_BLOB\n        return Spec.calc_excess_data_gas(\n            BlockHeaderDataGasFields(parent_excess_data_gas, parent_consumed_data_gas)\n        )\n\n    @classmethod\n    def get_min_excess_data_gas_for_data_gas_price(cls, data_gas_price: int) -> int:\n\"\"\"\n        Gets the minimum required excess data gas value to get a given data gas cost in a block\n        \"\"\"\n        current_excess_data_gas = 0\n        current_data_gas_price = 1\n        while current_data_gas_price < data_gas_price:\n            current_excess_data_gas += Spec.DATA_GAS_PER_BLOB\n            current_data_gas_price = Spec.get_data_gasprice(\n                excess_data_gas=current_excess_data_gas\n            )\n        return current_excess_data_gas\n\n    @classmethod\n    def get_min_excess_data_blobs_for_data_gas_price(cls, data_gas_price: int) -> int:\n\"\"\"\n        Gets the minimum required excess data blobs to get a given data gas cost in a block\n        \"\"\"\n        return (\n            cls.get_min_excess_data_gas_for_data_gas_price(data_gas_price)\n            // Spec.DATA_GAS_PER_BLOB\n        )\n
"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition/#tests.cancun.eip4844_blobs.test_excess_data_gas_fork_transition.test_invalid_pre_fork_block_with_blob_fields","title":"test_invalid_pre_fork_block_with_blob_fields(blockchain_test, env, pre, pre_fork_blocks, excess_data_gas_present, data_gas_used_present)","text":"

Test block rejection when excessDataGas and/or dataGasUsed fields are present on a pre-fork block.

Source code in tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition.py
@pytest.mark.parametrize(\n    \"excess_data_gas_present,data_gas_used_present\",\n    [\n        (True, False),\n        (False, True),\n        (True, True),\n    ],\n)\ndef test_invalid_pre_fork_block_with_blob_fields(\n    blockchain_test: BlockchainTestFiller,\n    env: Environment,\n    pre: Mapping[str, Account],\n    pre_fork_blocks: List[Block],\n    excess_data_gas_present: bool,\n    data_gas_used_present: bool,\n):\n\"\"\"\n    Test block rejection when `excessDataGas` and/or `dataGasUsed` fields are present on a pre-fork\n    block.\n    \"\"\"\n    header_modifier = Header()\n    if excess_data_gas_present:\n        header_modifier.excess_data_gas = 0\n    if data_gas_used_present:\n        header_modifier.data_gas_used = 0\n    blockchain_test(\n        pre=pre,\n        post={},\n        blocks=pre_fork_blocks[:-1]\n        + [\n            Block(\n                timestamp=(FORK_TIMESTAMP - 1),\n                rlp_modifier=header_modifier,\n                exception=\"invalid field\",\n            )\n        ],\n        genesis_environment=env,\n        tag=\"invalid_pre_fork_excess_data_gas\",\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition/#tests.cancun.eip4844_blobs.test_excess_data_gas_fork_transition.test_invalid_post_fork_block_without_blob_fields","title":"test_invalid_post_fork_block_without_blob_fields(blockchain_test, env, pre, pre_fork_blocks, excess_data_gas_missing, data_gas_used_missing)","text":"

Test block rejection when excessDataGas and/or dataGasUsed fields are missing on a post-fork block.

Source code in tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition.py
@pytest.mark.parametrize(\n    \"excess_data_gas_missing,data_gas_used_missing\",\n    [\n        (True, False),\n        (False, True),\n        (True, True),\n    ],\n)\ndef test_invalid_post_fork_block_without_blob_fields(\n    blockchain_test: BlockchainTestFiller,\n    env: Environment,\n    pre: Mapping[str, Account],\n    pre_fork_blocks: List[Block],\n    excess_data_gas_missing: bool,\n    data_gas_used_missing: bool,\n):\n\"\"\"\n    Test block rejection when `excessDataGas` and/or `dataGasUsed` fields are missing on a\n    post-fork block.\n    \"\"\"\n    header_modifier = Header()\n    if excess_data_gas_missing:\n        header_modifier.excess_data_gas = Header.REMOVE_FIELD\n    if data_gas_used_missing:\n        header_modifier.data_gas_used = Header.REMOVE_FIELD\n    blockchain_test(\n        pre=pre,\n        post={},\n        blocks=pre_fork_blocks\n        + [\n            Block(\n                timestamp=FORK_TIMESTAMP,\n                rlp_modifier=header_modifier,\n                exception=\"missing field\",\n            )\n        ],\n        genesis_environment=env,\n        tag=\"excess_data_gas_missing_post_fork\",\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition/#tests.cancun.eip4844_blobs.test_excess_data_gas_fork_transition.test_fork_transition_excess_data_gas","title":"test_fork_transition_excess_data_gas(blockchain_test, env, pre, pre_fork_blocks, post_fork_blocks, post)","text":"

Test excessDataGas calculation in the header when the fork is activated.

Also produce enough blocks to test the data gas price increase when the block is full with SpecHelpers.max_blobs_per_block()bs_per_block() blobs.

Source code in tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition.py
@pytest.mark.parametrize(\n    \"post_fork_block_count,blob_count_per_block\",\n    [\n        (\n            SpecHelpers.get_min_excess_data_blobs_for_data_gas_price(2)\n            // (SpecHelpers.max_blobs_per_block() - SpecHelpers.target_blobs_per_block())\n            + 2,\n            SpecHelpers.max_blobs_per_block(),\n        ),\n        (10, 0),\n        (10, SpecHelpers.target_blobs_per_block()),\n    ],\n    ids=[\"max_blobs\", \"no_blobs\", \"target_blobs\"],\n)\ndef test_fork_transition_excess_data_gas(\n    blockchain_test: BlockchainTestFiller,\n    env: Environment,\n    pre: Mapping[str, Account],\n    pre_fork_blocks: List[Block],\n    post_fork_blocks: List[Block],\n    post: Mapping[str, Account],\n):\n\"\"\"\n    Test `excessDataGas` calculation in the header when the fork is activated.\n\n    Also produce enough blocks to test the data gas price increase when the block is full with\n    `SpecHelpers.max_blobs_per_block()bs_per_block()` blobs.\n    \"\"\"\n    blockchain_test(\n        pre=pre,\n        post=post,\n        blocks=pre_fork_blocks + post_fork_blocks,\n        genesis_environment=env,\n        tag=\"correct_initial_data_gas_calc\",\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition/index/test_cases/","title":"Test Excess Data Gas Fork Transition - Test Cases","text":"

Test cases generated from tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition.py

Parametrized test cases generated from the test module tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition.py:

test_invalid_pre_fork_block_with_blob_fields[fork=ShanghaiToCancunAtTime15k-excess_data_gas_present=True-data_gas_used_present=False]\ntest_invalid_pre_fork_block_with_blob_fields[fork=ShanghaiToCancunAtTime15k-excess_data_gas_present=False-data_gas_used_present=True]\ntest_invalid_pre_fork_block_with_blob_fields[fork=ShanghaiToCancunAtTime15k-excess_data_gas_present=True-data_gas_used_present=True]\ntest_invalid_post_fork_block_without_blob_fields[fork=ShanghaiToCancunAtTime15k-excess_data_gas_missing=True-data_gas_used_missing=False]\ntest_invalid_post_fork_block_without_blob_fields[fork=ShanghaiToCancunAtTime15k-excess_data_gas_missing=False-data_gas_used_missing=True]\ntest_invalid_post_fork_block_without_blob_fields[fork=ShanghaiToCancunAtTime15k-excess_data_gas_missing=True-data_gas_used_missing=True]\ntest_fork_transition_excess_data_gas[fork=ShanghaiToCancunAtTime15k-max_blobs]\ntest_fork_transition_excess_data_gas[fork=ShanghaiToCancunAtTime15k-no_blobs]\ntest_fork_transition_excess_data_gas[fork=ShanghaiToCancunAtTime15k-target_blobs]\n

This output was extracted from the result of:

fill --collect-only -q --until Cancun tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition.py\n
"},{"location":"tests/cancun/eip4844_blobs/test_point_evaluation_precompile/","title":"Test Point Evaluation Precompile","text":"

Documentation for tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py.

Generate fixtures for these test cases for Cancun with:

Cancun only:

fill -v tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py --fork=Cancun --evm-bin=/path/to/evm-tool-dev-version\n
For all forks up to and including Cancun:
fill -v tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py --until=Cancun --evm-bin=/path/to/evm-tool-dev-version\n

Tests point evaluation precompile for EIP-4844: Shard Blob Transactions

Test point evaluation precompile for EIP-4844: Shard Blob Transactions.

Adding a new test

Add a function that is named test_<test_name> and takes at least the following arguments:

  • blockchain_test
  • pre
  • tx
  • post

The following arguments need to be parametrized or the test will not be generated:

  • versioned_hash
  • kzg_commitment
  • z
  • y
  • kzg_proof
  • success

These values correspond to a single call of the precompile, and success refers to whether the call should succeed or fail.

All other pytest.fixture fixtures can be parametrized to generate new combinations and test cases.

"},{"location":"tests/cancun/eip4844_blobs/test_point_evaluation_precompile/#tests.cancun.eip4844_blobs.test_point_evaluation_precompile.Spec","title":"Spec dataclass","text":"

Parameters from the EIP-4844 specifications as defined at https://eips.ethereum.org/EIPS/eip-4844#parameters

If the parameter is not currently used within the tests, it is commented out.

Source code in tests/cancun/eip4844_blobs/spec.py
@dataclass(frozen=True)\nclass Spec:\n\"\"\"\n    Parameters from the EIP-4844 specifications as defined at\n    https://eips.ethereum.org/EIPS/eip-4844#parameters\n\n    If the parameter is not currently used within the tests, it is commented\n    out.\n    \"\"\"\n\n    BLOB_TX_TYPE = 0x03\n    FIELD_ELEMENTS_PER_BLOB = 4096\n    BLS_MODULUS = 0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001\n    BLOB_COMMITMENT_VERSION_KZG = 1\n    POINT_EVALUATION_PRECOMPILE_ADDRESS = 20\n    POINT_EVALUATION_PRECOMPILE_GAS = 50_000\n    MAX_DATA_GAS_PER_BLOCK = 786432\n    TARGET_DATA_GAS_PER_BLOCK = 393216\n    MIN_DATA_GASPRICE = 1\n    DATA_GASPRICE_UPDATE_FRACTION = 3338477\n    # MAX_VERSIONED_HASHES_LIST_SIZE = 2**24\n    # MAX_CALLDATA_SIZE = 2**24\n    # MAX_ACCESS_LIST_SIZE = 2**24\n    # MAX_ACCESS_LIST_STORAGE_KEYS = 2**24\n    # MAX_TX_WRAP_COMMITMENTS = 2**12\n    # LIMIT_BLOBS_PER_TX = 2**12\n    DATA_GAS_PER_BLOB = 2**17\n    HASH_OPCODE_BYTE = 0x49\n    HASH_GAS_COST = 3\n\n    @classmethod\n    def kzg_to_versioned_hash(\n        cls,\n        kzg_commitment: bytes | int,  # 48 bytes\n        blob_commitment_version_kzg: Optional[bytes | int] = None,\n    ) -> bytes:\n\"\"\"\n        Calculates the versioned hash for a given KZG commitment.\n        \"\"\"\n        if blob_commitment_version_kzg is None:\n            blob_commitment_version_kzg = cls.BLOB_COMMITMENT_VERSION_KZG\n        if isinstance(kzg_commitment, int):\n            kzg_commitment = kzg_commitment.to_bytes(48, \"big\")\n        if isinstance(blob_commitment_version_kzg, int):\n            blob_commitment_version_kzg = blob_commitment_version_kzg.to_bytes(1, \"big\")\n        return blob_commitment_version_kzg + sha256(kzg_commitment).digest()[1:]\n\n    @classmethod\n    def fake_exponential(cls, factor: int, numerator: int, denominator: int) -> int:\n\"\"\"\n        Used to calculate the data gas cost.\n        \"\"\"\n        i = 1\n        output = 0\n        numerator_accumulator = factor * denominator\n        while numerator_accumulator > 0:\n            output += numerator_accumulator\n            numerator_accumulator = (numerator_accumulator * numerator) // (denominator * i)\n            i += 1\n        return output // denominator\n\n    @classmethod\n    def calc_excess_data_gas(cls, parent: BlockHeaderDataGasFields) -> int:\n\"\"\"\n        Calculate the excess data gas for a block given the excess data gas\n        and data gas used from the parent block header.\n        \"\"\"\n        if parent.excess_data_gas + parent.data_gas_used < cls.TARGET_DATA_GAS_PER_BLOCK:\n            return 0\n        else:\n            return parent.excess_data_gas + parent.data_gas_used - cls.TARGET_DATA_GAS_PER_BLOCK\n\n    # Note: Currently unused.\n    # @classmethod\n    # def get_total_data_gas(cls, tx: Transaction) -> int:\n    #     \"\"\"\n    #     Calculate the total data gas for a transaction.\n    #     \"\"\"\n    #     if tx.blob_versioned_hashes is None:\n    #         return 0\n    #     return cls.DATA_GAS_PER_BLOB * len(tx.blob_versioned_hashes)\n\n    @classmethod\n    def get_data_gasprice(cls, *, excess_data_gas: int) -> int:\n\"\"\"\n        Calculate the data gas price from the excess.\n        \"\"\"\n        return cls.fake_exponential(\n            cls.MIN_DATA_GASPRICE,\n            excess_data_gas,\n            cls.DATA_GASPRICE_UPDATE_FRACTION,\n        )\n
"},{"location":"tests/cancun/eip4844_blobs/test_point_evaluation_precompile/#tests.cancun.eip4844_blobs.test_point_evaluation_precompile.test_valid_precompile_calls","title":"test_valid_precompile_calls(blockchain_test, pre, tx, post)","text":"

Test valid sanity precompile calls that are expected to succeed.

  • kzg_commitment and kzg_proof are set to values such that p(z)==0 for all values of z, hence y is tested to be zero, and call to be successful.
Source code in tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py
@pytest.mark.parametrize(\n    \"z,y,kzg_commitment,kzg_proof,versioned_hash\",\n    [\n        pytest.param(Spec.BLS_MODULUS - 1, 0, INF_POINT, INF_POINT, auto, id=\"in_bounds_z\"),\n    ],\n)\n@pytest.mark.parametrize(\"success\", [True])\n@pytest.mark.valid_from(\"Cancun\")\ndef test_valid_precompile_calls(\n    blockchain_test: BlockchainTestFiller,\n    pre: Dict,\n    tx: Transaction,\n    post: Dict,\n):\n\"\"\"\n    Test valid sanity precompile calls that are expected to succeed.\n\n    - `kzg_commitment` and `kzg_proof` are set to values such that `p(z)==0` for all values of `z`,\n    hence `y` is tested to be zero, and call to be successful.\n    \"\"\"\n    blockchain_test(\n        pre=pre,\n        post=post,\n        blocks=[Block(txs=[tx])],\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_point_evaluation_precompile/#tests.cancun.eip4844_blobs.test_point_evaluation_precompile.test_invalid_precompile_calls","title":"test_invalid_precompile_calls(blockchain_test, pre, tx, post)","text":"

Test invalid precompile calls:

  • Out of bounds inputs z and y
  • Correct proof, commitment, z and y, but incorrect lengths
  • Null inputs
  • Zero inputs
  • Correct proof, commitment, z and y, but incorrect version versioned hash
Source code in tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py
@pytest.mark.parametrize(\n    \"z,y,kzg_commitment,kzg_proof,versioned_hash\",\n    [\n        (Spec.BLS_MODULUS, 0, INF_POINT, INF_POINT, auto),\n        (0, Spec.BLS_MODULUS, INF_POINT, INF_POINT, auto),\n        (Z, 0, INF_POINT, INF_POINT[:-1], auto),\n        (Z, 0, INF_POINT, INF_POINT[0:1], auto),\n        (Z, 0, INF_POINT, INF_POINT + bytes([0]), auto),\n        (Z, 0, INF_POINT, INF_POINT + bytes([0] * 1023), auto),\n        (bytes(), bytes(), bytes(), bytes(), bytes()),\n        (0, 0, 0, 0, 0),\n        (0, 0, 0, 0, auto),\n        (Z, 0, INF_POINT, INF_POINT, Spec.kzg_to_versioned_hash(0xC0 << 376, 0x00)),\n        (Z, 0, INF_POINT, INF_POINT, Spec.kzg_to_versioned_hash(0xC0 << 376, 0x02)),\n        (Z, 0, INF_POINT, INF_POINT, Spec.kzg_to_versioned_hash(0xC0 << 376, 0xFF)),\n    ],\n    ids=[\n        \"out_of_bounds_z\",\n        \"out_of_bounds_y\",\n        \"correct_proof_1_input_too_short\",\n        \"correct_proof_1_input_too_short_2\",\n        \"correct_proof_1_input_too_long\",\n        \"correct_proof_1_input_extra_long\",\n        \"null_inputs\",\n        \"zeros_inputs\",\n        \"zeros_inputs_correct_versioned_hash\",\n        \"correct_proof_1_incorrect_versioned_hash_version_0x00\",\n        \"correct_proof_1_incorrect_versioned_hash_version_0x02\",\n        \"correct_proof_1_incorrect_versioned_hash_version_0xff\",\n    ],\n)\n@pytest.mark.parametrize(\"success\", [False])\n@pytest.mark.valid_from(\"Cancun\")\ndef test_invalid_precompile_calls(\n    blockchain_test: BlockchainTestFiller,\n    pre: Dict,\n    tx: Transaction,\n    post: Dict,\n):\n\"\"\"\n    Test invalid precompile calls:\n\n    - Out of bounds inputs `z` and `y`\n    - Correct proof, commitment, z and y, but incorrect lengths\n    - Null inputs\n    - Zero inputs\n    - Correct proof, commitment, z and y, but incorrect version versioned hash\n    \"\"\"\n    blockchain_test(\n        pre=pre,\n        post=post,\n        blocks=[Block(txs=[tx])],\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_point_evaluation_precompile/#tests.cancun.eip4844_blobs.test_point_evaluation_precompile.test_point_evaluation_precompile_external_vectors","title":"test_point_evaluation_precompile_external_vectors(blockchain_test, pre, tx, post)","text":"

Test precompile calls using external test vectors compiled from different sources:

  • go_kzg_4844_verify_kzg_proof.json: test vectors from the go-kzg-4844 repository.
Source code in tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py
@pytest.mark.parametrize(\n    \"z,y,kzg_commitment,kzg_proof,success\",\n    all_external_vectors(),\n)\n@pytest.mark.parametrize(\"versioned_hash\", [auto])\n@pytest.mark.valid_from(\"Cancun\")\ndef test_point_evaluation_precompile_external_vectors(\n    blockchain_test: BlockchainTestFiller,\n    pre: Dict,\n    tx: Transaction,\n    post: Dict,\n):\n\"\"\"\n    Test precompile calls using external test vectors compiled from different sources:\n\n    - `go_kzg_4844_verify_kzg_proof.json`: test vectors from the\n    [go-kzg-4844](https://github.com/crate-crypto/go-kzg-4844) repository.\n    \"\"\"\n    blockchain_test(\n        pre=pre,\n        post=post,\n        blocks=[Block(txs=[tx])],\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_point_evaluation_precompile/#tests.cancun.eip4844_blobs.test_point_evaluation_precompile.test_point_evaluation_precompile_calls","title":"test_point_evaluation_precompile_calls(blockchain_test, pre, tx, post)","text":"

Test calling the Point Evaluation Precompile with different call types, gas and parameter configuration:

  • Using CALL, DELEGATECALL, CALLCODE and STATICCALL.
  • Using correct and incorrect proofs
  • Using barely insufficient gas
Source code in tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py
@pytest.mark.parametrize(\n    \"call_gas,y,success\",\n    [\n        (Spec.POINT_EVALUATION_PRECOMPILE_GAS, 0, True),\n        (Spec.POINT_EVALUATION_PRECOMPILE_GAS, 1, False),\n        (Spec.POINT_EVALUATION_PRECOMPILE_GAS - 1, 0, False),\n    ],\n    ids=[\"correct\", \"incorrect\", \"insufficient_gas\"],\n)\n@pytest.mark.parametrize(\n    \"call_type\",\n    [\n        Op.CALL,\n        Op.DELEGATECALL,\n        Op.CALLCODE,\n        Op.STATICCALL,\n    ],\n)\n@pytest.mark.parametrize(\n    \"z,kzg_commitment,kzg_proof,versioned_hash\",\n    [[Z, INF_POINT, INF_POINT, auto]],\n    ids=[\"\"],\n)\n@pytest.mark.valid_from(\"Cancun\")\ndef test_point_evaluation_precompile_calls(\n    blockchain_test: BlockchainTestFiller,\n    pre: Dict,\n    tx: Transaction,\n    post: Dict,\n):\n\"\"\"\n    Test calling the Point Evaluation Precompile with different call types, gas\n    and parameter configuration:\n\n    - Using CALL, DELEGATECALL, CALLCODE and STATICCALL.\n    - Using correct and incorrect proofs\n    - Using barely insufficient gas\n    \"\"\"\n    blockchain_test(\n        pre=pre,\n        post=post,\n        blocks=[Block(txs=[tx])],\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_point_evaluation_precompile/#tests.cancun.eip4844_blobs.test_point_evaluation_precompile.test_point_evaluation_precompile_gas_tx_to","title":"test_point_evaluation_precompile_gas_tx_to(blockchain_test, precompile_input, call_gas, proof_correct)","text":"

Test calling the Point Evaluation Precompile directly as transaction entry point, and measure the gas consumption.

  • Using gas_limit with exact necessary gas, insufficient gas and extra gas.
  • Using correct and incorrect proofs
Source code in tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py
@pytest.mark.parametrize(\n    \"call_gas\",\n    [\n        (Spec.POINT_EVALUATION_PRECOMPILE_GAS),\n        (Spec.POINT_EVALUATION_PRECOMPILE_GAS + 1),\n        (Spec.POINT_EVALUATION_PRECOMPILE_GAS - 1),\n    ],\n    ids=[\"exact_gas\", \"extra_gas\", \"insufficient_gas\"],\n)\n@pytest.mark.parametrize(\n    \"z,y,kzg_commitment,kzg_proof,versioned_hash,proof_correct\",\n    [\n        [Z, 0, INF_POINT, INF_POINT, auto, True],\n        [Z, 1, INF_POINT, INF_POINT, auto, False],\n    ],\n    ids=[\"correct_proof\", \"incorrect_proof\"],\n)\n@pytest.mark.valid_from(\"Cancun\")\ndef test_point_evaluation_precompile_gas_tx_to(\n    blockchain_test: BlockchainTestFiller,\n    precompile_input: bytes,\n    call_gas: int,\n    proof_correct: bool,\n):\n\"\"\"\n    Test calling the Point Evaluation Precompile directly as\n    transaction entry point, and measure the gas consumption.\n\n    - Using `gas_limit` with exact necessary gas, insufficient gas and extra gas.\n    - Using correct and incorrect proofs\n    \"\"\"\n    start_balance = 10**18\n    pre = {\n        TestAddress: Account(\n            nonce=0,\n            balance=start_balance,\n        )\n    }\n\n    # Gas is appended the intrinsic gas cost of the transaction\n    intrinsic_gas_cost = 21_000 + eip_2028_transaction_data_cost(precompile_input)\n\n    # Consumed gas will only be the precompile gas if the proof is correct and\n    # the call gas is sufficient.\n    # Otherwise, the call gas will be consumed in full.\n    consumed_gas = (\n        Spec.POINT_EVALUATION_PRECOMPILE_GAS\n        if call_gas >= Spec.POINT_EVALUATION_PRECOMPILE_GAS and proof_correct\n        else call_gas\n    ) + intrinsic_gas_cost\n\n    fee_per_gas = 7\n\n    tx = Transaction(\n        ty=2,\n        nonce=0,\n        data=precompile_input,\n        to=to_address(Spec.POINT_EVALUATION_PRECOMPILE_ADDRESS),\n        value=0,\n        gas_limit=call_gas + intrinsic_gas_cost,\n        max_fee_per_gas=7,\n        max_priority_fee_per_gas=0,\n    )\n\n    post = {\n        TestAddress: Account(\n            nonce=1,\n            balance=start_balance - (consumed_gas * fee_per_gas),\n        )\n    }\n\n    blockchain_test(\n        pre=pre,\n        post=post,\n        blocks=[Block(txs=[tx])],\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_point_evaluation_precompile/#tests.cancun.eip4844_blobs.test_point_evaluation_precompile.test_point_evaluation_precompile_before_fork","title":"test_point_evaluation_precompile_before_fork(blockchain_test, pre, tx)","text":"

Test calling the Point Evaluation Precompile before the appropriate fork.

Source code in tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py
@pytest.mark.parametrize(\n    \"z,y,kzg_commitment,kzg_proof,versioned_hash\",\n    [[Z, 0, INF_POINT, INF_POINT, auto]],\n    ids=[\"correct_proof\"],\n)\n@pytest.mark.valid_at_transition_to(\"Cancun\")\ndef test_point_evaluation_precompile_before_fork(\n    blockchain_test: BlockchainTestFiller,\n    pre: Dict,\n    tx: Transaction,\n):\n\"\"\"\n    Test calling the Point Evaluation Precompile before the appropriate fork.\n    \"\"\"\n    precompile_caller_code = Op.SSTORE(\n        Op.NUMBER,\n        Op.CALL(\n            Op.GAS,\n            Spec.POINT_EVALUATION_PRECOMPILE_ADDRESS,\n            1,  # Value\n            0,  # Zero-length calldata\n            0,\n            0,  # Zero-length return\n            0,\n        ),\n    )\n    precompile_caller_address = to_address(0x100)\n\n    pre = {\n        TestAddress: Account(\n            nonce=0,\n            balance=0x10**18,\n        ),\n        precompile_caller_address: Account(\n            nonce=0,\n            code=precompile_caller_code,\n            balance=0x10**18,\n        ),\n    }\n\n    def tx_generator() -> Iterator[Transaction]:\n        nonce = 0  # Initial value\n        while True:\n            yield tx.with_nonce(nonce)\n            nonce = nonce + 1\n\n    iter_tx = tx_generator()\n\n    FORK_TIMESTAMP = 15_000\n    PRE_FORK_BLOCK_RANGE = range(999, FORK_TIMESTAMP, 1_000)\n\n    # Blocks before fork\n    blocks = [Block(timestamp=t, txs=[next(iter_tx)]) for t in PRE_FORK_BLOCK_RANGE]\n    # Block after fork\n    blocks += [Block(timestamp=FORK_TIMESTAMP, txs=[next(iter_tx)])]\n\n    post = {\n        precompile_caller_address: Account(\n            storage={b: 1 for b in range(1, len(PRE_FORK_BLOCK_RANGE) + 1)},\n            # The tx in last block succeeds; storage 0 by default.\n        ),\n        to_address(Spec.POINT_EVALUATION_PRECOMPILE_ADDRESS): Account(\n            balance=len(PRE_FORK_BLOCK_RANGE),\n        ),\n    }\n\n    blockchain_test(\n        tag=\"point_evaluation_precompile_before_fork\",\n        pre=pre,\n        post=post,\n        blocks=blocks,\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_point_evaluation_precompile/index/test_cases/","title":"Test Point Evaluation Precompile - Test Cases","text":"

Test cases generated from tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py

Parametrized test cases generated from the test module tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py:

test_valid_precompile_calls[fork=Cancun-success=True-in_bounds_z]\ntest_invalid_precompile_calls[fork=Cancun-success=False-out_of_bounds_z]\ntest_invalid_precompile_calls[fork=Cancun-success=False-out_of_bounds_y]\ntest_invalid_precompile_calls[fork=Cancun-success=False-correct_proof_1_input_too_short]\ntest_invalid_precompile_calls[fork=Cancun-success=False-correct_proof_1_input_too_short_2]\ntest_invalid_precompile_calls[fork=Cancun-success=False-correct_proof_1_input_too_long]\ntest_invalid_precompile_calls[fork=Cancun-success=False-correct_proof_1_input_extra_long]\ntest_invalid_precompile_calls[fork=Cancun-success=False-null_inputs]\ntest_invalid_precompile_calls[fork=Cancun-success=False-zeros_inputs]\ntest_invalid_precompile_calls[fork=Cancun-success=False-zeros_inputs_correct_versioned_hash]\ntest_invalid_precompile_calls[fork=Cancun-success=False-correct_proof_1_incorrect_versioned_hash_version_0x00]\ntest_invalid_precompile_calls[fork=Cancun-success=False-correct_proof_1_incorrect_versioned_hash_version_0x02]\ntest_invalid_precompile_calls[fork=Cancun-success=False-correct_proof_1_incorrect_versioned_hash_version_0xff]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_02e696ada7d4631d]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_08f9e2f1cb3d39db]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_0cf79b17cb5f4ea2]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_1ce8e4f69d5df899]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_26b753dec0560daa]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_31ebd010e6098750]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_3208425794224c3f]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_36817bfd67de97a8]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_392169c16a2e5ef6]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_3ac8dc31e9aa6a70]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_3c1e8b38219e3e12]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_3c87ec986c2656c2]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_3cd183d0bab85fb7]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_420f2a187ce77035]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_444b73ff54a19b44]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_53a9bdf4f75196da]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_7db4f140a955dd1a]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_83e53423a2dd93fe]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_9b24f8997145435c]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_9b754afb690c47e1]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_af669445747d2585]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_af8b75f664ed7d43]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_b6cb6698327d9835]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_b6ec3736f9ff2c62]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_becf2e1641bbd4e6]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_c3d4322ec17fe7cd]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_c5e1490d672d026d]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_cae5d3491190b777]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_d0992bc0387790a4]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_d736268229bd87ec]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_e68d7111a2364a49]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_ed6b180ec759bcf6]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_f0ed3dc11cdeb130]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_f47eb9fc139f6bfd]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_f7f44e1e864aa967]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_correct_proof_ffa6e97b97146517]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_02e696ada7d4631d]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_08f9e2f1cb3d39db]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_0cf79b17cb5f4ea2]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_1ce8e4f69d5df899]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_26b753dec0560daa]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_31ebd010e6098750]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_3208425794224c3f]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_36817bfd67de97a8]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_392169c16a2e5ef6]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_3ac8dc31e9aa6a70]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_3c1e8b38219e3e12]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_3c87ec986c2656c2]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_3cd183d0bab85fb7]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_420f2a187ce77035]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_444b73ff54a19b44]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_53a9bdf4f75196da]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_7db4f140a955dd1a]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_83e53423a2dd93fe]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_9b24f8997145435c]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_9b754afb690c47e1]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_af669445747d2585]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_af8b75f664ed7d43]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_b6cb6698327d9835]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_b6ec3736f9ff2c62]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_becf2e1641bbd4e6]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_c3d4322ec17fe7cd]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_c5e1490d672d026d]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_cae5d3491190b777]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_d0992bc0387790a4]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_d736268229bd87ec]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_e68d7111a2364a49]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_ed6b180ec759bcf6]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_f0ed3dc11cdeb130]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_f47eb9fc139f6bfd]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_f7f44e1e864aa967]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_incorrect_proof_ffa6e97b97146517]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_invalid_commitment_1b44e341d56c757d]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_invalid_commitment_32afa9561a4b3b91]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_invalid_commitment_3e55802a5ed3c757]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_invalid_commitment_e9d3e9ec16fbc15f]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_invalid_proof_1b44e341d56c757d]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_invalid_proof_32afa9561a4b3b91]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_invalid_proof_3e55802a5ed3c757]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_invalid_proof_e9d3e9ec16fbc15f]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_invalid_y_35d08d612aad2197]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_invalid_y_4aa6def8c35c9097]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_invalid_y_4e51cef08a61606f]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_invalid_y_64b9ff2b8f7dddee]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_invalid_y_b358a2e763727b70]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_invalid_y_eb0601fec84cc5e9]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_invalid_z_35d08d612aad2197]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_invalid_z_4aa6def8c35c9097]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_invalid_z_4e51cef08a61606f]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_invalid_z_64b9ff2b8f7dddee]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_invalid_z_b358a2e763727b70]\ntest_point_evaluation_precompile_external_vectors[fork=Cancun-versioned_hash=auto-verify_kzg_proof_case_invalid_z_eb0601fec84cc5e9]\ntest_point_evaluation_precompile_calls[fork=Cancun--call_type=CALL-correct]\ntest_point_evaluation_precompile_calls[fork=Cancun--call_type=CALL-incorrect]\ntest_point_evaluation_precompile_calls[fork=Cancun--call_type=CALL-insufficient_gas]\ntest_point_evaluation_precompile_calls[fork=Cancun--call_type=DELEGATECALL-correct]\ntest_point_evaluation_precompile_calls[fork=Cancun--call_type=DELEGATECALL-incorrect]\ntest_point_evaluation_precompile_calls[fork=Cancun--call_type=DELEGATECALL-insufficient_gas]\ntest_point_evaluation_precompile_calls[fork=Cancun--call_type=CALLCODE-correct]\ntest_point_evaluation_precompile_calls[fork=Cancun--call_type=CALLCODE-incorrect]\ntest_point_evaluation_precompile_calls[fork=Cancun--call_type=CALLCODE-insufficient_gas]\ntest_point_evaluation_precompile_calls[fork=Cancun--call_type=STATICCALL-correct]\ntest_point_evaluation_precompile_calls[fork=Cancun--call_type=STATICCALL-incorrect]\ntest_point_evaluation_precompile_calls[fork=Cancun--call_type=STATICCALL-insufficient_gas]\ntest_point_evaluation_precompile_gas_tx_to[fork=Cancun-correct_proof-exact_gas]\ntest_point_evaluation_precompile_gas_tx_to[fork=Cancun-correct_proof-extra_gas]\ntest_point_evaluation_precompile_gas_tx_to[fork=Cancun-correct_proof-insufficient_gas]\ntest_point_evaluation_precompile_gas_tx_to[fork=Cancun-incorrect_proof-exact_gas]\ntest_point_evaluation_precompile_gas_tx_to[fork=Cancun-incorrect_proof-extra_gas]\ntest_point_evaluation_precompile_gas_tx_to[fork=Cancun-incorrect_proof-insufficient_gas]\ntest_point_evaluation_precompile_before_fork[fork=ShanghaiToCancunAtTime15k-correct_proof]\n

This output was extracted from the result of:

fill --collect-only -q --until Cancun tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py\n
"},{"location":"tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas/","title":"Test Point Evaluation Precompile Gas","text":"

Documentation for tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas.py.

Generate fixtures for these test cases for Cancun with:

Cancun only:

fill -v tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas.py --fork=Cancun --evm-bin=/path/to/evm-tool-dev-version\n
For all forks up to and including Cancun:
fill -v tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas.py --until=Cancun --evm-bin=/path/to/evm-tool-dev-version\n

Tests gas usage on point evaluation precompile for EIP-4844: Shard Blob Transactions

Test gas usage on point evaluation precompile for EIP-4844: Shard Blob Transactions.

"},{"location":"tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas/#tests.cancun.eip4844_blobs.test_point_evaluation_precompile_gas.Spec","title":"Spec dataclass","text":"

Parameters from the EIP-4844 specifications as defined at https://eips.ethereum.org/EIPS/eip-4844#parameters

If the parameter is not currently used within the tests, it is commented out.

Source code in tests/cancun/eip4844_blobs/spec.py
@dataclass(frozen=True)\nclass Spec:\n\"\"\"\n    Parameters from the EIP-4844 specifications as defined at\n    https://eips.ethereum.org/EIPS/eip-4844#parameters\n\n    If the parameter is not currently used within the tests, it is commented\n    out.\n    \"\"\"\n\n    BLOB_TX_TYPE = 0x03\n    FIELD_ELEMENTS_PER_BLOB = 4096\n    BLS_MODULUS = 0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001\n    BLOB_COMMITMENT_VERSION_KZG = 1\n    POINT_EVALUATION_PRECOMPILE_ADDRESS = 20\n    POINT_EVALUATION_PRECOMPILE_GAS = 50_000\n    MAX_DATA_GAS_PER_BLOCK = 786432\n    TARGET_DATA_GAS_PER_BLOCK = 393216\n    MIN_DATA_GASPRICE = 1\n    DATA_GASPRICE_UPDATE_FRACTION = 3338477\n    # MAX_VERSIONED_HASHES_LIST_SIZE = 2**24\n    # MAX_CALLDATA_SIZE = 2**24\n    # MAX_ACCESS_LIST_SIZE = 2**24\n    # MAX_ACCESS_LIST_STORAGE_KEYS = 2**24\n    # MAX_TX_WRAP_COMMITMENTS = 2**12\n    # LIMIT_BLOBS_PER_TX = 2**12\n    DATA_GAS_PER_BLOB = 2**17\n    HASH_OPCODE_BYTE = 0x49\n    HASH_GAS_COST = 3\n\n    @classmethod\n    def kzg_to_versioned_hash(\n        cls,\n        kzg_commitment: bytes | int,  # 48 bytes\n        blob_commitment_version_kzg: Optional[bytes | int] = None,\n    ) -> bytes:\n\"\"\"\n        Calculates the versioned hash for a given KZG commitment.\n        \"\"\"\n        if blob_commitment_version_kzg is None:\n            blob_commitment_version_kzg = cls.BLOB_COMMITMENT_VERSION_KZG\n        if isinstance(kzg_commitment, int):\n            kzg_commitment = kzg_commitment.to_bytes(48, \"big\")\n        if isinstance(blob_commitment_version_kzg, int):\n            blob_commitment_version_kzg = blob_commitment_version_kzg.to_bytes(1, \"big\")\n        return blob_commitment_version_kzg + sha256(kzg_commitment).digest()[1:]\n\n    @classmethod\n    def fake_exponential(cls, factor: int, numerator: int, denominator: int) -> int:\n\"\"\"\n        Used to calculate the data gas cost.\n        \"\"\"\n        i = 1\n        output = 0\n        numerator_accumulator = factor * denominator\n        while numerator_accumulator > 0:\n            output += numerator_accumulator\n            numerator_accumulator = (numerator_accumulator * numerator) // (denominator * i)\n            i += 1\n        return output // denominator\n\n    @classmethod\n    def calc_excess_data_gas(cls, parent: BlockHeaderDataGasFields) -> int:\n\"\"\"\n        Calculate the excess data gas for a block given the excess data gas\n        and data gas used from the parent block header.\n        \"\"\"\n        if parent.excess_data_gas + parent.data_gas_used < cls.TARGET_DATA_GAS_PER_BLOCK:\n            return 0\n        else:\n            return parent.excess_data_gas + parent.data_gas_used - cls.TARGET_DATA_GAS_PER_BLOCK\n\n    # Note: Currently unused.\n    # @classmethod\n    # def get_total_data_gas(cls, tx: Transaction) -> int:\n    #     \"\"\"\n    #     Calculate the total data gas for a transaction.\n    #     \"\"\"\n    #     if tx.blob_versioned_hashes is None:\n    #         return 0\n    #     return cls.DATA_GAS_PER_BLOB * len(tx.blob_versioned_hashes)\n\n    @classmethod\n    def get_data_gasprice(cls, *, excess_data_gas: int) -> int:\n\"\"\"\n        Calculate the data gas price from the excess.\n        \"\"\"\n        return cls.fake_exponential(\n            cls.MIN_DATA_GASPRICE,\n            excess_data_gas,\n            cls.DATA_GASPRICE_UPDATE_FRACTION,\n        )\n
"},{"location":"tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas/#tests.cancun.eip4844_blobs.test_point_evaluation_precompile_gas.test_point_evaluation_precompile_gas_usage","title":"test_point_evaluation_precompile_gas_usage(blockchain_test, pre, tx, post)","text":"

Test point evaluation precompile gas usage under different call contexts and gas limits:

  • Test using all call types (CALL, DELEGATECALL, CALLCODE, STATICCALL)
  • Test using different gas limits (exact gas, insufficient gas, extra gas)
  • Test using correct and incorrect proofs
Source code in tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas.py
@pytest.mark.parametrize(\n    \"call_type\",\n    [Op.CALL, Op.DELEGATECALL, Op.CALLCODE, Op.STATICCALL],\n)\n@pytest.mark.parametrize(\n    \"call_gas\",\n    [\n        Spec.POINT_EVALUATION_PRECOMPILE_GAS,\n        Spec.POINT_EVALUATION_PRECOMPILE_GAS - 1,\n        Spec.POINT_EVALUATION_PRECOMPILE_GAS + 1,\n    ],\n    ids=[\"exact_gas\", \"insufficient_gas\", \"extra_gas\"],\n)\n@pytest.mark.parametrize(\"proof\", [\"correct\", \"incorrect\"])\n@pytest.mark.valid_from(\"Cancun\")\ndef test_point_evaluation_precompile_gas_usage(\n    blockchain_test: BlockchainTestFiller,\n    pre: Dict,\n    tx: Transaction,\n    post: Dict,\n):\n\"\"\"\n    Test point evaluation precompile gas usage under different call contexts and gas limits:\n\n    - Test using all call types (CALL, DELEGATECALL, CALLCODE, STATICCALL)\n    - Test using different gas limits (exact gas, insufficient gas, extra gas)\n    - Test using correct and incorrect proofs\n    \"\"\"\n    blockchain_test(\n        pre=pre,\n        post=post,\n        blocks=[Block(txs=[tx])],\n    )\n
"},{"location":"tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas/index/test_cases/","title":"Test Point Evaluation Precompile Gas - Test Cases","text":"

Test cases generated from tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas.py

Parametrized test cases generated from the test module tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas.py:

test_point_evaluation_precompile_gas_usage[fork=Cancun-proof=correct-exact_gas-call_type=CALL]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=correct-exact_gas-call_type=DELEGATECALL]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=correct-exact_gas-call_type=CALLCODE]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=correct-exact_gas-call_type=STATICCALL]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=correct-insufficient_gas-call_type=CALL]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=correct-insufficient_gas-call_type=DELEGATECALL]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=correct-insufficient_gas-call_type=CALLCODE]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=correct-insufficient_gas-call_type=STATICCALL]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=correct-extra_gas-call_type=CALL]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=correct-extra_gas-call_type=DELEGATECALL]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=correct-extra_gas-call_type=CALLCODE]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=correct-extra_gas-call_type=STATICCALL]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=incorrect-exact_gas-call_type=CALL]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=incorrect-exact_gas-call_type=DELEGATECALL]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=incorrect-exact_gas-call_type=CALLCODE]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=incorrect-exact_gas-call_type=STATICCALL]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=incorrect-insufficient_gas-call_type=CALL]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=incorrect-insufficient_gas-call_type=DELEGATECALL]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=incorrect-insufficient_gas-call_type=CALLCODE]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=incorrect-insufficient_gas-call_type=STATICCALL]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=incorrect-extra_gas-call_type=CALL]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=incorrect-extra_gas-call_type=DELEGATECALL]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=incorrect-extra_gas-call_type=CALLCODE]\ntest_point_evaluation_precompile_gas_usage[fork=Cancun-proof=incorrect-extra_gas-call_type=STATICCALL]\n

This output was extracted from the result of:

fill --collect-only -q --until Cancun tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas.py\n
"},{"location":"tests/frontier/","title":"Frontier","text":"

Documentation for tests/frontier.

Generate fixtures for these test cases with:

fill -v tests/frontier\n

Test cases for EVM functionality introduced in Frontier.

"},{"location":"tests/frontier/opcodes/","title":"Opcodes","text":"

Documentation for tests/frontier/opcodes.

Generate fixtures for these test cases with:

fill -v tests/frontier/opcodes\n

Test for opcodes introduced in Frontier.

"},{"location":"tests/frontier/opcodes/test_dup/","title":"Test DUP","text":"

Documentation for tests/frontier/opcodes/test_dup.py.

Generate fixtures for these test cases with:

fill -v tests/frontier/opcodes/test_dup.py\n
Test DUP

Test the DUP opcodes.

"},{"location":"tests/frontier/opcodes/test_dup/#tests.frontier.opcodes.test_dup.test_dup","title":"test_dup(state_test)","text":"

Test the DUP1-DUP16 opcodes.

Test case ported from:
  • ethereum/tests/GeneralStateTests/VMTests/vmTests/dup.json by Ori Pomerantz.
Source code in tests/frontier/opcodes/test_dup.py
def test_dup(state_test: StateTestFiller):\n\"\"\"\n    Test the DUP1-DUP16 opcodes.\n\n    note: Test case ported from:\n\n        - [ethereum/tests/GeneralStateTests/VMTests/vmTests/dup.json](https://github.com/ethereum/tests/blob/develop/GeneralStateTests/VMTests/vmTests/dup.json)\n        by Ori Pomerantz.\n    \"\"\"  # noqa: E501\n    env = Environment()\n    pre = {\"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b\": Account(balance=1000000000000000000000)}\n    txs = []\n    post = {}\n\n\"\"\"\n    We are setting up 16 accounts, ranging from 0x100 to 0x10f.\n    They push values into the stack from 0-16, but each contract uses a\n    different DUP opcode, and depending on the opcode used, the item copied\n    into the storage changes.\n    \"\"\"\n    for i in range(0, 16):\n\"\"\"\n        Account 0x100 uses DUP1,\n        Account 0x10f uses DUP16.\n        \"\"\"\n        account = to_address(0x100 + i)\n        dup_opcode = 0x80 + i\n\n        pre[account] = Account(\n            code=(\n                # Push 0 - 16 onto the stack\n\"\"\"0x6000 6001 6002 6003 6004 6005 6006 6007 6008 6009\n                         600A 600B 600C 600D 600E 600F 6010\"\"\"\n                +\n                # Use the DUP opcode for this account\n                hex(dup_opcode)[2:]\n                +\n                # Save each stack value into different keys in storage\n\"\"\"6000 55 6001 55 6002 55 6003 55 6004 55 6005 55\n                       6006 55 6007 55 6008 55 6009 55 600A 55 600B 55\n                       600C 55 600D 55 600E 55 600F 55 6010 55\"\"\"\n            )\n        )\n\n\"\"\"\n        Also we are sending one transaction to each account.\n        The storage of each will only change by one item: storage[0]\n        The value depends on the DUP opcode used.\n        \"\"\"\n        tx = Transaction(\n            ty=0x0,\n            nonce=i,\n            to=account,\n            gas_limit=500000,\n            gas_price=10,\n            protected=False,\n            data=\"\",\n        )\n        txs.append(tx)\n\n\"\"\"\n        Storage will be structured as follows:\n\n        0x00: 0x10-0x01 (Depending on DUP opcode)\n        0x01: 0x10\n        0x02: 0x0F\n        0x03: 0x0E\n        0x04: 0x0D\n        0x05: 0x0C\n        0x06: 0x0B\n        0x07: 0x0A\n        0x08: 0x09\n        0x09: 0x08\n        0x0A: 0x07\n        0x0B: 0x06\n        0x0C: 0x05\n        0x0D: 0x04\n        0x0E: 0x03\n        0x0F: 0x02\n        0x10: 0x01\n\n        DUP1 copies the first element of the stack (0x10).\n        DUP16 copies the 16th element of the stack (0x01).\n        \"\"\"\n        s: Storage.StorageDictType = dict(zip(range(1, 17), range(16, 0, -1)))\n        s[0] = 16 - i\n\n        post[account] = Account(storage=s)\n\n    state_test(env=env, pre=pre, post=post, txs=txs)\n
"},{"location":"tests/frontier/opcodes/test_dup/index/test_cases/","title":"Test DUP - Test Cases","text":"

Test cases generated from tests/frontier/opcodes/test_dup.py

Parametrized test cases generated from the test module tests/frontier/opcodes/test_dup.py:

test_dup[fork=Frontier]\ntest_dup[fork=Homestead]\ntest_dup[fork=Byzantium]\ntest_dup[fork=Constantinople]\ntest_dup[fork=ConstantinopleFix]\ntest_dup[fork=Istanbul]\ntest_dup[fork=Berlin]\ntest_dup[fork=London]\ntest_dup[fork=Merge]\ntest_dup[fork=Shanghai]\ntest_dup[fork=Cancun]\n

This output was extracted from the result of:

fill --collect-only -q --until Cancun tests/frontier/opcodes/test_dup.py\n
"},{"location":"tests/homestead/","title":"Homestead","text":"

Documentation for tests/homestead.

Generate fixtures for these test cases with:

fill -v tests/homestead\n

Test cases for EVM functionality introduced in Homestead.

"},{"location":"tests/homestead/yul/","title":"Yul","text":"

Documentation for tests/homestead/yul.

Generate fixtures for these test cases with:

fill -v tests/homestead/yul\n

Tests using Yul source for contracts.

"},{"location":"tests/homestead/yul/test_yul_example/","title":"Test Yul Example","text":"

Documentation for tests/homestead/yul/test_yul_example.py.

Generate fixtures for these test cases with:

fill -v tests/homestead/yul/test_yul_example.py\n

Test Yul Source Code Examples

"},{"location":"tests/homestead/yul/test_yul_example/#tests.homestead.yul.test_yul_example.test_yul","title":"test_yul(state_test, yul)","text":"

Test YUL compiled bytecode.

Source code in tests/homestead/yul/test_yul_example.py
@pytest.mark.valid_from(\"Homestead\")\ndef test_yul(state_test: StateTestFiller, yul: YulCompiler):\n\"\"\"\n    Test YUL compiled bytecode.\n    \"\"\"\n    env = Environment()\n\n    pre = {\n        \"0x1000000000000000000000000000000000000000\": Account(\n            balance=0x0BA1A9CE0BA1A9CE,\n            code=yul(\n\"\"\"\n            {\n                function f(a, b) -> c {\n                    c := add(a, b)\n                }\n\n                sstore(0, f(1, 2))\n                return(0, 32)\n            }\n            \"\"\"\n            ),\n        ),\n        TestAddress: Account(balance=0x0BA1A9CE0BA1A9CE),\n    }\n\n    tx = Transaction(\n        ty=0x0,\n        chain_id=0x0,\n        nonce=0,\n        to=\"0x1000000000000000000000000000000000000000\",\n        gas_limit=500000,\n        gas_price=10,\n        protected=False,\n    )\n\n    post = {\n        \"0x1000000000000000000000000000000000000000\": Account(\n            storage={\n                0x00: 0x03,\n            },\n        ),\n    }\n\n    state_test(env=env, pre=pre, post=post, txs=[tx])\n
"},{"location":"tests/homestead/yul/test_yul_example/index/test_cases/","title":"Test Yul Example - Test Cases","text":"

Test cases generated from tests/homestead/yul/test_yul_example.py

Parametrized test cases generated from the test module tests/homestead/yul/test_yul_example.py:

test_yul[fork=Homestead]\ntest_yul[fork=Byzantium]\ntest_yul[fork=Constantinople]\ntest_yul[fork=ConstantinopleFix]\ntest_yul[fork=Istanbul]\ntest_yul[fork=Berlin]\ntest_yul[fork=London]\ntest_yul[fork=Merge]\ntest_yul[fork=Shanghai]\ntest_yul[fork=Cancun]\n

This output was extracted from the result of:

fill --collect-only -q --until Cancun tests/homestead/yul/test_yul_example.py\n
"},{"location":"tests/istanbul/","title":"Istanbul","text":"

Documentation for tests/istanbul.

Generate fixtures for these test cases with:

fill -v tests/istanbul\n

Test cases for EVM functionality introduced in Istanbul.

"},{"location":"tests/istanbul/eip1344_chainid/","title":"EIP-1344 CHAINID","text":"

Documentation for tests/istanbul/eip1344_chainid.

Generate fixtures for these test cases with:

fill -v tests/istanbul/eip1344_chainid\n
Tests EIP-1344: ChainID Opcode

Test cases for EIP-1344: ChainID Opcode.

"},{"location":"tests/istanbul/eip1344_chainid/test_chainid/","title":"Test CHAINID","text":"

Documentation for tests/istanbul/eip1344_chainid/test_chainid.py.

Generate fixtures for these test cases with:

fill -v tests/istanbul/eip1344_chainid/test_chainid.py\n
Tests EIP-1344: CHAINID opcode

Test cases for EIP-1344: CHAINID opcode.

"},{"location":"tests/istanbul/eip1344_chainid/test_chainid/#tests.istanbul.eip1344_chainid.test_chainid.test_chainid","title":"test_chainid(state_test)","text":"

Test CHAINID opcode.

Source code in tests/istanbul/eip1344_chainid/test_chainid.py
@pytest.mark.valid_from(\"Istanbul\")\ndef test_chainid(state_test: StateTestFiller):\n\"\"\"\n    Test CHAINID opcode.\n    \"\"\"\n    env = Environment(\n        coinbase=\"0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba\",\n        difficulty=0x20000,\n        gas_limit=10000000000,\n        number=1,\n        timestamp=1000,\n    )\n\n    pre = {\n        to_address(0x100): Account(code=Op.SSTORE(1, Op.CHAINID) + Op.STOP),\n        TestAddress: Account(balance=1000000000000000000000),\n    }\n\n    tx = Transaction(\n        ty=0x0,\n        chain_id=0x0,\n        nonce=0,\n        to=to_address(0x100),\n        gas_limit=100000000,\n        gas_price=10,\n        protected=False,\n    )\n\n    post = {\n        to_address(0x100): Account(code=\"0x4660015500\", storage={\"0x01\": \"0x01\"}),\n    }\n\n    state_test(env=env, pre=pre, post=post, txs=[tx])\n
"},{"location":"tests/istanbul/eip1344_chainid/test_chainid/index/test_cases/","title":"Test CHAINID - Test Cases","text":"

Test cases generated from tests/istanbul/eip1344_chainid/test_chainid.py

Parametrized test cases generated from the test module tests/istanbul/eip1344_chainid/test_chainid.py:

test_chainid[fork=Istanbul]\ntest_chainid[fork=Berlin]\ntest_chainid[fork=London]\ntest_chainid[fork=Merge]\ntest_chainid[fork=Shanghai]\ntest_chainid[fork=Cancun]\n

This output was extracted from the result of:

fill --collect-only -q --until Cancun tests/istanbul/eip1344_chainid/test_chainid.py\n
"},{"location":"tests/merge/","title":"Merge","text":"

Documentation for tests/merge.

Generate fixtures for these test cases with:

fill -v tests/merge\n

Test cases for EVM functionality introduced in the Merge.

"},{"location":"tests/merge/security/","title":"Security","text":"

Documentation for tests/merge/security.

Generate fixtures for these test cases with:

fill -v tests/merge/security\n

Ethereum execution client tests related to security issues.

"},{"location":"tests/merge/security/test_selfdestruct_balance_bug/","title":"Test Selfdestruct Balance Bug","text":"

Documentation for tests/merge/security/test_selfdestruct_balance_bug.py.

Generate fixtures for these test cases with:

fill -v tests/merge/security/test_selfdestruct_balance_bug.py\n
Tests the Consensus Flaw During Block Processing related to SELFDESTRUCT

Tests the consensus-vulnerability reported in go-ethereum/security/advisories/GHSA-xw37-57qp-9mm4.

To reproduce the issue with this test case:

  1. Fill the test with the most recent geth evm version.
  2. Run the fixture output within a vulnerable geth version: v1.9.20 > geth >= v1.9.4.
"},{"location":"tests/merge/security/test_selfdestruct_balance_bug/#tests.merge.security.test_selfdestruct_balance_bug.test_tx_selfdestruct_balance_bug","title":"test_tx_selfdestruct_balance_bug(blockchain_test, yul)","text":"

Test that the vulnerability is not present by checking the balance of the 0xaa contract after executing specific transactions:

  1. Start with contract 0xaa which has initial balance of 3 wei. 0xaa contract code simply performs a self-destruct to itself.

  2. Send a transaction (tx 1) to invoke caller contract 0xcc (which has a balance of 1 wei), which in turn invokes 0xaa with a 1 wei call.

  3. Store the balance of 0xaa after the first transaction is processed. 0xaa self-destructed. Expected outcome: 0 wei.

  4. Send another transaction (tx 2) to call 0xaa with 5 wei.

  5. Store the balance of 0xaa after the second transaction is processed. No self-destruct. Expected outcome: 5 wei.

  6. Verify that:

    • Call within tx 1 is successful, i.e 0xaa self-destructed.
    • The balances of 0xaa after each tx are correct.
    • During tx 2, code in 0xaa does not execute, hence self-destruct mechanism does not trigger.
Source code in tests/merge/security/test_selfdestruct_balance_bug.py
@pytest.mark.compile_yul_with(\"Merge\")  # Shanghai refuses to compile SELFDESTRUCT\n@pytest.mark.valid_from(\"Constantinople\")\ndef test_tx_selfdestruct_balance_bug(blockchain_test: BlockchainTestFiller, yul: YulCompiler):\n\"\"\"\n    Test that the vulnerability is not present by checking the balance of the\n    `0xaa` contract after executing specific transactions:\n\n    1. Start with contract `0xaa` which has initial balance of 3 wei.\n        `0xaa` contract code simply performs a self-destruct to itself.\n\n    2. Send a transaction (tx 1) to invoke caller contract `0xcc` (which\n        has a balance of 1 wei), which in turn invokes `0xaa` with a 1 wei call.\n\n    3. Store the balance of `0xaa` after the first transaction\n        is processed. `0xaa` self-destructed. Expected outcome: 0 wei.\n\n    4. Send another transaction (tx 2) to call 0xaa with 5 wei.\n\n    5. Store the balance of `0xaa` after the second transaction\n        is processed. No self-destruct. Expected outcome: 5 wei.\n\n    6. Verify that:\n        - Call within tx 1 is successful, i.e `0xaa` self-destructed.\n        - The balances of `0xaa` after each tx are correct.\n        - During tx 2, code in `0xaa` does not execute,\n            hence self-destruct mechanism does not trigger.\n    \"\"\"\n    aa_code = yul(\n\"\"\"\n        {\n            /* 1st entrance is self-destruct */\n            if eq(0, callvalue()) {\n                selfdestruct(0x00000000000000000000000000000000000000AA)\n            }\n\n            /* 2nd entrance is other rnd code execution */\n            if eq(1, callvalue()) {\n                let x := selfbalance()\n                sstore(0, x)\n            }\n        }\n        \"\"\"\n    )\n\n    cc_code = Op.SSTORE(0xCA1101, Op.CALL(100000, 0xAA, 0, 0, 0, 0, 0)) + Op.CALL(\n        100000, 0xAA, 1, 0, 0, 0, 0\n    )\n\n    balance_code = Op.SSTORE(0xBA1AA, Op.BALANCE(0xAA))\n\n    pre = {\n        # sender\n        TestAddress: Account(balance=1000000000),\n        # caller\n        to_address(0xCC): Account(balance=1000000000, code=cc_code),\n        # initial balance of 3 wei\n        to_address(0xAA): Account(balance=3, code=aa_code),\n        # stores balance of 0xaa after each tx 1\n        to_address(0xBA11): Account(code=balance_code),\n        # stores balance of 0xaa after each tx 2\n        to_address(0xBA12): Account(code=balance_code),\n    }\n\n    blocks = [\n        Block(\n            txs=[\n                # Sender invokes caller, caller invokes 0xaa:\n                # calling with 1 wei call\n                Transaction(\n                    nonce=0,\n                    to=to_address(0xCC),\n                    gas_limit=1000000,\n                    gas_price=10,\n                ),\n                # Dummy tx to store balance of 0xaa after first TX.\n                Transaction(\n                    nonce=1,\n                    to=to_address(0xBA11),\n                    gas_limit=100000,\n                    gas_price=10,\n                ),\n                # Sender calls 0xaa with 5 wei.\n                Transaction(\n                    nonce=2,\n                    to=to_address(0xAA),\n                    gas_limit=100000,\n                    gas_price=10,\n                    value=5,\n                ),\n                # Dummy tx to store balance of 0xaa after second TX.\n                Transaction(\n                    nonce=3,\n                    to=to_address(0xBA12),\n                    gas_limit=100000,\n                    gas_price=10,\n                ),\n            ],\n        ),\n    ]\n\n    post = {\n        # Check call from caller has succeeded.\n        to_address(0xCC): Account(storage={0xCA1101: 1}),\n        # Check balance of 0xaa after tx 1 is 0 wei, i.e self-destructed.\n        # Vulnerable versions should return 1 wei.\n        to_address(0xBA11): Account(storage={0xBA1AA: 0}),\n        # Check that 0xaa exists and balance after tx 2 is 5 wei.\n        # Vulnerable versions should return 6 wei.\n        to_address(0xBA12): Account(storage={0xBA1AA: 5}),\n        to_address(0xAA): Account(storage={0: 0}),\n    }\n\n    blockchain_test(pre=pre, post=post, blocks=blocks)\n
"},{"location":"tests/merge/security/test_selfdestruct_balance_bug/index/test_cases/","title":"Test Selfdestruct Balance Bug - Test Cases","text":"

Test cases generated from tests/merge/security/test_selfdestruct_balance_bug.py

Parametrized test cases generated from the test module tests/merge/security/test_selfdestruct_balance_bug.py:

test_tx_selfdestruct_balance_bug[fork=Constantinople]\ntest_tx_selfdestruct_balance_bug[fork=ConstantinopleFix]\ntest_tx_selfdestruct_balance_bug[fork=Istanbul]\ntest_tx_selfdestruct_balance_bug[fork=Berlin]\ntest_tx_selfdestruct_balance_bug[fork=London]\ntest_tx_selfdestruct_balance_bug[fork=Merge]\ntest_tx_selfdestruct_balance_bug[fork=Shanghai]\ntest_tx_selfdestruct_balance_bug[fork=Cancun]\n

This output was extracted from the result of:

fill --collect-only -q --until Cancun tests/merge/security/test_selfdestruct_balance_bug.py\n
"},{"location":"tests/shanghai/","title":"Shanghai","text":"

Documentation for tests/shanghai.

Generate fixtures for these test cases with:

fill -v tests/shanghai\n

Test cases for EVM functionality introduced in Shanghai.

"},{"location":"tests/shanghai/eip3651_warm_coinbase/","title":"EIP-3651 Warm Coinbase","text":"

Documentation for tests/shanghai/eip3651_warm_coinbase.

Generate fixtures for these test cases with:

fill -v tests/shanghai/eip3651_warm_coinbase\n
Tests EIP-3651: Warm COINBASE

Tests for EIP-3651: Warm COINBASE.

"},{"location":"tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase/","title":"Test Warm Coinbase","text":"

Documentation for tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase.py.

Generate fixtures for these test cases with:

fill -v tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase.py\n
Tests EIP-3651: Warm COINBASE

Tests for EIP-3651: Warm COINBASE.

Tests ported from:
  • ethereum/tests/pull/1082.
"},{"location":"tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase/#tests.shanghai.eip3651_warm_coinbase.test_warm_coinbase.test_warm_coinbase_call_out_of_gas","title":"test_warm_coinbase_call_out_of_gas(state_test, fork, opcode, contract_under_test_code, call_gas_exact, use_sufficient_gas)","text":"

Test that the coinbase is warm by accessing the COINBASE with each of the following opcodes:

  • CALL
  • CALLCODE
  • DELEGATECALL
  • STATICCALL
Source code in tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase.py
@pytest.mark.valid_from(\"Shanghai\")\n@pytest.mark.parametrize(\n    \"use_sufficient_gas\",\n    [True, False],\n    ids=[\"sufficient_gas\", \"insufficient_gas\"],\n)\n@pytest.mark.parametrize(\n    \"opcode,contract_under_test_code,call_gas_exact\",\n    [\n        (\n            \"call\",\n            Op.POP(Op.CALL(0, Op.COINBASE, 0, 0, 0, 0, 0)),\n            # Extra gas: COINBASE + 4*PUSH1 + 2*DUP1 + POP\n            GAS_REQUIRED_CALL_WARM_ACCOUNT + 22,\n        ),\n        (\n            \"callcode\",\n            Op.POP(Op.CALLCODE(0, Op.COINBASE, 0, 0, 0, 0, 0)),\n            # Extra gas: COINBASE + 4*PUSH1 + 2*DUP1 + POP\n            GAS_REQUIRED_CALL_WARM_ACCOUNT + 22,\n        ),\n        (\n            \"delegatecall\",\n            Op.POP(Op.DELEGATECALL(0, Op.COINBASE, 0, 0, 0, 0)),\n            # Extra: COINBASE + 3*PUSH1 + 2*DUP1 + POP\n            GAS_REQUIRED_CALL_WARM_ACCOUNT + 19,\n        ),\n        (\n            \"staticcall\",\n            Op.POP(Op.STATICCALL(0, Op.COINBASE, 0, 0, 0, 0)),\n            # Extra: COINBASE + 3*PUSH1 + 2*DUP1 + POP\n            GAS_REQUIRED_CALL_WARM_ACCOUNT + 19,\n        ),\n    ],\n    ids=[\"CALL\", \"CALLCODE\", \"DELEGATECALL\", \"STATICCALL\"],\n)\ndef test_warm_coinbase_call_out_of_gas(\n    state_test,\n    fork,\n    opcode,\n    contract_under_test_code,\n    call_gas_exact,\n    use_sufficient_gas,\n):\n\"\"\"\n    Test that the coinbase is warm by accessing the COINBASE with each\n    of the following opcodes:\n\n    - CALL\n    - CALLCODE\n    - DELEGATECALL\n    - STATICCALL\n    \"\"\"\n    env = Environment(\n        coinbase=\"0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba\",\n        difficulty=0x20000,\n        gas_limit=10000000000,\n        number=1,\n        timestamp=1000,\n    )\n    caller_address = \"0xcccccccccccccccccccccccccccccccccccccccc\"\n    contract_under_test_address = 0x100\n\n    if not use_sufficient_gas:\n        call_gas_exact -= 1\n\n    caller_code = Op.SSTORE(\n        0,\n        Op.CALL(call_gas_exact, contract_under_test_address, 0, 0, 0, 0, 0),\n    )\n\n    pre = {\n        TestAddress: Account(balance=1000000000000000000000),\n        caller_address: Account(code=caller_code),\n        to_address(contract_under_test_address): Account(code=contract_under_test_code),\n    }\n\n    tx = Transaction(\n        ty=0x0,\n        chain_id=0x0,\n        nonce=0,\n        to=caller_address,\n        gas_limit=100000000,\n        gas_price=10,\n        protected=False,\n    )\n\n    post = {}\n\n    if use_sufficient_gas and is_fork(fork=fork, which=Shanghai):\n        post[caller_address] = Account(\n            storage={\n                # On shanghai and beyond, calls with only 100 gas to\n                # coinbase will succeed.\n                0: 1,\n            }\n        )\n    else:\n        post[caller_address] = Account(\n            storage={\n                # Before shanghai, calls with only 100 gas to\n                # coinbase will fail.\n                0: 0,\n            }\n        )\n\n    state_test(\n        env=env,\n        pre=pre,\n        post=post,\n        txs=[tx],\n        tag=\"opcode_\" + opcode,\n    )\n
"},{"location":"tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase/#tests.shanghai.eip3651_warm_coinbase.test_warm_coinbase.test_warm_coinbase_gas_usage","title":"test_warm_coinbase_gas_usage(state_test, fork, opcode, code_gas_measure)","text":"

Test the gas usage of opcodes affected by assuming a warm coinbase:

  • EXTCODESIZE
  • EXTCODECOPY
  • EXTCODEHASH
  • BALANCE
  • CALL
  • CALLCODE
  • DELEGATECALL
  • STATICCALL
Source code in tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase.py
@pytest.mark.valid_from(\"Merge\")  # these tests fill for fork >= Berlin\n@pytest.mark.parametrize(\n    \"opcode,code_gas_measure\",\n    gas_measured_opcodes,\n    ids=[i[0] for i in gas_measured_opcodes],\n)\ndef test_warm_coinbase_gas_usage(state_test, fork, opcode, code_gas_measure):\n\"\"\"\n    Test the gas usage of opcodes affected by assuming a warm coinbase:\n\n    - EXTCODESIZE\n    - EXTCODECOPY\n    - EXTCODEHASH\n    - BALANCE\n    - CALL\n    - CALLCODE\n    - DELEGATECALL\n    - STATICCALL\n    \"\"\"\n    env = Environment(\n        coinbase=\"0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba\",\n        difficulty=0x20000,\n        gas_limit=10000000000,\n        number=1,\n        timestamp=1000,\n    )\n\n    measure_address = to_address(0x100)\n    pre = {\n        TestAddress: Account(balance=1000000000000000000000),\n        measure_address: Account(\n            code=code_gas_measure,\n        ),\n    }\n\n    if is_fork(fork, Shanghai):\n        expected_gas = GAS_REQUIRED_CALL_WARM_ACCOUNT  # Warm account access cost after EIP-3651\n    else:\n        expected_gas = 2600  # Cold account access cost before EIP-3651\n\n    post = {\n        measure_address: Account(\n            storage={\n                0x00: expected_gas,\n            }\n        )\n    }\n    tx = Transaction(\n        ty=0x0,\n        chain_id=0x0,\n        nonce=0,\n        to=measure_address,\n        gas_limit=100000000,\n        gas_price=10,\n        protected=False,\n    )\n\n    state_test(\n        env=env,\n        pre=pre,\n        post=post,\n        txs=[tx],\n        tag=\"opcode_\" + opcode.lower(),\n    )\n
"},{"location":"tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase/index/test_cases/","title":"Test Warm Coinbase - Test Cases","text":"

Test cases generated from tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase.py

Parametrized test cases generated from the test module tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase.py:

test_warm_coinbase_call_out_of_gas[fork=Shanghai-CALL-sufficient_gas]\ntest_warm_coinbase_call_out_of_gas[fork=Shanghai-CALL-insufficient_gas]\ntest_warm_coinbase_call_out_of_gas[fork=Shanghai-CALLCODE-sufficient_gas]\ntest_warm_coinbase_call_out_of_gas[fork=Shanghai-CALLCODE-insufficient_gas]\ntest_warm_coinbase_call_out_of_gas[fork=Shanghai-DELEGATECALL-sufficient_gas]\ntest_warm_coinbase_call_out_of_gas[fork=Shanghai-DELEGATECALL-insufficient_gas]\ntest_warm_coinbase_call_out_of_gas[fork=Shanghai-STATICCALL-sufficient_gas]\ntest_warm_coinbase_call_out_of_gas[fork=Shanghai-STATICCALL-insufficient_gas]\ntest_warm_coinbase_call_out_of_gas[fork=Cancun-CALL-sufficient_gas]\ntest_warm_coinbase_call_out_of_gas[fork=Cancun-CALL-insufficient_gas]\ntest_warm_coinbase_call_out_of_gas[fork=Cancun-CALLCODE-sufficient_gas]\ntest_warm_coinbase_call_out_of_gas[fork=Cancun-CALLCODE-insufficient_gas]\ntest_warm_coinbase_call_out_of_gas[fork=Cancun-DELEGATECALL-sufficient_gas]\ntest_warm_coinbase_call_out_of_gas[fork=Cancun-DELEGATECALL-insufficient_gas]\ntest_warm_coinbase_call_out_of_gas[fork=Cancun-STATICCALL-sufficient_gas]\ntest_warm_coinbase_call_out_of_gas[fork=Cancun-STATICCALL-insufficient_gas]\ntest_warm_coinbase_gas_usage[fork=Merge-EXTCODESIZE]\ntest_warm_coinbase_gas_usage[fork=Merge-EXTCODECOPY]\ntest_warm_coinbase_gas_usage[fork=Merge-EXTCODEHASH]\ntest_warm_coinbase_gas_usage[fork=Merge-BALANCE]\ntest_warm_coinbase_gas_usage[fork=Merge-CALL]\ntest_warm_coinbase_gas_usage[fork=Merge-CALLCODE]\ntest_warm_coinbase_gas_usage[fork=Merge-DELEGATECALL]\ntest_warm_coinbase_gas_usage[fork=Merge-STATICCALL]\ntest_warm_coinbase_gas_usage[fork=Shanghai-EXTCODESIZE]\ntest_warm_coinbase_gas_usage[fork=Shanghai-EXTCODECOPY]\ntest_warm_coinbase_gas_usage[fork=Shanghai-EXTCODEHASH]\ntest_warm_coinbase_gas_usage[fork=Shanghai-BALANCE]\ntest_warm_coinbase_gas_usage[fork=Shanghai-CALL]\ntest_warm_coinbase_gas_usage[fork=Shanghai-CALLCODE]\ntest_warm_coinbase_gas_usage[fork=Shanghai-DELEGATECALL]\ntest_warm_coinbase_gas_usage[fork=Shanghai-STATICCALL]\ntest_warm_coinbase_gas_usage[fork=Cancun-EXTCODESIZE]\ntest_warm_coinbase_gas_usage[fork=Cancun-EXTCODECOPY]\ntest_warm_coinbase_gas_usage[fork=Cancun-EXTCODEHASH]\ntest_warm_coinbase_gas_usage[fork=Cancun-BALANCE]\ntest_warm_coinbase_gas_usage[fork=Cancun-CALL]\ntest_warm_coinbase_gas_usage[fork=Cancun-CALLCODE]\ntest_warm_coinbase_gas_usage[fork=Cancun-DELEGATECALL]\ntest_warm_coinbase_gas_usage[fork=Cancun-STATICCALL]\n

This output was extracted from the result of:

fill --collect-only -q --until Cancun tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase.py\n
"},{"location":"tests/shanghai/eip3855_push0/","title":"EIP-3855 Push0","text":"

Documentation for tests/shanghai/eip3855_push0.

Generate fixtures for these test cases with:

fill -v tests/shanghai/eip3855_push0\n
Tests EIP-3855: PUSH0 Instruction

Tests for EIP-3855: PUSH0 Instruction.

"},{"location":"tests/shanghai/eip3855_push0/test_push0/","title":"Test Push0","text":"

Documentation for tests/shanghai/eip3855_push0/test_push0.py.

Generate fixtures for these test cases with:

fill -v tests/shanghai/eip3855_push0/test_push0.py\n
Tests EIP-3855: PUSH0 Instruction

Tests for EIP-3855: PUSH0 Instruction.

Tests ported from:
  • ethereum/tests/pull/1033.
"},{"location":"tests/shanghai/eip3855_push0/test_push0/#tests.shanghai.eip3855_push0.test_push0.test_push0_key_sstore","title":"test_push0_key_sstore(state_test, env, pre, post, tx, addr_1)","text":"

Use PUSH0 to set a key for SSTORE.

Source code in tests/shanghai/eip3855_push0/test_push0.py
def test_push0_key_sstore(\n    state_test: StateTestFiller,\n    env: Environment,\n    pre: dict,\n    post: dict,\n    tx: Transaction,\n    addr_1: str,\n):\n\"\"\"\n    Use PUSH0 to set a key for SSTORE.\n    \"\"\"\n    code = Op.SSTORE(Op.PUSH0, 1)\n\n    pre[addr_1] = Account(code=code)\n    post[addr_1] = Account(storage={0x00: 0x01})\n\n    state_test(env=env, pre=pre, post=post, txs=[tx], tag=\"key_sstore\")\n
"},{"location":"tests/shanghai/eip3855_push0/test_push0/#tests.shanghai.eip3855_push0.test_push0.test_push0_fill_stack","title":"test_push0_fill_stack(state_test, env, pre, post, tx, addr_1)","text":"

Fill stack with PUSH0, then OR all values and save using SSTORE.

Source code in tests/shanghai/eip3855_push0/test_push0.py
def test_push0_fill_stack(\n    state_test: StateTestFiller,\n    env: Environment,\n    pre: dict,\n    post: dict,\n    tx: Transaction,\n    addr_1: str,\n):\n\"\"\"\n    Fill stack with PUSH0, then OR all values and save using SSTORE.\n    \"\"\"\n    code = Op.PUSH0 * 1024\n    code += Op.OR * 1023\n    code += Op.SSTORE(Op.SWAP1, 1)\n\n    pre[addr_1] = Account(code=code)\n    post[addr_1] = Account(storage={0x00: 0x01})\n\n    state_test(env=env, pre=pre, post=post, txs=[tx], tag=\"fill_stack\")\n
"},{"location":"tests/shanghai/eip3855_push0/test_push0/#tests.shanghai.eip3855_push0.test_push0.test_push0_stack_overflow","title":"test_push0_stack_overflow(state_test, env, pre, post, tx, addr_1)","text":"

Stack overflow by using PUSH0 1025 times.

Source code in tests/shanghai/eip3855_push0/test_push0.py
def test_push0_stack_overflow(\n    state_test: StateTestFiller,\n    env: Environment,\n    pre: dict,\n    post: dict,\n    tx: Transaction,\n    addr_1: str,\n):\n\"\"\"\n    Stack overflow by using PUSH0 1025 times.\n    \"\"\"\n    code = Op.SSTORE(Op.PUSH0, 1)\n    code += Op.PUSH0 * 1025\n\n    pre[addr_1] = Account(code=code)\n    post[addr_1] = Account(storage={0x00: 0x00})\n\n    state_test(env=env, pre=pre, post=post, txs=[tx], tag=\"stack_overflow\")\n
"},{"location":"tests/shanghai/eip3855_push0/test_push0/#tests.shanghai.eip3855_push0.test_push0.test_push0_storage_overwrite","title":"test_push0_storage_overwrite(state_test, env, pre, post, tx, addr_1)","text":"

Update an already existing storage value.

Source code in tests/shanghai/eip3855_push0/test_push0.py
def test_push0_storage_overwrite(\n    state_test: StateTestFiller,\n    env: Environment,\n    pre: dict,\n    post: dict,\n    tx: Transaction,\n    addr_1: str,\n):\n\"\"\"\n    Update an already existing storage value.\n    \"\"\"\n    code = Op.SSTORE(Op.PUSH0, 2) + Op.SSTORE(1, Op.PUSH0)\n\n    pre[addr_1] = Account(code=code, storage={0x00: 0x0A, 0x01: 0x0A})\n    post[addr_1] = Account(storage={0x00: 0x02, 0x01: 0x00})\n\n    state_test(env=env, pre=pre, post=post, txs=[tx], tag=\"storage_overwrite\")\n
"},{"location":"tests/shanghai/eip3855_push0/test_push0/#tests.shanghai.eip3855_push0.test_push0.test_push0_during_staticcall","title":"test_push0_during_staticcall(state_test, env, pre, post, tx, addr_1)","text":"

Test PUSH0 during STATICCALL.

Source code in tests/shanghai/eip3855_push0/test_push0.py
def test_push0_during_staticcall(\n    state_test: StateTestFiller,\n    env: Environment,\n    pre: dict,\n    post: dict,\n    tx: Transaction,\n    addr_1: str,\n):\n\"\"\"\n    Test PUSH0 during STATICCALL.\n    \"\"\"\n    addr_2 = to_address(0x200)\n\n    code_1 = (\n        Op.SSTORE(0, Op.STATICCALL(100000, 0x200, 0, 0, 0, 0))\n        + Op.SSTORE(0, 1)\n        + Op.RETURNDATACOPY(0x1F, 0, 1)\n        + Op.SSTORE(1, Op.MLOAD(0))\n    )\n    code_2 = Op.MSTORE8(Op.PUSH0, 0xFF) + Op.RETURN(Op.PUSH0, 1)\n\n    pre[addr_1] = Account(code=code_1)\n    pre[addr_2] = Account(code=code_2)\n    post[addr_1] = Account(storage={0x00: 0x01, 0x01: 0xFF})\n\n    state_test(env=env, pre=pre, post=post, txs=[tx], tag=\"during_staticcall\")\n
"},{"location":"tests/shanghai/eip3855_push0/test_push0/#tests.shanghai.eip3855_push0.test_push0.test_push0_before_jumpdest","title":"test_push0_before_jumpdest(state_test, env, pre, post, tx, addr_1)","text":"

Jump to a JUMPDEST next to a PUSH0, must succeed.

Source code in tests/shanghai/eip3855_push0/test_push0.py
def test_push0_before_jumpdest(\n    state_test: StateTestFiller,\n    env: Environment,\n    pre: dict,\n    post: dict,\n    tx: Transaction,\n    addr_1: str,\n):\n\"\"\"\n    Jump to a JUMPDEST next to a PUSH0, must succeed.\n    \"\"\"\n    code = Op.PUSH1(4) + Op.JUMP + Op.PUSH0 + Op.JUMPDEST + Op.SSTORE(Op.PUSH0, 1) + Op.STOP\n\n    pre[addr_1] = Account(code=code)\n    post[addr_1] = Account(storage={0x00: 0x01})\n\n    state_test(env=env, pre=pre, post=post, txs=[tx], tag=\"before_jumpdest\")\n
"},{"location":"tests/shanghai/eip3855_push0/test_push0/#tests.shanghai.eip3855_push0.test_push0.test_push0_gas_cost","title":"test_push0_gas_cost(state_test, env, pre, post, tx, addr_1)","text":"

Test PUSH0 gas cost.

Source code in tests/shanghai/eip3855_push0/test_push0.py
def test_push0_gas_cost(\n    state_test: StateTestFiller,\n    env: Environment,\n    pre: dict,\n    post: dict,\n    tx: Transaction,\n    addr_1: str,\n):\n\"\"\"\n    Test PUSH0 gas cost.\n    \"\"\"\n    code = CodeGasMeasure(\n        code=Op.PUSH0,\n        extra_stack_items=1,\n    )\n\n    pre[addr_1] = Account(code=code)\n    post[addr_1] = Account(storage={0x00: 0x02})\n\n    state_test(env=env, pre=pre, post=post, txs=[tx], tag=\"gas_cost\")\n
"},{"location":"tests/shanghai/eip3855_push0/test_push0/index/test_cases/","title":"Test Push0 - Test Cases","text":"

Test cases generated from tests/shanghai/eip3855_push0/test_push0.py

Parametrized test cases generated from the test module tests/shanghai/eip3855_push0/test_push0.py:

test_push0_key_sstore[fork=Shanghai]\ntest_push0_key_sstore[fork=Cancun]\ntest_push0_fill_stack[fork=Shanghai]\ntest_push0_fill_stack[fork=Cancun]\ntest_push0_stack_overflow[fork=Shanghai]\ntest_push0_stack_overflow[fork=Cancun]\ntest_push0_storage_overwrite[fork=Shanghai]\ntest_push0_storage_overwrite[fork=Cancun]\ntest_push0_during_staticcall[fork=Shanghai]\ntest_push0_during_staticcall[fork=Cancun]\ntest_push0_before_jumpdest[fork=Shanghai]\ntest_push0_before_jumpdest[fork=Cancun]\ntest_push0_gas_cost[fork=Shanghai]\ntest_push0_gas_cost[fork=Cancun]\n

This output was extracted from the result of:

fill --collect-only -q --until Cancun tests/shanghai/eip3855_push0/test_push0.py\n
"},{"location":"tests/shanghai/eip3860_initcode/","title":"EIP-3860 Initcode","text":"

Documentation for tests/shanghai/eip3860_initcode.

Generate fixtures for these test cases with:

fill -v tests/shanghai/eip3860_initcode\n
Test EIP-3860: Limit and meter initcode

Tests for EIP-3860: Limit and meter initcode.

"},{"location":"tests/shanghai/eip3860_initcode/test_initcode/","title":"Test Initcode","text":"

Documentation for tests/shanghai/eip3860_initcode/test_initcode.py.

Generate fixtures for these test cases with:

fill -v tests/shanghai/eip3860_initcode/test_initcode.py\n
Test EIP-3860: Limit and meter initcode

Tests for EIP-3860: Limit and meter initcode.

Tests ported from:
  • ethereum/tests/pull/990
  • ethereum/tests/pull/1012
"},{"location":"tests/shanghai/eip3860_initcode/test_initcode/#tests.shanghai.eip3860_initcode.test_initcode.test_contract_creating_tx","title":"test_contract_creating_tx(blockchain_test, initcode)","text":"

Test cases using a contract creating transaction

Test creating a contract using a transaction using an initcode that is on/over the max allowed limit.

Generates a BlockchainTest based on the provided initcode and its length.

Source code in tests/shanghai/eip3860_initcode/test_initcode.py
@pytest.mark.parametrize(\n    \"initcode\",\n    [\n        INITCODE_ZEROS_MAX_LIMIT,\n        INITCODE_ONES_MAX_LIMIT,\n        INITCODE_ZEROS_OVER_LIMIT,\n        INITCODE_ONES_OVER_LIMIT,\n    ],\n    ids=get_initcode_name,\n)\ndef test_contract_creating_tx(blockchain_test: BlockchainTestFiller, initcode: Initcode):\n\"\"\"\n    Test cases using a contract creating transaction\n\n    Test creating a contract using a transaction using an initcode that is\n    on/over the max allowed limit.\n\n    Generates a BlockchainTest based on the provided `initcode` and its\n    length.\n    \"\"\"\n    eip_3860_active = True\n    env = Environment()\n\n    pre = {\n        TestAddress: Account(balance=1000000000000000000000),\n    }\n\n    post: Dict[Any, Any] = {}\n\n    created_contract_address = compute_create_address(\n        address=TestAddress,\n        nonce=0,\n    )\n\n    tx = Transaction(\n        nonce=0,\n        to=None,\n        data=initcode,\n        gas_limit=10000000,\n        gas_price=10,\n    )\n\n    block = Block(txs=[tx])\n\n    if len(initcode.assemble()) > MAX_INITCODE_SIZE and eip_3860_active:\n        # Initcode is above the max size, tx inclusion in the block makes\n        # it invalid.\n        post[created_contract_address] = Account.NONEXISTENT\n        tx.error = \"max initcode size exceeded\"\n        block.exception = \"max initcode size exceeded\"\n    else:\n        # Initcode is at or below the max size, tx inclusion in the block\n        # is ok and the contract is successfully created.\n        post[created_contract_address] = Account(code=Op.STOP)\n\n    blockchain_test(\n        pre=pre,\n        post=post,\n        blocks=[block],\n        genesis_environment=env,\n        tag=f\"{initcode.name}\",\n    )\n
"},{"location":"tests/shanghai/eip3860_initcode/test_initcode/#tests.shanghai.eip3860_initcode.test_initcode.TestContractCreationGasUsage","title":"TestContractCreationGasUsage","text":"

Test EIP-3860 Limit Initcode Gas Usage for a contract creating transaction, using different initcode lengths.

Generates 4 test cases that verify the gas cost behavior of a contract creating transaction:

  1. Test with exact intrinsic gas minus one, contract create fails and tx is invalid.
  2. Test with exact intrinsic gas, contract create fails, but tx is valid.
  3. Test with exact execution gas minus one, contract create fails, but tx is valid.
  4. Test with exact execution gas, contract create succeeds.

Initcode must be within valid EIP-3860 length.

Source code in tests/shanghai/eip3860_initcode/test_initcode.py
@pytest.mark.parametrize(\n    \"initcode\",\n    [\n        INITCODE_ZEROS_MAX_LIMIT,\n        INITCODE_ONES_MAX_LIMIT,\n        EMPTY_INITCODE,\n        SINGLE_BYTE_INITCODE,\n        INITCODE_ZEROS_32_BYTES,\n        INITCODE_ZEROS_33_BYTES,\n        INITCODE_ZEROS_49120_BYTES,\n        INITCODE_ZEROS_49121_BYTES,\n    ],\n    ids=get_initcode_name,\n)\n@pytest.mark.parametrize(\n    \"gas_test_case\",\n    [\n        \"too_little_intrinsic_gas\",\n        \"exact_intrinsic_gas\",\n        \"too_little_execution_gas\",\n        \"exact_execution_gas\",\n    ],\n    ids=lambda x: x,\n)\nclass TestContractCreationGasUsage:\n\"\"\"\n    Test EIP-3860 Limit Initcode Gas Usage for a contract\n    creating transaction, using different initcode lengths.\n\n    Generates 4 test cases that verify the gas cost behavior of a\n    contract creating transaction:\n\n    1. Test with exact intrinsic gas minus one, contract create fails\n        and tx is invalid.\n    2. Test with exact intrinsic gas, contract create fails,\n        but tx is valid.\n    3. Test with exact execution gas minus one, contract create fails,\n        but tx is valid.\n    4. Test with exact execution gas, contract create succeeds.\n\n    Initcode must be within valid EIP-3860 length.\n    \"\"\"\n\n    @pytest.fixture\n    def eip_3860_active(self):  # noqa: D102\n        return True\n\n    @pytest.fixture\n    def exact_intrinsic_gas(self, initcode, eip_3860_active):\n\"\"\"\n        Calculates the intrinsic tx gas cost.\n        \"\"\"\n        return calculate_create_tx_intrinsic_cost(initcode, eip_3860_active)\n\n    @pytest.fixture\n    def exact_execution_gas(self, initcode, eip_3860_active):\n\"\"\"\n        Calculates the total execution gas cost.\n        \"\"\"\n        return calculate_create_tx_execution_cost(\n            initcode,\n            eip_3860_active,\n        )\n\n    @pytest.fixture\n    def created_contract_address(self):\n\"\"\"\n        Calculates the address of the contract deployed via CREATE.\n        \"\"\"\n        return compute_create_address(\n            address=TestAddress,\n            nonce=0,\n        )\n\n    @pytest.fixture\n    def env(self) -> Environment:  # noqa: D102\n        return Environment()\n\n    @pytest.fixture\n    def pre(self) -> Dict[Any, Any]:  # noqa: D102\n        return {\n            TestAddress: Account(balance=1000000000000000000000),\n        }\n\n    @pytest.fixture\n    def tx_error(self, gas_test_case) -> str | None:\n\"\"\"\n        Test that the transaction is invalid if too little intrinsic gas is\n        specified, otherwise the tx succeeds.\n        \"\"\"\n        if gas_test_case == \"too_little_intrinsic_gas\":\n            return \"intrinsic gas too low\"\n        return None\n\n    @pytest.fixture\n    def tx(\n        self,\n        gas_test_case,\n        initcode,\n        tx_error,\n        exact_intrinsic_gas,\n        exact_execution_gas,\n    ) -> Transaction:\n\"\"\"\n        Implement the gas_test_case by setting the gas_limit of the tx\n        appropriately and test whether the tx succeeds or fails with\n        appropriate error.\n        \"\"\"\n        if gas_test_case == \"too_little_intrinsic_gas\":\n            gas_limit = exact_intrinsic_gas - 1\n        elif gas_test_case == \"exact_intrinsic_gas\":\n            gas_limit = exact_intrinsic_gas\n        elif gas_test_case == \"too_little_execution_gas\":\n            gas_limit = exact_execution_gas - 1\n        elif gas_test_case == \"exact_execution_gas\":\n            gas_limit = exact_execution_gas\n        else:\n            pytest.fail(\"Invalid gas test case provided.\")\n\n        return Transaction(\n            nonce=0,\n            to=None,\n            data=initcode,\n            gas_limit=gas_limit,\n            gas_price=10,\n            error=tx_error,\n        )\n\n    @pytest.fixture\n    def block(self, tx, tx_error) -> Block:\n\"\"\"\n        Test that the tx_error is also propagated on the Block for the case of\n        too little intrinsic gas.\n        \"\"\"\n        return Block(txs=[tx], exception=tx_error)\n\n    @pytest.fixture\n    def post(\n        self,\n        gas_test_case,\n        initcode,\n        created_contract_address,\n        exact_intrinsic_gas,\n        exact_execution_gas,\n    ) -> Dict[Any, Any]:\n\"\"\"\n        Test that contract creation fails unless enough execution gas is\n        provided.\n        \"\"\"\n        if gas_test_case == \"exact_intrinsic_gas\" and exact_intrinsic_gas == exact_execution_gas:\n            # Special scenario where the execution of the initcode and\n            # gas cost to deploy are zero\n            return {created_contract_address: Account(code=initcode.deploy_code)}\n        elif gas_test_case == \"exact_execution_gas\":\n            return {created_contract_address: Account(code=initcode.deploy_code)}\n        return {created_contract_address: Account.NONEXISTENT}\n\n    def test_gas_usage(\n        self,\n        blockchain_test: BlockchainTestFiller,\n        gas_test_case: str,\n        initcode: Initcode,\n        exact_intrinsic_gas,\n        exact_execution_gas,\n        env,\n        pre,\n        block,\n        post,\n    ):\n\"\"\"\n        Test transaction and contract creation behavior for different gas\n        limits.\n        \"\"\"\n        if (gas_test_case == \"too_little_execution_gas\") and (\n            exact_execution_gas == exact_intrinsic_gas\n        ):\n            pytest.skip(\n                \"Special case, the execution of the initcode and gas \"\n                \"cost to deploy are zero: Then this test case is \"\n                \"equivalent to that of 'test_exact_intrinsic_gas'.\"\n            )\n\n        blockchain_test(\n            pre=pre,\n            post=post,\n            blocks=[block],\n            genesis_environment=env,\n            tag=f\"{initcode.name}_{gas_test_case}\",\n        )\n
"},{"location":"tests/shanghai/eip3860_initcode/test_initcode/#tests.shanghai.eip3860_initcode.test_initcode.TestContractCreationGasUsage.test_gas_usage","title":"test_gas_usage(blockchain_test, gas_test_case, initcode, exact_intrinsic_gas, exact_execution_gas, env, pre, block, post)","text":"

Test transaction and contract creation behavior for different gas limits.

Source code in tests/shanghai/eip3860_initcode/test_initcode.py
def test_gas_usage(\n    self,\n    blockchain_test: BlockchainTestFiller,\n    gas_test_case: str,\n    initcode: Initcode,\n    exact_intrinsic_gas,\n    exact_execution_gas,\n    env,\n    pre,\n    block,\n    post,\n):\n\"\"\"\n    Test transaction and contract creation behavior for different gas\n    limits.\n    \"\"\"\n    if (gas_test_case == \"too_little_execution_gas\") and (\n        exact_execution_gas == exact_intrinsic_gas\n    ):\n        pytest.skip(\n            \"Special case, the execution of the initcode and gas \"\n            \"cost to deploy are zero: Then this test case is \"\n            \"equivalent to that of 'test_exact_intrinsic_gas'.\"\n        )\n\n    blockchain_test(\n        pre=pre,\n        post=post,\n        blocks=[block],\n        genesis_environment=env,\n        tag=f\"{initcode.name}_{gas_test_case}\",\n    )\n
"},{"location":"tests/shanghai/eip3860_initcode/test_initcode/#tests.shanghai.eip3860_initcode.test_initcode.TestCreateInitcode","title":"TestCreateInitcode","text":"

Test contract creation via the CREATE/CREATE2 opcodes that have an initcode that is on/over the max allowed limit.

Source code in tests/shanghai/eip3860_initcode/test_initcode.py
@pytest.mark.parametrize(\n    \"initcode\",\n    [\n        INITCODE_ZEROS_MAX_LIMIT,\n        INITCODE_ONES_MAX_LIMIT,\n        INITCODE_ZEROS_OVER_LIMIT,\n        INITCODE_ONES_OVER_LIMIT,\n        EMPTY_INITCODE,\n        SINGLE_BYTE_INITCODE,\n        INITCODE_ZEROS_32_BYTES,\n        INITCODE_ZEROS_33_BYTES,\n        INITCODE_ZEROS_49120_BYTES,\n        INITCODE_ZEROS_49121_BYTES,\n    ],\n    ids=get_initcode_name,\n)\n@pytest.mark.parametrize(\"opcode\", [Op.CREATE, Op.CREATE2], ids=get_create_id)\nclass TestCreateInitcode:\n\"\"\"\n    Test contract creation via the CREATE/CREATE2 opcodes that have an initcode\n    that is on/over the max allowed limit.\n    \"\"\"\n\n    @pytest.fixture\n    def create_code(self, opcode: Op, initcode: Initcode):  # noqa: D102\n        if opcode == Op.CREATE:\n            create_call = Op.CREATE(0, 0, Op.CALLDATASIZE)\n        elif opcode == Op.CREATE2:\n            create_call = Op.CREATE2(0, 0, Op.CALLDATASIZE, 0xDEADBEEF)\n        else:\n            raise Exception(\"Invalid opcode specified for test.\")\n        return (\n            Op.CALLDATACOPY(0, 0, Op.CALLDATASIZE)\n            + Op.GAS\n            + create_call\n            + Op.GAS\n            # stack: [Gas 2, Call Result, Gas 1]\n            + Op.SWAP1\n            # stack: [Call Result, Gas 2, Gas 1]\n            + Op.SSTORE(0)\n            # stack: [Gas 2, Gas 1]\n            + Op.SWAP1\n            # stack: [Gas 1, Gas 2]\n            + Op.SUB\n            # stack: [Gas 1 - Gas 2]\n            + Op.SSTORE(1)\n        )\n\n    @pytest.fixture\n    def created_contract_address(self, initcode: Initcode, opcode: Op):  # noqa: D102\n        if opcode == Op.CREATE:\n            return compute_create_address(\n                address=0x100,\n                nonce=1,\n            )\n        if opcode == Op.CREATE2:\n            return compute_create2_address(\n                address=0x100,\n                salt=0xDEADBEEF,\n                initcode=initcode.assemble(),\n            )\n        raise Exception(\"invalid opcode for generator\")\n\n    def test_create_opcode_initcode(\n        self,\n        state_test: StateTestFiller,\n        opcode: Op,\n        initcode: Initcode,\n        create_code: Yul,\n        created_contract_address: str,\n    ):\n\"\"\"\n        Test contract creation via the CREATE/CREATE2 opcodes that have an\n        initcode that is on/over the max allowed limit.\n        \"\"\"\n        eip_3860_active = True\n        env = Environment()\n\n        call_code = Op.CALLDATACOPY(0, 0, Op.CALLDATASIZE)\n        call_code += Op.SSTORE(\n            Op.CALL(5000000, 0x100, 0, 0, Op.CALLDATASIZE, 0, 0),\n            1,\n        )\n\n        pre = {\n            TestAddress: Account(balance=1000000000000000000000),\n            to_address(0x100): Account(\n                code=create_code,\n                nonce=1,\n            ),\n            to_address(0x200): Account(\n                code=call_code,\n                nonce=1,\n            ),\n        }\n\n        post: Dict[Any, Any] = {}\n\n        tx = Transaction(\n            nonce=0,\n            to=to_address(0x200),\n            data=initcode,\n            gas_limit=10000000,\n            gas_price=10,\n        )\n\n        # Calculate the expected gas of the contract creation operation\n        expected_gas_usage = (\n            CREATE_CONTRACT_BASE_GAS\n            + GAS_OPCODE_GAS\n            + (2 * PUSH_DUP_OPCODE_GAS)\n            + CALLDATASIZE_OPCODE_GAS\n        )\n        if opcode == Op.CREATE2:\n            # Extra PUSH operation\n            expected_gas_usage += PUSH_DUP_OPCODE_GAS\n\n        if len(initcode.assemble()) > MAX_INITCODE_SIZE and eip_3860_active:\n            # Call returns 0 as out of gas s[0]==1\n            post[to_address(0x200)] = Account(\n                nonce=1,\n                storage={\n                    0: 1,\n                    1: 0,\n                },\n            )\n\n            post[created_contract_address] = Account.NONEXISTENT\n            post[to_address(0x100)] = Account(\n                nonce=1,\n                storage={\n                    0: 0,\n                    1: 0,\n                },\n            )\n\n        else:\n            # The initcode is only executed if the length check succeeds\n            expected_gas_usage += initcode.execution_gas\n            # The code is only deployed if the length check succeeds\n            expected_gas_usage += initcode.deployment_gas\n\n            if opcode == Op.CREATE2:\n                # CREATE2 hashing cost should only be deducted if the initcode\n                # does not exceed the max length\n                expected_gas_usage += calculate_create2_word_cost(len(initcode.assemble()))\n\n            if eip_3860_active:\n                # Initcode word cost is only deducted if the length check\n                # succeeds\n                expected_gas_usage += calculate_initcode_word_cost(len(initcode.assemble()))\n\n            # Call returns 1 as valid initcode length s[0]==1 && s[1]==1\n            post[to_address(0x200)] = Account(\n                nonce=1,\n                storage={\n                    0: 0,\n                    1: 1,\n                },\n            )\n\n            post[created_contract_address] = Account(code=initcode.deploy_code)\n            post[to_address(0x100)] = Account(\n                nonce=2,\n                storage={\n                    0: created_contract_address,\n                    1: expected_gas_usage,\n                },\n            )\n\n        state_test(\n            env=env,\n            pre=pre,\n            post=post,\n            txs=[tx],\n            tag=f\"{initcode.name}_{opcode}\",\n        )\n
"},{"location":"tests/shanghai/eip3860_initcode/test_initcode/#tests.shanghai.eip3860_initcode.test_initcode.TestCreateInitcode.test_create_opcode_initcode","title":"test_create_opcode_initcode(state_test, opcode, initcode, create_code, created_contract_address)","text":"

Test contract creation via the CREATE/CREATE2 opcodes that have an initcode that is on/over the max allowed limit.

Source code in tests/shanghai/eip3860_initcode/test_initcode.py
def test_create_opcode_initcode(\n    self,\n    state_test: StateTestFiller,\n    opcode: Op,\n    initcode: Initcode,\n    create_code: Yul,\n    created_contract_address: str,\n):\n\"\"\"\n    Test contract creation via the CREATE/CREATE2 opcodes that have an\n    initcode that is on/over the max allowed limit.\n    \"\"\"\n    eip_3860_active = True\n    env = Environment()\n\n    call_code = Op.CALLDATACOPY(0, 0, Op.CALLDATASIZE)\n    call_code += Op.SSTORE(\n        Op.CALL(5000000, 0x100, 0, 0, Op.CALLDATASIZE, 0, 0),\n        1,\n    )\n\n    pre = {\n        TestAddress: Account(balance=1000000000000000000000),\n        to_address(0x100): Account(\n            code=create_code,\n            nonce=1,\n        ),\n        to_address(0x200): Account(\n            code=call_code,\n            nonce=1,\n        ),\n    }\n\n    post: Dict[Any, Any] = {}\n\n    tx = Transaction(\n        nonce=0,\n        to=to_address(0x200),\n        data=initcode,\n        gas_limit=10000000,\n        gas_price=10,\n    )\n\n    # Calculate the expected gas of the contract creation operation\n    expected_gas_usage = (\n        CREATE_CONTRACT_BASE_GAS\n        + GAS_OPCODE_GAS\n        + (2 * PUSH_DUP_OPCODE_GAS)\n        + CALLDATASIZE_OPCODE_GAS\n    )\n    if opcode == Op.CREATE2:\n        # Extra PUSH operation\n        expected_gas_usage += PUSH_DUP_OPCODE_GAS\n\n    if len(initcode.assemble()) > MAX_INITCODE_SIZE and eip_3860_active:\n        # Call returns 0 as out of gas s[0]==1\n        post[to_address(0x200)] = Account(\n            nonce=1,\n            storage={\n                0: 1,\n                1: 0,\n            },\n        )\n\n        post[created_contract_address] = Account.NONEXISTENT\n        post[to_address(0x100)] = Account(\n            nonce=1,\n            storage={\n                0: 0,\n                1: 0,\n            },\n        )\n\n    else:\n        # The initcode is only executed if the length check succeeds\n        expected_gas_usage += initcode.execution_gas\n        # The code is only deployed if the length check succeeds\n        expected_gas_usage += initcode.deployment_gas\n\n        if opcode == Op.CREATE2:\n            # CREATE2 hashing cost should only be deducted if the initcode\n            # does not exceed the max length\n            expected_gas_usage += calculate_create2_word_cost(len(initcode.assemble()))\n\n        if eip_3860_active:\n            # Initcode word cost is only deducted if the length check\n            # succeeds\n            expected_gas_usage += calculate_initcode_word_cost(len(initcode.assemble()))\n\n        # Call returns 1 as valid initcode length s[0]==1 && s[1]==1\n        post[to_address(0x200)] = Account(\n            nonce=1,\n            storage={\n                0: 0,\n                1: 1,\n            },\n        )\n\n        post[created_contract_address] = Account(code=initcode.deploy_code)\n        post[to_address(0x100)] = Account(\n            nonce=2,\n            storage={\n                0: created_contract_address,\n                1: expected_gas_usage,\n            },\n        )\n\n    state_test(\n        env=env,\n        pre=pre,\n        post=post,\n        txs=[tx],\n        tag=f\"{initcode.name}_{opcode}\",\n    )\n
"},{"location":"tests/shanghai/eip3860_initcode/test_initcode/index/test_cases/","title":"Test Initcode - Test Cases","text":"

Test cases generated from tests/shanghai/eip3860_initcode/test_initcode.py

Parametrized test cases generated from the test module tests/shanghai/eip3860_initcode/test_initcode.py:

test_contract_creating_tx[fork=Shanghai-max_size_zeros]\ntest_contract_creating_tx[fork=Shanghai-max_size_ones]\ntest_contract_creating_tx[fork=Shanghai-over_limit_zeros]\ntest_contract_creating_tx[fork=Shanghai-over_limit_ones]\ntest_contract_creating_tx[fork=Cancun-max_size_zeros]\ntest_contract_creating_tx[fork=Cancun-max_size_ones]\ntest_contract_creating_tx[fork=Cancun-over_limit_zeros]\ntest_contract_creating_tx[fork=Cancun-over_limit_ones]\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestContractCreationGasUsage\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\nTestCreateInitcode\n

This output was extracted from the result of:

fill --collect-only -q --until Cancun tests/shanghai/eip3860_initcode/test_initcode.py\n
"},{"location":"tests/shanghai/eip4895_withdrawals/","title":"EIP-4895 Withdrawals","text":"

Documentation for tests/shanghai/eip4895_withdrawals.

Generate fixtures for these test cases with:

fill -v tests/shanghai/eip4895_withdrawals\n
Tests EIP-4895: Beacon chain withdrawals

Test cases for EIP-4895: Beacon chain push withdrawals as operations.

"},{"location":"tests/shanghai/eip4895_withdrawals/test_withdrawals/","title":"Test Withdrawals","text":"

Documentation for tests/shanghai/eip4895_withdrawals/test_withdrawals.py.

Generate fixtures for these test cases with:

fill -v tests/shanghai/eip4895_withdrawals/test_withdrawals.py\n
Tests EIP-4895: Beacon chain withdrawals

Test cases for EIP-4895: Beacon chain push withdrawals as operations.

"},{"location":"tests/shanghai/eip4895_withdrawals/test_withdrawals/#tests.shanghai.eip4895_withdrawals.test_withdrawals.TestUseValueInTx","title":"TestUseValueInTx","text":"

Test that the value from a withdrawal can be used in a transaction:

  1. tx_in_withdrawals_block: Test that the withdrawal value can not be used by a transaction in the same block as the withdrawal.

  2. tx_after_withdrawals_block: Test that the withdrawal value can be used by a transaction in the subsequent block.

Source code in tests/shanghai/eip4895_withdrawals/test_withdrawals.py
@pytest.mark.parametrize(\n    \"test_case\",\n    [\"tx_in_withdrawals_block\", \"tx_after_withdrawals_block\"],\n    ids=lambda x: x,\n)\nclass TestUseValueInTx:\n\"\"\"\n    Test that the value from a withdrawal can be used in a transaction:\n\n    1. `tx_in_withdrawals_block`: Test that the withdrawal value can not be used by a transaction\n        in the same block as the withdrawal.\n\n    2. `tx_after_withdrawals_block`: Test that the withdrawal value can be used by a transaction\n        in the subsequent block.\n    \"\"\"\n\n    @pytest.fixture\n    def tx(self):  # noqa: D102\n        # Transaction sent from the `TestAddress`, which has 0 balance at start\n        return Transaction(\n            nonce=0,\n            gas_price=ONE_GWEI,\n            gas_limit=21000,\n            to=to_address(0x100),\n            data=\"0x\",\n        )\n\n    @pytest.fixture\n    def withdrawal(self, tx: Transaction):  # noqa: D102\n        return Withdrawal(\n            index=0,\n            validator=0,\n            address=TestAddress,\n            amount=tx.gas_limit + 1,\n        )\n\n    @pytest.fixture\n    def blocks(self, tx: Transaction, withdrawal: Withdrawal, test_case):  # noqa: D102\n        if test_case == \"tx_in_withdrawals_block\":\n            return [\n                Block(\n                    txs=[tx.with_error(\"intrinsic gas too low: have 0, want 21000\")],\n                    withdrawals=[\n                        withdrawal,\n                    ],\n                    exception=\"Transaction without funds\",\n                )\n            ]\n        if test_case == \"tx_after_withdrawals_block\":\n            return [\n                Block(\n                    txs=[],\n                    withdrawals=[\n                        withdrawal,\n                    ],\n                ),\n                Block(\n                    txs=[tx],\n                    withdrawals=[],\n                ),\n            ]\n        raise Exception(\"Invalid test case.\")\n\n    @pytest.fixture\n    def post(self, test_case: str) -> Dict:  # noqa: D102\n        if test_case == \"tx_in_withdrawals_block\":\n            return {}\n        if test_case == \"tx_after_withdrawals_block\":\n            return {TestAddress: Account(balance=ONE_GWEI)}\n        raise Exception(\"Invalid test case.\")\n\n    def test_use_value_in_tx(\n        self,\n        blockchain_test: BlockchainTestFiller,\n        post: dict,\n        blocks: List[Block],\n    ):\n\"\"\"\n        Test sending withdrawal value in a transaction.\n        \"\"\"\n        pre = {TestAddress: Account(balance=0)}\n        blockchain_test(pre=pre, post=post, blocks=blocks)\n
"},{"location":"tests/shanghai/eip4895_withdrawals/test_withdrawals/#tests.shanghai.eip4895_withdrawals.test_withdrawals.TestUseValueInTx.test_use_value_in_tx","title":"test_use_value_in_tx(blockchain_test, post, blocks)","text":"

Test sending withdrawal value in a transaction.

Source code in tests/shanghai/eip4895_withdrawals/test_withdrawals.py
def test_use_value_in_tx(\n    self,\n    blockchain_test: BlockchainTestFiller,\n    post: dict,\n    blocks: List[Block],\n):\n\"\"\"\n    Test sending withdrawal value in a transaction.\n    \"\"\"\n    pre = {TestAddress: Account(balance=0)}\n    blockchain_test(pre=pre, post=post, blocks=blocks)\n
"},{"location":"tests/shanghai/eip4895_withdrawals/test_withdrawals/#tests.shanghai.eip4895_withdrawals.test_withdrawals.test_use_value_in_contract","title":"test_use_value_in_contract(blockchain_test)","text":"

Test sending value from contract that has not received a withdrawal

Source code in tests/shanghai/eip4895_withdrawals/test_withdrawals.py
def test_use_value_in_contract(blockchain_test: BlockchainTestFiller):\n\"\"\"\n    Test sending value from contract that has not received a withdrawal\n    \"\"\"\n    SEND_ONE_GWEI = Op.SSTORE(\n        Op.NUMBER,\n        Op.CALL(Op.GAS, 0x200, 1000000000, 0, 0, 0, 0),\n    )\n\n    pre = {\n        TestAddress: Account(balance=1000000000000000000000, nonce=0),\n        to_address(0x100): Account(balance=0, code=SEND_ONE_GWEI),\n        to_address(0x200): Account(balance=0),\n    }\n    tx = Transaction(\n        # Transaction sent from the `TestAddress`, which has 0 balance at start\n        nonce=0,\n        value=0,\n        gas_price=10,\n        gas_limit=100000,\n        to=to_address(0x100),\n        data=\"0x\",\n    )\n    withdrawal = Withdrawal(\n        index=0,\n        validator=0,\n        address=to_address(0x100),\n        amount=1,\n    )\n\n    blocks = [\n        Block(\n            txs=[tx.with_nonce(0)],\n            withdrawals=[withdrawal],\n        ),\n        Block(\n            txs=[tx.with_nonce(1)],  # Same tx again, just increase nonce\n        ),\n    ]\n    post = {\n        to_address(0x100): Account(\n            storage={\n                0x1: 0x0,  # Call fails on the first attempt\n                0x2: 0x1,  # Succeeds on the second attempt\n            }\n        ),\n        to_address(0x200): Account(\n            balance=ONE_GWEI,\n        ),\n    }\n\n    blockchain_test(pre=pre, post=post, blocks=blocks)\n
"},{"location":"tests/shanghai/eip4895_withdrawals/test_withdrawals/#tests.shanghai.eip4895_withdrawals.test_withdrawals.test_balance_within_block","title":"test_balance_within_block(blockchain_test)","text":"

Test Withdrawal balance increase within the same block, inside contract call.

Source code in tests/shanghai/eip4895_withdrawals/test_withdrawals.py
def test_balance_within_block(blockchain_test: BlockchainTestFiller):\n\"\"\"\n    Test Withdrawal balance increase within the same block,\n    inside contract call.\n    \"\"\"\n    SAVE_BALANCE_ON_BLOCK_NUMBER = Op.SSTORE(\n        Op.NUMBER,\n        Op.BALANCE(Op.CALLDATALOAD(0)),\n    )\n    pre = {\n        TestAddress: Account(balance=1000000000000000000000, nonce=0),\n        to_address(0x100): Account(\n            code=SAVE_BALANCE_ON_BLOCK_NUMBER,\n        ),\n        to_address(0x200): Account(\n            balance=ONE_GWEI,\n        ),\n    }\n    blocks = [\n        Block(\n            txs=[\n                Transaction(\n                    nonce=0,\n                    gas_limit=100000,\n                    to=to_address(0x100),\n                    data=to_hash(0x200),\n                )\n            ],\n            withdrawals=[\n                Withdrawal(\n                    index=0,\n                    validator=0,\n                    address=to_address(0x200),\n                    amount=1,\n                )\n            ],\n        ),\n        Block(\n            txs=[\n                Transaction(\n                    nonce=1,\n                    gas_limit=100000,\n                    to=to_address(0x100),\n                    data=to_hash(0x200),\n                )\n            ]\n        ),\n    ]\n\n    post = {\n        to_address(0x100): Account(\n            storage={\n                1: ONE_GWEI,\n                2: 2 * ONE_GWEI,\n            }\n        )\n    }\n\n    blockchain_test(pre=pre, post=post, blocks=blocks)\n
"},{"location":"tests/shanghai/eip4895_withdrawals/test_withdrawals/#tests.shanghai.eip4895_withdrawals.test_withdrawals.TestMultipleWithdrawalsSameAddress","title":"TestMultipleWithdrawalsSameAddress","text":"

Test that multiple withdrawals can be sent to the same address in:

  1. A single block.

  2. Multiple blocks.

Source code in tests/shanghai/eip4895_withdrawals/test_withdrawals.py
@pytest.mark.parametrize(\"test_case\", [\"single_block\", \"multiple_blocks\"])\nclass TestMultipleWithdrawalsSameAddress:\n\"\"\"\n    Test that multiple withdrawals can be sent to the same address in:\n\n    1. A single block.\n\n    2. Multiple blocks.\n    \"\"\"\n\n    ADDRESSES = [\n        to_address(0x0),  # Zero address\n        to_address(0x1),  # Pre-compiles\n        to_address(0x2),\n        to_address(0x3),\n        to_address(0x4),\n        to_address(0x5),\n        to_address(0x6),\n        to_address(0x7),\n        to_address(0x8),\n        to_address(0x9),\n        to_address(2**160 - 1),\n    ]\n\n    @pytest.fixture\n    def blocks(self, test_case: str):  # noqa: D102\n        if test_case == \"single_block\":\n            # Many repeating withdrawals of the same accounts in the same\n            # block.\n            return [\n                Block(\n                    withdrawals=[\n                        Withdrawal(\n                            index=i,\n                            validator=i,\n                            address=self.ADDRESSES[i % len(self.ADDRESSES)],\n                            amount=1,\n                        )\n                        for i in range(len(self.ADDRESSES) * 16)\n                    ],\n                ),\n            ]\n        if test_case == \"multiple_blocks\":\n            # Similar test but now use multiple blocks each with multiple\n            # withdrawals to the same withdrawal address.\n            return [\n                Block(\n                    withdrawals=[\n                        Withdrawal(\n                            index=i * 16 + j,\n                            validator=i,\n                            address=self.ADDRESSES[i],\n                            amount=1,\n                        )\n                        for j in range(16)\n                    ],\n                )\n                for i in range(len(self.ADDRESSES))\n            ]\n        raise Exception(\"Invalid test case.\")\n\n    def test_multiple_withdrawals_same_address(\n        self,\n        blockchain_test: BlockchainTestFiller,\n        test_case: str,\n        blocks: List[Block],\n    ):\n\"\"\"\n        Test Withdrawals can be done to the same address multiple times in\n        the same block.\n        \"\"\"\n        pre = {\n            TestAddress: Account(balance=1000000000000000000000, nonce=0),\n        }\n        for addr in self.ADDRESSES:\n            pre[addr] = Account(\n                # set a storage value unconditionally on call\n                code=Op.SSTORE(Op.NUMBER, 1),\n            )\n\n        # Expected post is the same for both test cases.\n        post = {}\n        for addr in self.ADDRESSES:\n            post[addr] = Account(\n                balance=16 * ONE_GWEI,\n                storage={},\n            )\n\n        blockchain_test(pre=pre, post=post, blocks=blocks, tag=test_case)\n
"},{"location":"tests/shanghai/eip4895_withdrawals/test_withdrawals/#tests.shanghai.eip4895_withdrawals.test_withdrawals.TestMultipleWithdrawalsSameAddress.test_multiple_withdrawals_same_address","title":"test_multiple_withdrawals_same_address(blockchain_test, test_case, blocks)","text":"

Test Withdrawals can be done to the same address multiple times in the same block.

Source code in tests/shanghai/eip4895_withdrawals/test_withdrawals.py
def test_multiple_withdrawals_same_address(\n    self,\n    blockchain_test: BlockchainTestFiller,\n    test_case: str,\n    blocks: List[Block],\n):\n\"\"\"\n    Test Withdrawals can be done to the same address multiple times in\n    the same block.\n    \"\"\"\n    pre = {\n        TestAddress: Account(balance=1000000000000000000000, nonce=0),\n    }\n    for addr in self.ADDRESSES:\n        pre[addr] = Account(\n            # set a storage value unconditionally on call\n            code=Op.SSTORE(Op.NUMBER, 1),\n        )\n\n    # Expected post is the same for both test cases.\n    post = {}\n    for addr in self.ADDRESSES:\n        post[addr] = Account(\n            balance=16 * ONE_GWEI,\n            storage={},\n        )\n\n    blockchain_test(pre=pre, post=post, blocks=blocks, tag=test_case)\n
"},{"location":"tests/shanghai/eip4895_withdrawals/test_withdrawals/#tests.shanghai.eip4895_withdrawals.test_withdrawals.test_many_withdrawals","title":"test_many_withdrawals(blockchain_test)","text":"

Test Withdrawals with a count of N withdrawals in a single block where N is a high number not expected to be seen in mainnet.

Source code in tests/shanghai/eip4895_withdrawals/test_withdrawals.py
def test_many_withdrawals(blockchain_test: BlockchainTestFiller):\n\"\"\"\n    Test Withdrawals with a count of N withdrawals in a single block where\n    N is a high number not expected to be seen in mainnet.\n    \"\"\"\n    N = 400\n    pre = {\n        TestAddress: Account(balance=1000000000000000000000, nonce=0),\n    }\n    withdrawals = []\n    post = {}\n    for i in range(N):\n        addr = to_address(0x100 * i)\n        amount = i * 1\n        pre[addr] = Account(\n            code=Op.SSTORE(Op.NUMBER, 1),\n        )\n        withdrawals.append(\n            Withdrawal(\n                index=i,\n                validator=i,\n                address=addr,\n                amount=amount,\n            )\n        )\n        post[addr] = Account(\n            code=Op.SSTORE(Op.NUMBER, 1),\n            balance=amount * ONE_GWEI,\n            storage={},\n        )\n\n    blocks = [\n        Block(\n            withdrawals=withdrawals,\n        ),\n    ]\n\n    blockchain_test(pre=pre, post=post, blocks=blocks)\n
"},{"location":"tests/shanghai/eip4895_withdrawals/test_withdrawals/#tests.shanghai.eip4895_withdrawals.test_withdrawals.test_self_destructing_account","title":"test_self_destructing_account(blockchain_test)","text":"

Test withdrawals can be done to self-destructed accounts. Account 0x100 self-destructs and sends all its balance to 0x200. Then, a withdrawal is received at 0x100 with 99 wei.

Source code in tests/shanghai/eip4895_withdrawals/test_withdrawals.py
def test_self_destructing_account(blockchain_test: BlockchainTestFiller):\n\"\"\"\n    Test withdrawals can be done to self-destructed accounts.\n    Account `0x100` self-destructs and sends all its balance to `0x200`.\n    Then, a withdrawal is received at `0x100` with 99 wei.\n    \"\"\"\n    pre = {\n        TestAddress: Account(balance=1000000000000000000000, nonce=0),\n        to_address(0x100): Account(\n            code=Op.SELFDESTRUCT(Op.CALLDATALOAD(0)),\n            balance=(100 * ONE_GWEI),\n        ),\n        to_address(0x200): Account(\n            balance=0,\n        ),\n    }\n\n    tx_1 = Transaction(\n        # Transaction sent from the `TestAddress`, that calls a\n        # self-destructing contract.\n        nonce=0,\n        gas_price=10,\n        gas_limit=100000,\n        to=to_address(0x100),\n        data=to_hash(0x200),\n    )\n\n    withdrawal = Withdrawal(\n        index=0,\n        validator=0,\n        address=to_address(0x100),\n        amount=(99),\n    )\n\n    block = Block(\n        txs=[tx_1],\n        withdrawals=[withdrawal],\n    )\n\n    post = {\n        to_address(0x100): Account(\n            code=None,\n            balance=(99 * ONE_GWEI),\n        ),\n        to_address(0x200): Account(\n            code=None,\n            balance=(100 * ONE_GWEI),\n        ),\n    }\n\n    blockchain_test(pre=pre, post=post, blocks=[block])\n
"},{"location":"tests/shanghai/eip4895_withdrawals/test_withdrawals/#tests.shanghai.eip4895_withdrawals.test_withdrawals.test_newly_created_contract","title":"test_newly_created_contract(blockchain_test, include_value_in_tx, request)","text":"

Test Withdrawing to a newly created contract.

Source code in tests/shanghai/eip4895_withdrawals/test_withdrawals.py
@pytest.mark.parametrize(\n    \"include_value_in_tx\",\n    [False, True],\n    ids=[\"without_tx_value\", \"with_tx_value\"],\n)\ndef test_newly_created_contract(\n    blockchain_test: BlockchainTestFiller,\n    include_value_in_tx: bool,\n    request,\n):\n\"\"\"\n    Test Withdrawing to a newly created contract.\n    \"\"\"\n    created_contract = compute_create_address(TestAddress, 0)\n\n    pre = {\n        TestAddress: Account(balance=1000000000000000000000, nonce=0),\n    }\n\n    initcode = Op.RETURN(0, 1)\n\n    tx = Transaction(\n        # Transaction sent from the `TestAddress`, that creates a\n        # new contract.\n        nonce=0,\n        gas_price=10,\n        gas_limit=1000000,\n        to=None,\n        data=initcode,\n    )\n\n    withdrawal = Withdrawal(\n        index=0,\n        validator=0,\n        address=created_contract,\n        amount=1,\n    )\n\n    block = Block(\n        txs=[tx],\n        withdrawals=[withdrawal],\n    )\n\n    post = {\n        created_contract: Account(\n            code=\"0x00\",\n            balance=ONE_GWEI,\n        ),\n    }\n    if include_value_in_tx:\n        tx.value = ONE_GWEI\n        post[created_contract].balance = 2 * ONE_GWEI\n\n    tag = request.node.callspec.id.split(\"-\")[0]  # remove fork; brittle\n    blockchain_test(pre=pre, post=post, blocks=[block], tag=tag)\n
"},{"location":"tests/shanghai/eip4895_withdrawals/test_withdrawals/#tests.shanghai.eip4895_withdrawals.test_withdrawals.test_no_evm_execution","title":"test_no_evm_execution(blockchain_test)","text":"

Test Withdrawals don't trigger EVM execution.

Source code in tests/shanghai/eip4895_withdrawals/test_withdrawals.py
def test_no_evm_execution(blockchain_test: BlockchainTestFiller):\n\"\"\"\n    Test Withdrawals don't trigger EVM execution.\n    \"\"\"\n    pre = {\n        TestAddress: Account(balance=1000000000000000000000, nonce=0),\n        to_address(0x100): Account(\n            code=Op.SSTORE(Op.NUMBER, 1),\n        ),\n        to_address(0x200): Account(\n            code=Op.SSTORE(Op.NUMBER, 1),\n        ),\n        to_address(0x300): Account(\n            code=Op.SSTORE(Op.NUMBER, 1),\n        ),\n        to_address(0x400): Account(\n            code=Op.SSTORE(Op.NUMBER, 1),\n        ),\n    }\n    blocks = [\n        Block(\n            txs=[\n                Transaction(\n                    nonce=0,\n                    gas_limit=100000,\n                    to=to_address(0x300),\n                ),\n                Transaction(\n                    nonce=1,\n                    gas_limit=100000,\n                    to=to_address(0x400),\n                ),\n            ],\n            withdrawals=[\n                Withdrawal(\n                    index=0,\n                    validator=0,\n                    address=to_address(0x100),\n                    amount=1,\n                ),\n                Withdrawal(\n                    index=1,\n                    validator=1,\n                    address=to_address(0x200),\n                    amount=1,\n                ),\n            ],\n        ),\n        Block(\n            txs=[\n                Transaction(\n                    nonce=2,\n                    gas_limit=100000,\n                    to=to_address(0x100),\n                ),\n                Transaction(\n                    nonce=3,\n                    gas_limit=100000,\n                    to=to_address(0x200),\n                ),\n            ],\n            withdrawals=[\n                Withdrawal(\n                    index=0,\n                    validator=0,\n                    address=to_address(0x300),\n                    amount=1,\n                ),\n                Withdrawal(\n                    index=1,\n                    validator=1,\n                    address=to_address(0x400),\n                    amount=1,\n                ),\n            ],\n        ),\n    ]\n\n    post = {\n        to_address(0x100): Account(storage={2: 1}),\n        to_address(0x200): Account(storage={2: 1}),\n        to_address(0x300): Account(storage={1: 1}),\n        to_address(0x400): Account(storage={1: 1}),\n    }\n\n    blockchain_test(pre=pre, post=post, blocks=blocks)\n
"},{"location":"tests/shanghai/eip4895_withdrawals/test_withdrawals/#tests.shanghai.eip4895_withdrawals.test_withdrawals.test_zero_amount","title":"test_zero_amount(blockchain_test, test_case)","text":"

Test withdrawals with zero amount for the following cases, all withdrawals are included in one block:

  1. Two withdrawals of zero amount to two different addresses; one to an untouched account, one to an account with a balance.
  2. As 1., but with an additional withdrawal with positive value.
  3. As 2., but with an additional withdrawal containing the maximum value possible.
  4. As 3., but with order of withdrawals in the block reversed.
Source code in tests/shanghai/eip4895_withdrawals/test_withdrawals.py
@pytest.mark.parametrize(\n    \"test_case\",\n    [case for case in ZeroAmountTestCases],\n    ids=[case.value for case in ZeroAmountTestCases],\n)\ndef test_zero_amount(\n    blockchain_test: BlockchainTestFiller,\n    test_case: ZeroAmountTestCases,\n):\n\"\"\"\n    Test withdrawals with zero amount for the following cases, all withdrawals\n    are included in one block:\n\n    1. Two withdrawals of zero amount to two different addresses; one to an\n       untouched account, one to an account with a balance.\n    2. As 1., but with an additional withdrawal with positive value.\n    3. As 2., but with an additional withdrawal containing the maximum value\n       possible.\n    4. As 3., but with order of withdrawals in the block reversed.\n\n    \"\"\"\n    pre = {\n        TestAddress: Account(balance=1000000000000000000000, nonce=0),\n        to_address(0x200): Account(\n            code=\"0x00\",\n            balance=0,\n        ),\n    }\n\n    all_withdrawals = [\n        # No value, untouched account\n        Withdrawal(\n            index=0,\n            validator=0,\n            address=to_address(0x100),\n            amount=0,\n        ),\n        # No value, touched account\n        Withdrawal(\n            index=0,\n            validator=0,\n            address=to_address(0x200),\n            amount=0,\n        ),\n        # Withdrawal with value\n        Withdrawal(\n            index=1,\n            validator=0,\n            address=to_address(0x300),\n            amount=1,\n        ),\n        # Withdrawal with maximum amount\n        Withdrawal(\n            index=2,\n            validator=0,\n            address=to_address(0x400),\n            amount=2**64 - 1,\n        ),\n    ]\n    all_post = {\n        to_address(0x100): Account.NONEXISTENT,\n        to_address(0x200): Account(code=\"0x00\", balance=0),\n        to_address(0x300): Account(balance=ONE_GWEI),\n        to_address(0x400): Account(balance=(2**64 - 1) * ONE_GWEI),\n    }\n\n    withdrawals: List[Withdrawal] = []\n    post: Mapping[str, Account | object] = {}\n    if test_case == ZeroAmountTestCases.TWO_ZERO:\n        withdrawals = all_withdrawals[0:2]\n        post = {\n            account: all_post[account]\n            for account in post\n            if account in [to_address(0x100), to_address(0x200)]\n        }\n    elif test_case == ZeroAmountTestCases.THREE_ONE_WITH_VALUE:\n        withdrawals = all_withdrawals[0:3]\n        post = {\n            account: all_post[account]\n            for account in post\n            if account\n            in [\n                to_address(0x100),\n                to_address(0x200),\n                to_address(0x300),\n            ]\n        }\n    elif test_case == ZeroAmountTestCases.FOUR_ONE_WITH_MAX:\n        withdrawals = all_withdrawals\n        post = all_post\n    elif test_case == ZeroAmountTestCases.FOUR_ONE_WITH_MAX_REVERSED:\n        withdrawals = all_withdrawals\n        withdrawals.reverse()\n        set_withdrawal_index(withdrawals)\n        post = all_post\n    else:\n        raise Exception(\"Unknown test case.\")\n\n    blockchain_test(\n        pre=pre,\n        # TODO: Fix in BlockchainTest? post: Mapping[str, Account | object]\n        # to allow for Account.NONEXISTENT\n        post=post,  # type: ignore\n        blocks=[Block(withdrawals=withdrawals)],\n        tag=test_case.value,\n    )\n
"},{"location":"tests/shanghai/eip4895_withdrawals/test_withdrawals/#tests.shanghai.eip4895_withdrawals.test_withdrawals.test_large_amount","title":"test_large_amount(blockchain_test)","text":"

Test Withdrawals that have a large gwei amount, so that (gwei * 1e9) could overflow uint64 but not uint256.

Source code in tests/shanghai/eip4895_withdrawals/test_withdrawals.py
def test_large_amount(blockchain_test: BlockchainTestFiller):\n\"\"\"\n    Test Withdrawals that have a large gwei amount, so that (gwei * 1e9)\n    could overflow uint64 but not uint256.\n    \"\"\"\n    pre = {\n        TestAddress: Account(balance=1000000000000000000000, nonce=0),\n    }\n\n    withdrawals: List[Withdrawal] = []\n    amounts: List[int] = [\n        (2**35),\n        (2**64) - 1,\n        (2**63) + 1,\n        (2**63),\n        (2**63) - 1,\n    ]\n\n    post = {}\n\n    for i, amount in enumerate(amounts):\n        addr = to_address(0x100 * (i + 1))\n        withdrawals.append(\n            Withdrawal(\n                index=i,\n                validator=i,\n                address=addr,\n                amount=amount,\n            )\n        )\n        post[addr] = Account(balance=(amount * ONE_GWEI))\n\n    blocks = [\n        Block(\n            withdrawals=withdrawals,\n        )\n    ]\n    blockchain_test(pre=pre, post=post, blocks=blocks)\n
"},{"location":"tests/shanghai/eip4895_withdrawals/test_withdrawals/index/test_cases/","title":"Test Withdrawals - Test Cases","text":"

Test cases generated from tests/shanghai/eip4895_withdrawals/test_withdrawals.py

Parametrized test cases generated from the test module tests/shanghai/eip4895_withdrawals/test_withdrawals.py:

TestUseValueInTx\nTestUseValueInTx\nTestUseValueInTx\nTestUseValueInTx\ntest_use_value_in_contract[fork=Shanghai]\ntest_use_value_in_contract[fork=Cancun]\ntest_balance_within_block[fork=Shanghai]\ntest_balance_within_block[fork=Cancun]\nTestMultipleWithdrawalsSameAddress\nTestMultipleWithdrawalsSameAddress\nTestMultipleWithdrawalsSameAddress\nTestMultipleWithdrawalsSameAddress\ntest_many_withdrawals[fork=Shanghai]\ntest_many_withdrawals[fork=Cancun]\ntest_self_destructing_account[fork=Shanghai]\ntest_self_destructing_account[fork=Cancun]\ntest_newly_created_contract[fork=Shanghai-without_tx_value]\ntest_newly_created_contract[fork=Shanghai-with_tx_value]\ntest_newly_created_contract[fork=Cancun-without_tx_value]\ntest_newly_created_contract[fork=Cancun-with_tx_value]\ntest_no_evm_execution[fork=Shanghai]\ntest_no_evm_execution[fork=Cancun]\ntest_zero_amount[fork=Shanghai-two_withdrawals_no_value]\ntest_zero_amount[fork=Shanghai-three_withdrawals_one_with_value]\ntest_zero_amount[fork=Shanghai-four_withdrawals_one_with_value_one_with_max]\ntest_zero_amount[fork=Shanghai-four_withdrawals_one_with_value_one_with_max_reversed_order]\ntest_zero_amount[fork=Cancun-two_withdrawals_no_value]\ntest_zero_amount[fork=Cancun-three_withdrawals_one_with_value]\ntest_zero_amount[fork=Cancun-four_withdrawals_one_with_value_one_with_max]\ntest_zero_amount[fork=Cancun-four_withdrawals_one_with_value_one_with_max_reversed_order]\ntest_large_amount[fork=Shanghai]\ntest_large_amount[fork=Cancun]\n

This output was extracted from the result of:

fill --collect-only -q --until Cancun tests/shanghai/eip4895_withdrawals/test_withdrawals.py\n
"},{"location":"tutorials/blockchain/","title":"Blockchain Tests","text":"

This tutorial teaches you to create a blockchain execution specification test. These tests verify that a blockchain, starting from a defined pre-state, will process given blocks and arrive at a defined post-state.

"},{"location":"tutorials/blockchain/#pre-requisites","title":"Pre-requisites","text":"

Before proceeding with this tutorial, it is assumed that you have prior knowledge and experience with the following:

  • Set up and run an execution specification test as outlined in the quick start guide.
  • Understand how to read a blockchain test.
  • Know the basics of Yul, which is an EVM assembly language.
  • Familiarity with Python.
  • Understand how to write an execution spec state transition test.
"},{"location":"tutorials/blockchain/#example-tests","title":"Example Tests","text":"

In this tutorial we will go over [test_block_number] in test_block_example.py(https://github.com/ethereum/execution-spec-tests/tree/main/tests/example/test_block_example.py#L19).

It is assumed you have already gone through the state transition test tutorial. Only new concepts will be discussed.

"},{"location":"tutorials/blockchain/#smart-contract","title":"Smart Contract","text":"

A smart contract is defined that is called by each transaction in the test. It stores a pointer to storage at storage[0]. When it is called storage cell 0 gets the current block number, and the pointer is incremented to the next value.

contract_addr: Account(\n    balance=1000000000000000000000,\n    code=Yul(\n\"\"\"\n        {\n            let next_slot := sload(0)\n            sstore(next_slot, number())\n            sstore(0, add(next_slot, 1))\n        }\n        \"\"\"\n    ),\n    storage={\n        0x00: 0x01,\n    },\n),\n
"},{"location":"tutorials/blockchain/#transaction-generator","title":"Transaction Generator","text":"

The transactions used in this test are nearly identical. Their only different is the nonce value which needs to be incremented.

def tx_generator():\n    nonce = 0  # Initial value\n    while True:\n        tx = Transaction(\n            ty=0x0,\n            chain_id=0x0,\n            nonce=nonce,\n            to=contractAddr,\n            gas_limit=500000,\n            gas_price=10,\n        )\n        nonce = nonce + 1\n        yield tx\n\ntx_generator = tx_generator()\n

This looks like an infinite loop but it isn't because this is a generator function. When generator encounters the yield keyword it returns the value and stops execution, keeping a copy of all the local variables, until it is called again. Hence infinite loops inside a generator are not a problem as long as they include yield. This code section is responsible for creating the Transaction object and incrementing the nonce.

Every time the function tx_generator() is called, it returns a new generator with a nonce of zero. To increment the nonce we need to use the same generator. We assign this generator to tx_generator.

"},{"location":"tutorials/blockchain/#blocks","title":"Blocks","text":"

Each integer in the tx_per_block array is the number of transactions in a block. The genesis block is block 0 (no transactions). It follows that we have 2 transactions in block 1, 0 in block two, 4 in block 3, ..., and 50 in block 9.

tx_per_block = [2, 0, 4, 8, 0, 0, 20, 1, 50]\n

The code section that creates the blocks is a bit complex in this test. For some simpler definitions of Block creation you can browse tests within test_withdrawals.py.

blocks = map(\n    lambda len: Block(\n        txs=list(map(lambda x: next(tx_generator), range(len)))\n    ),\n    tx_per_block,\n)\n

We use lambda notation to specify short functions. In this case, the function doesn't actually care about its input, it just returns the next transaction from the generator.

lambda x: next(tx_generator)\n

Python uses range(n) to create a list of numbers from 0 to n-1. Among other things, it's a simple way to create a list of n values.

range(len)\n

The map function runs the function (the first parameter) on every element of the list (the second parameter). Putting together what we know, it means that it runs next(tx_generator) len times, giving us len transactions. We then use list to turn the transactions into a list that we can provide as the txs parameter to the Block constructor.

list(map(lambda x: next(tx_generator), range(len)))\n

The outer lambda function takes an integer, len, and creates a Block object with len transactions. This function is then run on every value of tx_per_block to generate the blocks.

blocks = map(\n    lambda len: Block(\n        txs=list of len transactions\n    ),\n    tx_per_block,\n)\n

For example, if we had tx_per_block = [0,2,4], we'd get this result:

blocks = [\n    Blocks(txs=[]),\n    Blocks(txs=[next(tx_generator), next(tx_generator)]),\n    Blocks(txs=[next(tx_generator), next(tx_generator), next(tx_generator), next(tx_generator)])        \n]\n
"},{"location":"tutorials/blockchain/#post-state","title":"Post State","text":"

Recall that storage slot 0 retains the value of the next slot that the block number is written into. It starts at one and is incremented after each transaction. Hence it's the total number of transactions plus 1.

storage = {0: sum(tx_per_block) + 1}\n

For every block and transaction within the block, we write the block number and increment the next slot number in storage slot 0. As Python lists are 0 indexed, we must increment the block number by 1.

next_slot = 1\nfor blocknum in range(len(tx_per_block)):\n    for _ in range(tx_per_block[blocknum]):\n        storage[next_slot] = blocknum + 1\n        next_slot = next_slot + 1\n

Now that the expeced storage values are calculated, the post state can be defined and yielded within the BlockchainTest, synonymous to the state test example.

post = {contract_addr: Account(storage=storage)}\n\nyield BlockchainTest(\n    genesis_environment=env,\n    pre=pre,\n    blocks=blocks,\n    post=post,\n)\n

Note that because of the yield we could have multiple tests under the same name.

"},{"location":"tutorials/blockchain/#conclusion","title":"Conclusion","text":"

At this point you should be able to write blockchain tests.

"},{"location":"tutorials/state_transition/","title":"State Transition Tests","text":"

This tutorial teaches you to create a state transition execution specification test. These tests verify that a blockchain, starting from a defined pre-state, will reach a specified post-state after executing a set of specific transactions.

"},{"location":"tutorials/state_transition/#pre-requisites","title":"Pre-requisites","text":"

Before proceeding with this tutorial, it is assumed that you have prior knowledge and experience with the following:

  • Set up and run an execution specification test as outlined in the quick start guide.
  • Understand how to read a static state transition test.
  • Know the basics of Yul, which is an EVM assembly language.
  • Familiarity with Python.
"},{"location":"tutorials/state_transition/#example-tests","title":"Example Tests","text":"

The most effective method of learning how to write tests is to study a couple of straightforward examples. In this tutorial we will go over the Yul state test.

"},{"location":"tutorials/state_transition/#yul-test","title":"Yul Test","text":"

You can find the source code for the Yul test in tests/homestead/yul/test_yul_example.py. It is the spec test equivalent of this static test.

Lets examine each section.

\"\"\"\nTest Yul Source Code Examples\n\"\"\"\n

In Python, multi-line strings are denoted using \"\"\". As a convention, a file's purpose is often described in the opening string of the file.

from ethereum_test_forks import Fork\nfrom ethereum_test_tools import (\n    Account,\n    Environment,\n    StateTestFiller,\n    TestAddress,\n    Transaction,\n    Yul,\n)\n

In this snippet the required constants, types and helper functions are imported from ethereum_test_tools and ethereum_test_forks. We will go over these as we come across them.

@pytest.mark.valid_from(\"Berlin\")\n

In Python this kind of definition is called a decorator. It modifies the action of the function after it. In this case, the decorator is a custom pytest fixture defined by the execution-specs-test framework that specifies that the test is valid for the Berlin fork and all forks after it. The framework will then execute this test case for all forks in the fork range specified by the command-line arguments.

Executing the test

To execute this test for all the specified forks, we can specify pytest's -k flag that filters test cases by keyword expression:

fill -k test_yul\n
and to execute it for a specific fork range, we can provide the --from and --until command-line arguments:
fill -k test_yul --from London --until Merge\n

def test_yul(state_test: StateTestFiller, fork: Fork):\n\"\"\"\n    Test YUL compiled bytecode.\n    \"\"\"\n

This is the format of a Python function. It starts with def <function name>(<parameters>):, and then has indented code for the function. The function definition ends when there is a line that is no longer indented. As with files, by convention functions start with a string that explains what the function does.

The state_test function argument

This test defines a state test and, as such, must include the state_test in its function arguments. This is a callable object (actually a wrapper class to the StateTest); we will see how it is called later.

    env = Environment()\n

This line specifies that env is an Environment object, and that we just use the default parameters. If necessary we can modify the environment to have different block gas limits, block numbers, etc. In most tests the defaults are good enough.

For more information, see the static test documentation.

"},{"location":"tutorials/state_transition/#pre-state","title":"Pre State","text":"
    pre = {\n

Here we define the pre-state section, the one that tells us what is on the \"blockchain\" before the test. It is a dictionary, which is the Python term for an associative array.

        \"0x1000000000000000000000000000000000000000\": Account(\n

The keys of the dictionary are addresses (as strings), and the values are Account objects. You can read more about address fields in the static test documentation.

            balance=0x0BA1A9CE0BA1A9CE,\n

This field is the balance: the amount of Wei that the account has. It usually doesn't matter what its value is in the case of state test contracts.

            code=Yul(\n

Here we define the Yul code for the contract. It is defined as a multi-line string and starts and ends with curly braces ({ <yul> }).

When running the test filler fill, the solidity compiler solc will automatically translate the Yul to EVM opcode at runtime.

Note

Currently Yul and direct EVM opcode are supported in execution spec tests. LLL and Solidity may be supported in the future.

                \"\"\"\n                {\n                    function f(a, b) -> c {\n                        c := add(a, b)\n                    }\n                    sstore(0, f(1, 2))\n                    return(0, 32)\n                }\n                \"\"\"\n            ),\n        ),\n

Within this example test Yul code we have a function definition, and inside it we are using the Yul add instruction. When compiled with solc it translates the instruction directly to theADD opcode. For further Yul instructions see here. Notice that function is utilised with the Yul sstore instruction, which stores the result of add(1, 2) to the storage address 0x00.

Generally for execution spec tests the sstore instruction acts as a high-level assertion method to check pre to post-state changes. The test filler achieves this by verifying that the correct value is held within post-state storage, hence we can validate that the Yul code has run successfully.

        TestAddress: Account(balance=0x0BA1A9CE0BA1A9CE),\n    }\n

TestAddress is an address for which the test filler has the private key. This means that the test runner can issue a transaction as that contract. Of course, this address also needs a balance to be able to issue transactions.

"},{"location":"tutorials/state_transition/#transactions","title":"Transactions","text":"
    tx = Transaction(\n        ty=0x0,\n        chain_id=0x0,\n        nonce=0,\n        to=\"0x1000000000000000000000000000000000000000\",\n        gas_limit=500000,\n        gas_price=10,\n        protected=False,\n    )\n

With the pre-state specified, we can add a description for the Transaction. For more information, see the static test documentation

"},{"location":"tutorials/state_transition/#post-state","title":"Post State","text":"
    post = {\n        \"0x1000000000000000000000000000000000000000\": Account(\n            storage={\n                0x00: 0x03,\n            },\n        ),\n    }\n

This is the post-state which is equivalent to expect in static tests, but without the indexes. It is similar to the pre-state, except that we do not need to specify everything, only those accounts and fields we wish to test.

In this case, we look at the storage of the contract we called and add to it what we expect to see. In this example storage cell 0x00 should be 0x03 as in the pre-state we essentially stored the result of the Yul instruction add(1, 2).

"},{"location":"tutorials/state_transition/#state-test","title":"State Test","text":"
    state_test(env=env, pre=pre, post=post, txs=[tx])\n

This line calls the wrapper to the StateTest object that provides all the objects required (for example, the fork parameter) in order to fill the test, generate the test fixtures and write them to file (by default, ./fixtures/example/yul_example/test_yul.json).

"},{"location":"tutorials/state_transition/#conclusion","title":"Conclusion","text":"

At this point you should be able to state transition tests within a single block.

"},{"location":"tutorials/state_transition_bad_opcode/","title":"State transition bad opcode","text":""},{"location":"tutorials/state_transition_bad_opcode/#bad-opcode-test","title":"Bad Opcode Test","text":"

The source code for this test is here. We will only go over the parts that are new.

We use Python string templates, so we need to import that library.

from string import Template\n

In this test we need a couple of addresses, so we create them here. Python lets us specify <string>*<number> when we need a string repeated multiple times, which makes for more readable code than 0x00...000C0DE.

    code_addr = \"0x\" + \"0\"*(40-4) + \"C0DE\"\n    goat_addr = \"0x\" + \"0\"*(40-4) + \"60A7\"\n

We create env and tx first because they are constant. This function will yield multiple tests, but always with the same env and tx values.

    env = Environment()\n\n    tx = Transaction(\n           .\n           .\n           .\n        )\n

Here we create two post states. We will use whichever one is appropriate to the test we create.

    post_valid = {\n       code_addr: Account(\n         storage={0x00: 1},\n       ),\n    }\n\n    post_invalid = {\n       code_addr: Account(\n         storage={0x00: 0},\n       ),\n    }\n

Here we define a function (opc_valid) inside another function. Python supports this, and it has two advantages:

  • Avoid namespace pollution by restricting the function to where it is needed.
  • Functions defined inside other functions can use the parameters and local variables of those functions. In this case, we need to use fork.
    # Check if an Opcode is valid\n    def opc_valid(opc):\n\"\"\"\n        Return whether opc will be evaluated as valid by the test or not.\n        Note that some opcodes are evaluated as invalid because the way they act\n        \"\"\"\n

This is the syntax for Python comments, # <rest of the line>.

        # PUSH0 is only valid Shanghai and later\n

Opcode 0x5F (PUSH0) is only valid starting with the Shangai fork. We don't know what will be the fork names after Shanghai, so it is easiest to specify that prior to Shanghai it is invalid. We don't need to worry about forks prior to London because the decorator for this test says it is only valid from London.

        if fork in {\"london\", \"merge\"} and opc==0x5F:\n

Python has a set data structure. We use this structure when the order of the values are irrelevant, and we just want to be able to check if something is a member or not.

Note that if statements are also followed by a colon (:) and the code inside them indented. That is the general Python syntax.

            return False\n

Boolean values in Python are either True or False.

This test works by running an opcode and then does a SSTORE. Opcodes that terminate execution, such as STOP and RETURN also cause the SSTORE not to happen, so they must be treated as invalid. The same is true for JUMP.

        # Valid opcodes, but they are terminal, and so cause\n        # the SSTORE not to happen\n        if opc in {0x00, 0xF3, 0xFD, 0xFF}:\n            return False\n\n\n        # Jumps. If you jump to a random location, you skip the SSTORE\n        if opc in {0x56}:\n            return False\n

Next we return True for supported opcodes.

        # Opcodes that aren't part of a range\n        # 0x20 - SHA3\n        # 0xFA - STATICCALL\n        if opc in {0x20, 0xFA}:\n            return True\n

In Python, as in math, you can use a < b < c for a < b and b < c.

        # Arithmetic opcodes\n        if 0x01 <= opc <= 0x0b:\n            return True\n\n        .\n        .\n        .\n

The last part the function returns False. If we got here, then this is not a valid opcode.

        return False\n        # End of opc_valid\n

As this is the end of the function, the next code line is unindented (compared to the function definition code).

This is a for loop. For loops iterate over a sequnce, and the range function, in this case, gives us the range 0..255. As with functions and if statements, the for loop has a colon and includes the indented code.

    # For every possible opcode\n    for opc in range(256):\n

We have two post states. One, post_valid, has the value of 1 in storage location 0. The other, post_invalid has the value of 0 in storage location 0. But SELFDESTRUCT destroys the contract so there is no longer an account at that address. Neither is valid, so we just skip that test case.

        # We can't check SELFDESTRUCT using this technique\n        if opc in {0xFF}:\n           continue\n

We need the opcode in hexadecimal. The function hex gives us the hexadecimal number in hex. However, it also gives us a 0x prefix, which we don't want, so we use a slice to remove the first two characters.

        opc_hex = hex(opc)[2:]\n

We need opc_hex to be two characters. If the length is only one, prepend a zero.

        if len(opc_hex) == 1:\n          opc_hex = \"0\" + opc_hex\n

This is a Template string. This means we'll be able to substitute template variables (${<var name>}) with values to produce the actual code.

        yul_code = Template(\"\"\"\n        {\n

We start with a call 0x00...0060A7 (a.k.a. goat_addr) so we'll have some return data. Otherwise, RETURNDATACOPY will fail and appear like it is not an opcode.

           pop(call(gas(), 0x60A7, 0, 0, 0, 0, 0))\n\n           // fails on opcodes with >20 inputs\n           // (currently dup16, at 17 inputs, is the\n           // one that goes deepest)\n           //\n           // Follow with 32 NOPs (0x5B) to handle PUSH, which has an immediate\n           // operand\n

Opcodes can have two types of operands:

  • Immediate operands, which are part of the bytecode. For example, 6001 is PUSH1 with the value 0x01.
  • Implied operands (a.k.a. stack operands), which come from the stack.

This verbatim code provides both operand types. The code, ${opcode}${nop32} is the opcode we are testing, followed by 32 copies of 0x5B. When 0x5B is not used as an operand, it is JUMPDEST and does nothing.

           verbatim_20i_0o(hex\"${opcode}${nop32}\",\n

The opcode string is followed by the input parameters (in this case, twenty of them). These can be Yul expressions, but for the sake of simplicity here we just use constant values.

              0x00, 0x00, 0x00, 0xFF, 0xFF,\n              0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\n              0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\n              0xFF, 0xFF, 0xFF, 0xFF, 0xFF)\n

If the opcode terminates the smart contract execution (as invalid opcodes do), we don't get here. If we do get here, write to storage cell 0x00 to record that fact.

Note the syntax let <var> := <value>. This is how you specify variables in Yul.

           // We only get here is the opcode is legit (and it doesn't terminate\n           // execution like STOP and RETURN)\n           let zero := 0\n           let one := 1\n           sstore(zero, one)\n        }\n

Replace ${opcode} with the one byte hex code, and ${nop32} with 32 copies of 5b (for NOP).

        \"\"\").substitute(opcode=opc_hex, nop32=\"5B\"*32)\n        pre = {\n           TestAddress: Account(balance=0x0BA1A9CE0BA1A9CE),\n           codeAddr: Account(\n        balance=0,\n        nonce=1,\n        code=Yul(yul_code)\n           ),\n

This is the account for 0x00..0060A7. It just returns data (all zeros).

           goat_addr: Account(\n                balance=0,\n                nonce=1,\n                code=Yul(\"{ return(0, 0x100) }\"),\n           )\n        }\n

Every time the for loop gets here, it yields a separate test. Over the entire for loop, it yields 255 different tests.

    yield StateTest(\n        env=env, \n        pre=pre, \n        txs=[tx],\n        post=(post_valid if opc_valid(opc) else post_invalid),\n    )\n

The Python format for the ternary operation is a bit different from C-like languages. In C like languages the syntax is <condition> ? <yes value> : <no value>. In Python it is <yes value> if <condition> else <no value>.

"},{"location":"writing_tests/","title":"Writing Tests","text":"

The best way to get started is to use one of the existing test modules for inspiration. A good simple example is tests.berlin.eip2930_access_list.test_acl.test_access_list.

Please check that your code adheres to the repo's Coding Standards and read the other pages in this section for more background and an explanation of how to implement state transition and blockchain tests.

"},{"location":"writing_tests/adding_a_new_test/","title":"Adding a New Test","text":"

All test cases are located underneath the tests directory, which are then organized by fork. Each fork contains sub-directories containing test sub-categories.

\ud83d\udcc1 execution-test-specs/\n\u251c\u2500\u2574\ud83d\udcc1 tests/\n|   \u251c\u2500\u2500 \ud83d\udcc4 __init__.py\n\u2502   \u251c\u2500\u2500 \ud83d\udcc1 cancun/\n|   |    \u251c\u2500\u2500 \ud83d\udcc4 __init__.py\n\u2502   |    \u2514\u2500\u2500 \ud83d\udcc1 eip4844_blobs/\n|   |        \u251c\u2500\u2500 \ud83d\udcc4 __init__.py\n|   |        \u251c\u2500\u2500 \ud83d\udcc4 test_blobhash_opcode.py\n|   |        \u251c\u2500\u2500 \ud83d\udcc4 test_excess_data_gas.py\n|   |        \u2514\u2500\u2500 \ud83d\udcc4 ...\n|   \u251c\u2500\u2500 \ud83d\udcc1 shanghai\n|   |    \u251c\u2500\u2500 \ud83d\udcc1 eip3651_warm_coinbase\n|   |    |   \u251c\u2500\u2500 \ud83d\udcc4 __init__.py\n|   |    |   \u2514\u2500\u2500 \ud83d\udcc4 test_warm_coinbase.py\n|   |    \u251c\u2500\u2500 \ud83d\udcc1 eip3855_push0\n|   |    |   \u251c\u2500\u2500 \ud83d\udcc4 __init__.py\n|   |    |   \u2514\u2500\u2500 \ud83d\udcc4 test_push0.py\n|   |    \u251c\u2500\u2500 \ud83d\udcc1...\n|   |    ...\n\u2502   \u2514\u2500\u2500 \ud83d\udcc1 ...\n

Each category/sub-directory may have multiple Python test modules (*.py) which in turn may contain many test functions. The test functions themselves are always parametrized by fork (by the framework).

A new test can be added by either:

  • Adding a new test_ python function to an existing file in any of the existing category subdirectories within tests.
  • Creating a new source file in an existing category, and populating it with the new test function(s).
  • Creating an entirely new category by adding a subdirectory in tests with the appropriate source files and test functions.
"},{"location":"writing_tests/code_standards/","title":"Code Standards","text":"

The Python code in the tests subdirectory ./tests must fulfill the following checks:

Command Explanation 1 fname8 tests Spell check passes using the ./whitelist.txt dictionary file. 2 isort tests --check --diff Python imports ordered and arranged according to isort's standards. 3 black tests --check --diff Python source must be black-formatted. 4 flake8 tests Python lint checked. 5 mypy tests Objects that provide typehints pass type-checking via mypy. 6 fill All tests tests must execute correctly. 7 mkdocs build --strict Documentation generated without warnings.

While this seems like a long list, a correctly configured editor (see VS Code Setup) essentially assures:

  1. Points 2 and 3 are automatically covered.
  2. Points 1, 4 & 5 are mostly covered. Additionally, if you skip type hints, they won't be checked; we can help you add these in the PR.

These checks must pass in order for the execution-spec-tests Github Actions to pass upon pushing to remote.

Running the checks with tox

All these checks can be executed locally in a single command, tox, see Verifying Changes.

If you need help, get in touch!

"},{"location":"writing_tests/reference_specification/","title":"Referencing an EIP Spec Version","text":"

An Ethereum Improvement Proposal (ethereum/EIPs) and its SHA digest can be directly referenced within a python test module in order to check whether the test implementation could be out-dated. The test framework automatically generates tests for every module that defines a spec version. If the spec is out-of-date because the SHA of the specified file in the remote repo changes, the corresponding test_eip_spec_version() test fails.

<-snip->

The SHA value is the output from git's hash-object command, for example:

git clone git@github.com:ethereum/EIPs\ngit hash-object EIPS/EIPS/eip-3651.md\n# output: d94c694c6f12291bb6626669c3e8587eef3adff1\n
and can be retrieved from the remote repo via the Github API on the command-line as following:
sudo apt install jq\ncurl -s -H \"Accept: application/vnd.github.v3+json\" \\\nhttps://api.github.com/repos/ethereum/EIPs/contents/EIPS/eip-3651.md |\\\njq -r '.sha'\n# output: d94c694c6f12291bb6626669c3e8587eef3adff1\n

"},{"location":"writing_tests/reference_specification/#how-to-add-a-spec-version-check","title":"How to Add a Spec Version Check","text":"

This check accomplished by adding the following two global variables anywhere in the Python source file:

Variable Name Explanation REFERENCE_SPEC_GIT_PATH The relative path of the EIP markdown file in the ethereum/EIPs repository, e.g. \"EIPS/eip-1234.md\" REFERENCE_SPEC_VERSION The SHA hash of the latest version of the file retrieved from the Github API:https://api.github.com/repos/ethereum/EIPs/contents/EIPS/eip-<EIP Number>.md"},{"location":"writing_tests/reference_specification/#example","title":"Example","text":"

Here is an example from ./tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase.py:

REFERENCE_SPEC_GIT_PATH = \"EIPS/eip-3651.md\"\nREFERENCE_SPEC_VERSION = \"d94c694c6f12291bb6626669c3e8587eef3adff1\"\n

The SHA digest was retrieved from here.

"},{"location":"writing_tests/types_of_tests/","title":"Types of tests","text":"

There are currently two types of tests that can be produced by a test spec:

  1. State Tests
  2. Blockchain Tests
"},{"location":"writing_tests/types_of_tests/#state-tests","title":"State Tests","text":"

State tests span a single block and, ideally, a single transaction. For example:

  • Test a single opcode behavior.
  • Verify opcode gas costs.
  • Test interactions between multiple smart contracts.
  • Test creation of smart contracts.
"},{"location":"writing_tests/types_of_tests/#blockchain-tests","title":"Blockchain Tests","text":"

Blockchain tests span multiple blocks which may or may not contain transactions and mainly focus on the block to block effects to the Ethereum state. For example:

  • Verify system-level operations such as coinbase balance updates or withdrawals.
  • Verify fork transitions.
  • Verify blocks with invalid transactions/properties are rejected.
"},{"location":"writing_tests/types_of_tests/#fork-transition-tests","title":"Fork Transition Tests","text":"

There is a special type of blockchain test that is used to test a fork transition. It's not executed for all possible forks, rather it targets exactly the blocks at the point of transition from one evm implementation to the next. This type of test must be marked with the valid_at_transition_to marker, for example:

@pytest.mark.valid_at_transition_to(\"Cancun\")\ndef test_blob_type_tx_pre_fork(\n    blockchain_test: BlockchainTestFiller,\n    pre: Dict,\n    env: Environment,\n    blocks: List[Block],\n):\n\"\"\"\n    Reject blocks with blobs before blobs fork\n    \"\"\"\n
"},{"location":"writing_tests/verifying_changes/","title":"Verifying Changes","text":"

The tox tool can be used to lint, type check, test and verify that documentation is correctly generated. The tox tool can be executed locally to check that local changes won't cause Github Actions Checks to fail.

There are two tox environments available, one for the test cases (tests) and one for the framework and libraries (py3).

Tox Virtual Environment

The checks performed by tox are sandboxed in their own virtual environments (which are created automatically in the .tox/ subdirectory). These can be used to debug errors encountered during tox execution.

Whilst we create a virtual environment in the code snippets below, they are only to install the tox tool itself.

"},{"location":"writing_tests/verifying_changes/#test-case-verification-tests","title":"Test Case Verification: tests","text":"

Prerequisite:

python -m venv ./venv/\nsource ./venv/bin/activate\npip install tox\n
Verify:
tox -e tests\n

"},{"location":"writing_tests/verifying_changes/#framework-verification-py3","title":"Framework Verification: py3","text":"

Prerequisite:

python -m venv ./venv/\nsource ./venv/bin/activate\npip install tox\n
Verify:
tox -e py3\n

"},{"location":"writing_tests/writing_a_new_test/","title":"Writing a New Test","text":""},{"location":"writing_tests/writing_a_new_test/#test-functions","title":"Test Functions","text":"

Every test case is defined as a python function that defines a single StateTest or BlockchainTest by using one of the state_test or blockchain_test objects made available by the framework. Test cases, respectively test modules, must fulfil the following requirements:

Requirement When Be decorated with validity markers If the test case is not valid for all forks Use one of state_test or blockchain_test in its function arguments Always Call the state_test or blockchain_test in its test body Always Add a reference version of the EIP spec under test Test path contains eip"},{"location":"writing_tests/writing_a_new_test/#specifying-which-forks-tests-are-valid-for","title":"Specifying which Forks Tests are Valid For","text":"

Test cases can (and it most cases should) be decorated with one or more \"validity markers\" that define which the forks the test is valid for. This is achieved by applying:

  • pytest.mark.valid_from(FORK) and/or pytest.mark.valid_until(FORK)

or

  • pytest.mark.valid_at_transition_to(FORK)

markers on either the test function, test class or test module level:

FunctionClassModule
import pytest\n\n@pytest.mark.valid_from(\"Berlin\")\n@pytest.mark.valid_until(\"London\")\ndef test_access_list(state_test: StateTestFiller, fork: Fork):\n
import pytest\n\n\n@pytest.mark.valid_from(\"Shanghai\")\nclass TestMultipleWithdrawalsSameAddress:\n
import pytest\n\npytestmark = pytest.mark.valid_from(\"Shanghai\")\n

The ethereum_test_forks package defines the available forks and provides the following helpers that return all forks within the specified range:

  • forks_from
  • forks_from_until
"},{"location":"writing_tests/writing_a_new_test/#the-state_test-and-blockchain_test-test-function-arguments","title":"The state_test and blockchain_test Test Function Arguments","text":"

The test function's signature must contain exactly one of either a state_test or blockchain_test argument.

For example, for state tests:

def test_access_list(state_test: StateTestFiller):\n

and for blockchain tests:

def test_contract_creating_tx(\n    blockchain_test: BlockchainTestFiller, fork: Fork, initcode: Initcode\n):\n

The state_test and blockchain_test objects are actually wrapper classes to the StateTest, respectively BlockchainTest objects, that once called actually instantiate a new instance of these objects and fill the test case using the evm tool according to the pre and post states and the transactions defined within the test.

"},{"location":"writing_tests/writing_a_new_test/#statetest-object","title":"StateTest Object","text":"

The StateTest object represents a single test vector, and contains the following attributes:

  • env: Environment object which describes the global state of the blockchain before the test starts.
  • pre: Pre-State containing the information of all Ethereum accounts that exist before any transaction is executed.
  • post: Post-State containing the information of all Ethereum accounts that are created or modified after all transactions are executed.
  • txs: All transactions to be executed during test execution.
"},{"location":"writing_tests/writing_a_new_test/#blockchaintest-object","title":"BlockchainTest Object","text":"

The BlockchainTest object represents a single test vector that evaluates the Ethereum VM by attempting to append multiple blocks to the chain:

  • pre: Pre-State containing the information of all Ethereum accounts that exist before any block is executed.
  • post: Post-State containing the information of all Ethereum accounts that are created or modified after all blocks are executed.
  • blocks: All blocks to be appended to the blockchain during the test.
"},{"location":"writing_tests/writing_a_new_test/#prepost-state-of-the-test","title":"Pre/Post State of the Test","text":"

The pre and post states are elemental to setup and then verify the outcome of the state test.

Both pre and post are mappings of account addresses to account structures (see more info).

A single test vector can contain as many accounts in the pre and post states as required, and they can be also filled dynamically.

storage of an account is a key/value dictionary, and its values are integers within range of [0, 2**256 - 1].

txs are the steps which transform the pre-state into the post-state and must perform specific actions within the accounts (smart contracts) that result in verifiable changes to the balance, nonce, and/or storage in each of them.

post is compared against the outcome of the client after the execution of each transaction, and any differences are considered a failure

When designing a test, all the changes must be ideally saved into the contract's storage to be able to verify them in the post-state.

"},{"location":"writing_tests/writing_a_new_test/#test-transactions","title":"Test Transactions","text":"

Transactions can be crafted by sending them with specific data or to a specific account, which contains the code to be executed

Transactions can also create more accounts, by setting the to field to an empty string.

Transactions can be designed to fail, and a verification must be made that the transaction fails with the specific error that matches what is expected by the test.

"},{"location":"writing_tests/writing_a_new_test/#writing-code-for-the-accounts-in-the-test","title":"Writing code for the accounts in the test","text":"

Account bytecode can be embedded in the test accounts by adding it to the code field of the account object, or the data field of the tx object if the bytecode is meant to be treated as init code or call data.

The code can be in either of the following formats:

  • bytes object, representing the raw opcodes in binary format.
  • str, representing an hexadecimal format of the opcodes.
  • Code compilable object.

Currently supported built-in compilable objects are:

  • Yul object containing Yul source code.

Code objects can be concatenated together by using the + operator.

"},{"location":"writing_tests/writing_a_new_test/#verifying-the-accounts-post-states","title":"Verifying the Accounts' Post States","text":"

The state of the accounts after all blocks/transactions have been executed is the way of verifying that the execution client actually behaves like the test expects.

During their filling process, all tests automatically verify that the accounts specified in their post property actually match what was returned by the transition tool.

Within the post dictionary object, an account address can be:

  • None: The account will not be checked for absence or existence in the result returned by the transition tool.
  • Account object: The test expects that this account exists and also has properties equal to the properties specified by the Account object.
  • Account.NONEXISTENT: The test expects that this account does not exist in the result returned by the transition tool, and if the account exists, it results in error. E.g. when the transaction creating a contract is expected to fail and the test wants to verify that the address where the contract was supposed to be created is indeed empty.
"},{"location":"writing_tests/writing_a_new_test/#the-account-object","title":"The Account object","text":"

The Account object is used to specify the properties of an account to be verified in the post state.

The python representation can be found in src/ethereum_test_tools/common/types.py.

It can verify the following properties of an account:

  • nonce: the scalar value equal to a) the number of transactions sent by an Externally Owned Account, b) the amount of contracts created by a contract.

  • balance: the amount of Wei (10-18 Eth) the account has.

  • code: Bytecode contained by the account. To verify that an account contains no code, this property needs to be set to \"0x\" or \"\".

It is not recommended to verify Yul compiled code in the output account, because the bytecode can change from version to version.

  • storage: Storage within the account represented as a dict object. All storage keys that are expected to be set must be specified, and if a key is skipped, it is implied that its expected value is zero. Setting this property to {} (empty dict), means that all the keys in the account must be unset (equal to zero).

All account's properties are optional, and they can be skipped or set to None, which means that no check will be performed on that specific account property.

"},{"location":"writing_tests/writing_a_new_test/#verifying-correctness-of-the-new-test","title":"Verifying correctness of the new test","text":"

A well written test performs a single verification output at a time.

A verification output can be a single storage slot, the balance of an account, or a newly created contract.

It is not recommended to use balance changes to verify test correctness, as it can be easily affected by gas cost changes in future EIPs.

The best way to verify a transaction/block execution outcome is to check its storage.

A test can be written as a negative verification. E.g. a contract is not created, or a transaction fails to execute or runs out of gas.

These verifications must be carefully crafted because it is possible to end up having a false positive result, which means that the test passed but the intended verification was never made.

To avoid these scenarios, it is important to have a separate verification to check that test is effective. E.g. when a transaction is supposed to fail, it is necessary to check that the failure error is actually the one expected by the test.

"},{"location":"writing_tests/writing_a_new_test/#failing-or-invalid-transactions","title":"Failing or invalid transactions","text":"

Transactions included in a StateTest are expected to be intrinsically valid, i.e. the account sending the transaction must have enough funds to cover the gas costs, the max fee of the transaction must be equal or higher than the base fee of the block, etc.

An intrinsically valid transaction can still revert during its execution.

Blocks in a BlockchainTest can contain intrinsically invalid transactions but in this case the block is expected to be completely rejected, along with all transactions in it, including other valid transactions.

"}]} \ No newline at end of file diff --git a/v1.0.1b1-refactor-4844-specs/sitemap.xml.gz b/v1.0.1b1-refactor-4844-specs/sitemap.xml.gz index d54bdf7d83e9f8f39b47916c306d79ef781e72e7..dff41dbcd6d102d7fcd92ca5be3bfdc250bb9329 100644 GIT binary patch delta 15 WcmZ3&zJ#4kzMF&NWa&n>dCUMLoCK`^ delta 15 WcmZ3&zJ#4kzMF&NckD*CdCUMMPz1*S diff --git a/v1.0.1b1-refactor-4844-specs/tests/berlin/eip2930_access_list/index.html b/v1.0.1b1-refactor-4844-specs/tests/berlin/eip2930_access_list/index.html index fa54821407..7fe0405088 100644 --- a/v1.0.1b1-refactor-4844-specs/tests/berlin/eip2930_access_list/index.html +++ b/v1.0.1b1-refactor-4844-specs/tests/berlin/eip2930_access_list/index.html @@ -3217,7 +3217,7 @@

EIP-2930 Access List

-

Documentation for tests/berlin/eip2930_access_list.

+

Documentation for tests/berlin/eip2930_access_list.

Generate fixtures for these test cases with:

fill -v tests/berlin/eip2930_access_list
diff --git a/v1.0.1b1-refactor-4844-specs/tests/berlin/eip2930_access_list/test_acl/index.html b/v1.0.1b1-refactor-4844-specs/tests/berlin/eip2930_access_list/test_acl/index.html
index ef9ce69cc3..09d0fa4d99 100644
--- a/v1.0.1b1-refactor-4844-specs/tests/berlin/eip2930_access_list/test_acl/index.html
+++ b/v1.0.1b1-refactor-4844-specs/tests/berlin/eip2930_access_list/test_acl/index.html
@@ -3226,7 +3226,7 @@
 
 
 

Test ACL

-

Documentation for tests/berlin/eip2930_access_list/test_acl.py.

+

Documentation for tests/berlin/eip2930_access_list/test_acl.py.

Generate fixtures for these test cases with:

fill -v tests/berlin/eip2930_access_list/test_acl.py
diff --git a/v1.0.1b1-refactor-4844-specs/tests/berlin/eip2930_access_list/test_acl/index/test_cases/index.html b/v1.0.1b1-refactor-4844-specs/tests/berlin/eip2930_access_list/test_acl/index/test_cases/index.html
index 529dbb5b0e..453fb3fd76 100644
--- a/v1.0.1b1-refactor-4844-specs/tests/berlin/eip2930_access_list/test_acl/index/test_cases/index.html
+++ b/v1.0.1b1-refactor-4844-specs/tests/berlin/eip2930_access_list/test_acl/index/test_cases/index.html
@@ -3216,7 +3216,7 @@
 

Test ACL - Test Cases

Test cases generated from tests/berlin/eip2930_access_list/test_acl.py

-

Parametrized test cases generated from the test module tests/berlin/eip2930_access_list/test_acl.py:

+

Parametrized test cases generated from the test module tests/berlin/eip2930_access_list/test_acl.py:

test_access_list[fork=Berlin]
 test_access_list[fork=London]
 
diff --git a/v1.0.1b1-refactor-4844-specs/tests/berlin/index.html b/v1.0.1b1-refactor-4844-specs/tests/berlin/index.html index 97602d52fe..ff30e32285 100644 --- a/v1.0.1b1-refactor-4844-specs/tests/berlin/index.html +++ b/v1.0.1b1-refactor-4844-specs/tests/berlin/index.html @@ -3215,7 +3215,7 @@

Berlin

-

Documentation for tests/berlin.

+

Documentation for tests/berlin.

Generate fixtures for these test cases with:

fill -v tests/berlin
diff --git a/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/index.html b/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/index.html
index 16183eb256..d489eb97de 100644
--- a/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/index.html
+++ b/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/index.html
@@ -3217,7 +3217,7 @@
 
 
 

EIP-4844 Blobs

-

Documentation for tests/cancun/eip4844_blobs.

+

Documentation for tests/cancun/eip4844_blobs.

Generate fixtures for these test cases for Cancun with:

Cancun only: diff --git a/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/spec/index.html b/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/spec/index.html index 192ade8ba1..496f5c5091 100644 --- a/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/spec/index.html +++ b/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/spec/index.html @@ -3286,7 +3286,7 @@

Spec

-

Documentation for tests/cancun/eip4844_blobs/spec.py.

+

Documentation for tests/cancun/eip4844_blobs/spec.py.

@@ -3295,7 +3295,7 @@

Spec&par
-

Defines EIP-4844 spec constants and functions.

+

Defines EIP-4844 specification constants and functions.

@@ -3323,8 +3323,6 @@

-

- Bases: IntEnum

Parameters from the EIP-4844 specifications as defined at @@ -3335,7 +3333,8 @@

Source code in tests/cancun/eip4844_blobs/spec.py -
 34
+          
 33
+ 34
  35
  36
  37
@@ -3425,9 +3424,8 @@ 

121 122 123 -124 -125

@dataclass(frozen=True)
-class Spec(IntEnum):
+124
@dataclass(frozen=True)
+class Spec:
     """
     Parameters from the EIP-4844 specifications as defined at
     https://eips.ethereum.org/EIPS/eip-4844#parameters
@@ -3490,8 +3488,8 @@ 

@classmethod def calc_excess_data_gas(cls, parent: BlockHeaderDataGasFields) -> int: """ - Calculate the excess data gas for a block given the parent excess data gas - and the number of blobs in the block. + Calculate the excess data gas for a block given the excess data gas + and data gas used from the parent block header. """ if parent.excess_data_gas + parent.data_gas_used < cls.TARGET_DATA_GAS_PER_BLOCK: return 0 @@ -3506,7 +3504,7 @@

# """ # if tx.blob_versioned_hashes is None: # return 0 - # return cls.DATA_GAS_PER_BLOB.value * len(tx.blob_versioned_hashes) + # return cls.DATA_GAS_PER_BLOB * len(tx.blob_versioned_hashes) @classmethod def get_data_gasprice(cls, *, excess_data_gas: int) -> int: @@ -3514,9 +3512,9 @@

Calculate the data gas price from the excess. """ return cls.fake_exponential( - cls.MIN_DATA_GASPRICE.value, + cls.MIN_DATA_GASPRICE, excess_data_gas, - cls.DATA_GASPRICE_UPDATE_FRACTION.value, + cls.DATA_GASPRICE_UPDATE_FRACTION, )

@@ -3556,8 +3554,6 @@

-

- Bases: Enum

Define parameters and helper functions that are tightly coupled to the 4844 @@ -3566,7 +3562,8 @@

Source code in tests/cancun/eip4844_blobs/spec.py -
128
+          
127
+128
 129
 130
 131
@@ -3623,9 +3620,8 @@ 

182 183 184 -185 -186

@dataclass(frozen=True)
-class SpecHelpers(Enum):
+185
@dataclass(frozen=True)
+class SpecHelpers:
     """
     Define parameters and helper functions that are tightly coupled to the 4844
     spec but not strictly part of it.
@@ -3638,14 +3634,14 @@ 

""" Returns the maximum number of blobs per block. """ - return Spec.MAX_DATA_GAS_PER_BLOCK.value // Spec.DATA_GAS_PER_BLOB.value + return Spec.MAX_DATA_GAS_PER_BLOCK // Spec.DATA_GAS_PER_BLOB @classmethod def target_blobs_per_block(cls) -> int: """ Returns the target number of blobs per block. """ - return Spec.TARGET_DATA_GAS_PER_BLOCK.value // Spec.DATA_GAS_PER_BLOB.value + return Spec.TARGET_DATA_GAS_PER_BLOCK // Spec.DATA_GAS_PER_BLOB @classmethod def calc_excess_data_gas_from_blob_count( @@ -3655,7 +3651,7 @@

Calculate the excess data gas for a block given the parent excess data gas and the number of blobs in the block. """ - parent_consumed_data_gas = parent_blob_count * Spec.DATA_GAS_PER_BLOB.value + parent_consumed_data_gas = parent_blob_count * Spec.DATA_GAS_PER_BLOB return Spec.calc_excess_data_gas( BlockHeaderDataGasFields(parent_excess_data_gas, parent_consumed_data_gas) ) @@ -3668,7 +3664,7 @@

current_excess_data_gas = 0 current_data_gas_price = 1 while current_data_gas_price < data_gas_price: - current_excess_data_gas += Spec.DATA_GAS_PER_BLOB.value + current_excess_data_gas += Spec.DATA_GAS_PER_BLOB current_data_gas_price = Spec.get_data_gasprice( excess_data_gas=current_excess_data_gas ) @@ -3681,7 +3677,7 @@

""" return ( cls.get_min_excess_data_gas_for_data_gas_price(data_gas_price) - // Spec.DATA_GAS_PER_BLOB.value + // Spec.DATA_GAS_PER_BLOB )

diff --git a/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_blob_txs/index.html b/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_blob_txs/index.html index 7c56511b95..c53b2df3e8 100644 --- a/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_blob_txs/index.html +++ b/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_blob_txs/index.html @@ -3331,7 +3331,7 @@

Test Blob Txs

-

Documentation for tests/cancun/eip4844_blobs/test_blob_txs.py.

+

Documentation for tests/cancun/eip4844_blobs/test_blob_txs.py.

Generate fixtures for these test cases for Cancun with:

Cancun only: @@ -3391,8 +3391,6 @@

-

- Bases: IntEnum

Parameters from the EIP-4844 specifications as defined at @@ -3403,7 +3401,8 @@

Source code in tests/cancun/eip4844_blobs/spec.py -
 34
+          
 33
+ 34
  35
  36
  37
@@ -3493,9 +3492,8 @@ 

121 122 123 -124 -125

@dataclass(frozen=True)
-class Spec(IntEnum):
+124
@dataclass(frozen=True)
+class Spec:
     """
     Parameters from the EIP-4844 specifications as defined at
     https://eips.ethereum.org/EIPS/eip-4844#parameters
@@ -3558,8 +3556,8 @@ 

@classmethod def calc_excess_data_gas(cls, parent: BlockHeaderDataGasFields) -> int: """ - Calculate the excess data gas for a block given the parent excess data gas - and the number of blobs in the block. + Calculate the excess data gas for a block given the excess data gas + and data gas used from the parent block header. """ if parent.excess_data_gas + parent.data_gas_used < cls.TARGET_DATA_GAS_PER_BLOCK: return 0 @@ -3574,7 +3572,7 @@

# """ # if tx.blob_versioned_hashes is None: # return 0 - # return cls.DATA_GAS_PER_BLOB.value * len(tx.blob_versioned_hashes) + # return cls.DATA_GAS_PER_BLOB * len(tx.blob_versioned_hashes) @classmethod def get_data_gasprice(cls, *, excess_data_gas: int) -> int: @@ -3582,9 +3580,9 @@

Calculate the data gas price from the excess. """ return cls.fake_exponential( - cls.MIN_DATA_GASPRICE.value, + cls.MIN_DATA_GASPRICE, excess_data_gas, - cls.DATA_GASPRICE_UPDATE_FRACTION.value, + cls.DATA_GASPRICE_UPDATE_FRACTION, )

@@ -3624,8 +3622,6 @@

-

- Bases: Enum

Define parameters and helper functions that are tightly coupled to the 4844 @@ -3634,7 +3630,8 @@

Source code in tests/cancun/eip4844_blobs/spec.py -
128
+          
127
+128
 129
 130
 131
@@ -3691,9 +3688,8 @@ 

182 183 184 -185 -186

@dataclass(frozen=True)
-class SpecHelpers(Enum):
+185
@dataclass(frozen=True)
+class SpecHelpers:
     """
     Define parameters and helper functions that are tightly coupled to the 4844
     spec but not strictly part of it.
@@ -3706,14 +3702,14 @@ 

""" Returns the maximum number of blobs per block. """ - return Spec.MAX_DATA_GAS_PER_BLOCK.value // Spec.DATA_GAS_PER_BLOB.value + return Spec.MAX_DATA_GAS_PER_BLOCK // Spec.DATA_GAS_PER_BLOB @classmethod def target_blobs_per_block(cls) -> int: """ Returns the target number of blobs per block. """ - return Spec.TARGET_DATA_GAS_PER_BLOCK.value // Spec.DATA_GAS_PER_BLOB.value + return Spec.TARGET_DATA_GAS_PER_BLOCK // Spec.DATA_GAS_PER_BLOB @classmethod def calc_excess_data_gas_from_blob_count( @@ -3723,7 +3719,7 @@

Calculate the excess data gas for a block given the parent excess data gas and the number of blobs in the block. """ - parent_consumed_data_gas = parent_blob_count * Spec.DATA_GAS_PER_BLOB.value + parent_consumed_data_gas = parent_blob_count * Spec.DATA_GAS_PER_BLOB return Spec.calc_excess_data_gas( BlockHeaderDataGasFields(parent_excess_data_gas, parent_consumed_data_gas) ) @@ -3736,7 +3732,7 @@

current_excess_data_gas = 0 current_data_gas_price = 1 while current_data_gas_price < data_gas_price: - current_excess_data_gas += Spec.DATA_GAS_PER_BLOB.value + current_excess_data_gas += Spec.DATA_GAS_PER_BLOB current_data_gas_price = Spec.get_data_gasprice( excess_data_gas=current_excess_data_gas ) @@ -3749,7 +3745,7 @@

""" return ( cls.get_min_excess_data_gas_for_data_gas_price(data_gas_price) - // Spec.DATA_GAS_PER_BLOB.value + // Spec.DATA_GAS_PER_BLOB )

diff --git a/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_blob_txs/index/test_cases/index.html b/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_blob_txs/index/test_cases/index.html index 91cc2ac8d1..171d04d98a 100644 --- a/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_blob_txs/index/test_cases/index.html +++ b/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_blob_txs/index/test_cases/index.html @@ -3216,7 +3216,7 @@

Test Blob Txs - Test Cases

Test cases generated from tests/cancun/eip4844_blobs/test_blob_txs.py

-

Parametrized test cases generated from the test module tests/cancun/eip4844_blobs/test_blob_txs.py:

+

Parametrized test cases generated from the test module tests/cancun/eip4844_blobs/test_blob_txs.py:

test_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(1, 1, 1, 1, 1, 1)]
 test_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(1, 1, 1, 1, 1)]
 test_valid_blob_tx_combinations[fork=Cancun-blobs_per_tx=(1, 1, 1, 1, 2)]
diff --git a/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_blob_txs_full/index.html b/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_blob_txs_full/index.html
index e30b84f972..a1fe545c71 100644
--- a/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_blob_txs_full/index.html
+++ b/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_blob_txs_full/index.html
@@ -3240,7 +3240,7 @@
 
 
 

Test Blob Txs Full

-

Documentation for tests/cancun/eip4844_blobs/test_blob_txs_full.py.

+

Documentation for tests/cancun/eip4844_blobs/test_blob_txs_full.py.

Generate fixtures for these test cases for Cancun with:

Cancun only: @@ -3289,8 +3289,6 @@

-

- Bases: IntEnum

Parameters from the EIP-4844 specifications as defined at @@ -3301,7 +3299,8 @@

Source code in tests/cancun/eip4844_blobs/spec.py -
 34
+          
 33
+ 34
  35
  36
  37
@@ -3391,9 +3390,8 @@ 

121 122 123 -124 -125

@dataclass(frozen=True)
-class Spec(IntEnum):
+124
@dataclass(frozen=True)
+class Spec:
     """
     Parameters from the EIP-4844 specifications as defined at
     https://eips.ethereum.org/EIPS/eip-4844#parameters
@@ -3456,8 +3454,8 @@ 

@classmethod def calc_excess_data_gas(cls, parent: BlockHeaderDataGasFields) -> int: """ - Calculate the excess data gas for a block given the parent excess data gas - and the number of blobs in the block. + Calculate the excess data gas for a block given the excess data gas + and data gas used from the parent block header. """ if parent.excess_data_gas + parent.data_gas_used < cls.TARGET_DATA_GAS_PER_BLOCK: return 0 @@ -3472,7 +3470,7 @@

# """ # if tx.blob_versioned_hashes is None: # return 0 - # return cls.DATA_GAS_PER_BLOB.value * len(tx.blob_versioned_hashes) + # return cls.DATA_GAS_PER_BLOB * len(tx.blob_versioned_hashes) @classmethod def get_data_gasprice(cls, *, excess_data_gas: int) -> int: @@ -3480,9 +3478,9 @@

Calculate the data gas price from the excess. """ return cls.fake_exponential( - cls.MIN_DATA_GASPRICE.value, + cls.MIN_DATA_GASPRICE, excess_data_gas, - cls.DATA_GASPRICE_UPDATE_FRACTION.value, + cls.DATA_GASPRICE_UPDATE_FRACTION, )

@@ -3522,8 +3520,6 @@

-

- Bases: Enum

Define parameters and helper functions that are tightly coupled to the 4844 @@ -3532,7 +3528,8 @@

Source code in tests/cancun/eip4844_blobs/spec.py -
128
+          
127
+128
 129
 130
 131
@@ -3589,9 +3586,8 @@ 

182 183 184 -185 -186

@dataclass(frozen=True)
-class SpecHelpers(Enum):
+185
@dataclass(frozen=True)
+class SpecHelpers:
     """
     Define parameters and helper functions that are tightly coupled to the 4844
     spec but not strictly part of it.
@@ -3604,14 +3600,14 @@ 

""" Returns the maximum number of blobs per block. """ - return Spec.MAX_DATA_GAS_PER_BLOCK.value // Spec.DATA_GAS_PER_BLOB.value + return Spec.MAX_DATA_GAS_PER_BLOCK // Spec.DATA_GAS_PER_BLOB @classmethod def target_blobs_per_block(cls) -> int: """ Returns the target number of blobs per block. """ - return Spec.TARGET_DATA_GAS_PER_BLOCK.value // Spec.DATA_GAS_PER_BLOB.value + return Spec.TARGET_DATA_GAS_PER_BLOCK // Spec.DATA_GAS_PER_BLOB @classmethod def calc_excess_data_gas_from_blob_count( @@ -3621,7 +3617,7 @@

Calculate the excess data gas for a block given the parent excess data gas and the number of blobs in the block. """ - parent_consumed_data_gas = parent_blob_count * Spec.DATA_GAS_PER_BLOB.value + parent_consumed_data_gas = parent_blob_count * Spec.DATA_GAS_PER_BLOB return Spec.calc_excess_data_gas( BlockHeaderDataGasFields(parent_excess_data_gas, parent_consumed_data_gas) ) @@ -3634,7 +3630,7 @@

current_excess_data_gas = 0 current_data_gas_price = 1 while current_data_gas_price < data_gas_price: - current_excess_data_gas += Spec.DATA_GAS_PER_BLOB.value + current_excess_data_gas += Spec.DATA_GAS_PER_BLOB current_data_gas_price = Spec.get_data_gasprice( excess_data_gas=current_excess_data_gas ) @@ -3647,7 +3643,7 @@

""" return ( cls.get_min_excess_data_gas_for_data_gas_price(data_gas_price) - // Spec.DATA_GAS_PER_BLOB.value + // Spec.DATA_GAS_PER_BLOB )

@@ -3758,10 +3754,7 @@

338 339 340 -341 -342 -343 -344

@pytest.mark.parametrize(
+341
@pytest.mark.parametrize(
     "txs_blobs,txs_wrapped_blobs",
     [
         (
@@ -3769,8 +3762,7 @@ 

[ # Blobs per transaction Blob( blob=bytes( - Spec.FIELD_ELEMENTS_PER_BLOB.value - * SpecHelpers.BYTES_PER_FIELD_ELEMENT.value + Spec.FIELD_ELEMENTS_PER_BLOB * SpecHelpers.BYTES_PER_FIELD_ELEMENT ), kzg_commitment=INF_POINT, kzg_proof=INF_POINT, @@ -3784,8 +3776,7 @@

[ # Blobs per transaction Blob( blob=bytes( - Spec.FIELD_ELEMENTS_PER_BLOB.value - * SpecHelpers.BYTES_PER_FIELD_ELEMENT.value + Spec.FIELD_ELEMENTS_PER_BLOB * SpecHelpers.BYTES_PER_FIELD_ELEMENT ), kzg_commitment=INF_POINT, kzg_proof=INF_POINT, @@ -3800,8 +3791,7 @@

[ # Blobs per transaction Blob( blob=bytes( - Spec.FIELD_ELEMENTS_PER_BLOB.value - * SpecHelpers.BYTES_PER_FIELD_ELEMENT.value + Spec.FIELD_ELEMENTS_PER_BLOB * SpecHelpers.BYTES_PER_FIELD_ELEMENT ), kzg_commitment=INF_POINT, kzg_proof=INF_POINT, diff --git a/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_blob_txs_full/index/test_cases/index.html b/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_blob_txs_full/index/test_cases/index.html index 13fb38fc37..929ecb6473 100644 --- a/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_blob_txs_full/index/test_cases/index.html +++ b/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_blob_txs_full/index/test_cases/index.html @@ -3216,7 +3216,7 @@

Test Blob Txs Full - Test Cases

Test cases generated from tests/cancun/eip4844_blobs/test_blob_txs_full.py

-

Parametrized test cases generated from the test module tests/cancun/eip4844_blobs/test_blob_txs_full.py:

+

Parametrized test cases generated from the test module tests/cancun/eip4844_blobs/test_blob_txs_full.py:

test_reject_valid_full_blob_in_block_rlp[fork=Cancun-one_full_blob_one_tx]
 test_reject_valid_full_blob_in_block_rlp[fork=Cancun-one_full_blob_max_txs]
 test_reject_valid_full_blob_in_block_rlp[fork=Cancun-one_full_blob_at_the_end_max_txs]
diff --git a/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_blobhash_opcode/index.html b/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_blobhash_opcode/index.html
index 4768983cbd..ffb4c294a6 100644
--- a/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_blobhash_opcode/index.html
+++ b/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_blobhash_opcode/index.html
@@ -3261,7 +3261,7 @@
 
 
 

Test Blobhash Opcode

-

Documentation for tests/cancun/eip4844_blobs/test_blobhash_opcode.py.

+

Documentation for tests/cancun/eip4844_blobs/test_blobhash_opcode.py.

Generate fixtures for these test cases for Cancun with:

Cancun only: @@ -3323,8 +3323,6 @@

-

- Bases: IntEnum

Parameters from the EIP-4844 specifications as defined at @@ -3335,7 +3333,8 @@

Source code in tests/cancun/eip4844_blobs/spec.py -
 34
+          
 33
+ 34
  35
  36
  37
@@ -3425,9 +3424,8 @@ 

121 122 123 -124 -125

@dataclass(frozen=True)
-class Spec(IntEnum):
+124
@dataclass(frozen=True)
+class Spec:
     """
     Parameters from the EIP-4844 specifications as defined at
     https://eips.ethereum.org/EIPS/eip-4844#parameters
@@ -3490,8 +3488,8 @@ 

@classmethod def calc_excess_data_gas(cls, parent: BlockHeaderDataGasFields) -> int: """ - Calculate the excess data gas for a block given the parent excess data gas - and the number of blobs in the block. + Calculate the excess data gas for a block given the excess data gas + and data gas used from the parent block header. """ if parent.excess_data_gas + parent.data_gas_used < cls.TARGET_DATA_GAS_PER_BLOCK: return 0 @@ -3506,7 +3504,7 @@

# """ # if tx.blob_versioned_hashes is None: # return 0 - # return cls.DATA_GAS_PER_BLOB.value * len(tx.blob_versioned_hashes) + # return cls.DATA_GAS_PER_BLOB * len(tx.blob_versioned_hashes) @classmethod def get_data_gasprice(cls, *, excess_data_gas: int) -> int: @@ -3514,9 +3512,9 @@

Calculate the data gas price from the excess. """ return cls.fake_exponential( - cls.MIN_DATA_GASPRICE.value, + cls.MIN_DATA_GASPRICE, excess_data_gas, - cls.DATA_GASPRICE_UPDATE_FRACTION.value, + cls.DATA_GASPRICE_UPDATE_FRACTION, )

@@ -3662,7 +3660,7 @@

] ) ) - post[address] = Account(storage={0: Spec.HASH_GAS_COST.value}) + post[address] = Account(storage={0: Spec.HASH_GAS_COST}) blockchain_test( pre=pre, blocks=blocks, @@ -3695,8 +3693,6 @@

-

- Bases: Enum

Define parameters and helper functions that are tightly coupled to the 4844 @@ -3705,7 +3701,8 @@

Source code in tests/cancun/eip4844_blobs/spec.py -
128
+          
127
+128
 129
 130
 131
@@ -3762,9 +3759,8 @@ 

182 183 184 -185 -186

@dataclass(frozen=True)
-class SpecHelpers(Enum):
+185
@dataclass(frozen=True)
+class SpecHelpers:
     """
     Define parameters and helper functions that are tightly coupled to the 4844
     spec but not strictly part of it.
@@ -3777,14 +3773,14 @@ 

""" Returns the maximum number of blobs per block. """ - return Spec.MAX_DATA_GAS_PER_BLOCK.value // Spec.DATA_GAS_PER_BLOB.value + return Spec.MAX_DATA_GAS_PER_BLOCK // Spec.DATA_GAS_PER_BLOB @classmethod def target_blobs_per_block(cls) -> int: """ Returns the target number of blobs per block. """ - return Spec.TARGET_DATA_GAS_PER_BLOCK.value // Spec.DATA_GAS_PER_BLOB.value + return Spec.TARGET_DATA_GAS_PER_BLOCK // Spec.DATA_GAS_PER_BLOB @classmethod def calc_excess_data_gas_from_blob_count( @@ -3794,7 +3790,7 @@

Calculate the excess data gas for a block given the parent excess data gas and the number of blobs in the block. """ - parent_consumed_data_gas = parent_blob_count * Spec.DATA_GAS_PER_BLOB.value + parent_consumed_data_gas = parent_blob_count * Spec.DATA_GAS_PER_BLOB return Spec.calc_excess_data_gas( BlockHeaderDataGasFields(parent_excess_data_gas, parent_consumed_data_gas) ) @@ -3807,7 +3803,7 @@

current_excess_data_gas = 0 current_data_gas_price = 1 while current_data_gas_price < data_gas_price: - current_excess_data_gas += Spec.DATA_GAS_PER_BLOB.value + current_excess_data_gas += Spec.DATA_GAS_PER_BLOB current_data_gas_price = Spec.get_data_gasprice( excess_data_gas=current_excess_data_gas ) @@ -3820,7 +3816,7 @@

""" return ( cls.get_min_excess_data_gas_for_data_gas_price(data_gas_price) - // Spec.DATA_GAS_PER_BLOB.value + // Spec.DATA_GAS_PER_BLOB )

@@ -3951,7 +3947,7 @@

Block( txs=[ template_tx.with_fields( - ty=Spec.BLOB_TX_TYPE.value, + ty=Spec.BLOB_TX_TYPE, nonce=i, to=address, access_list=[], @@ -4097,7 +4093,7 @@

Block( txs=[ template_tx.with_fields( - ty=Spec.BLOB_TX_TYPE.value, + ty=Spec.BLOB_TX_TYPE, nonce=i, to=address, access_list=[], diff --git a/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_blobhash_opcode/index/test_cases/index.html b/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_blobhash_opcode/index/test_cases/index.html index 7f09342fef..b936e6f95a 100644 --- a/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_blobhash_opcode/index/test_cases/index.html +++ b/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_blobhash_opcode/index/test_cases/index.html @@ -3216,7 +3216,7 @@

Test Blobhash Opcode - Test Cases

Test cases generated from tests/cancun/eip4844_blobs/test_blobhash_opcode.py

-

Parametrized test cases generated from the test module tests/cancun/eip4844_blobs/test_blobhash_opcode.py:

+

Parametrized test cases generated from the test module tests/cancun/eip4844_blobs/test_blobhash_opcode.py:

test_blobhash_gas_cost[fork=Cancun-tx_type=0]
 test_blobhash_gas_cost[fork=Cancun-tx_type=1]
 test_blobhash_gas_cost[fork=Cancun-tx_type=2]
diff --git a/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts/index.html b/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts/index.html
index f048c8bf02..1e65d70cc1 100644
--- a/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts/index.html
+++ b/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts/index.html
@@ -3240,7 +3240,7 @@
 
 
 

Test Blobhash Opcode Contexts

-

Documentation for tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts.py.

+

Documentation for tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts.py.

Generate fixtures for these test cases for Cancun with:

Cancun only: @@ -3290,8 +3290,6 @@

-

- Bases: IntEnum

Parameters from the EIP-4844 specifications as defined at @@ -3302,7 +3300,8 @@

Source code in tests/cancun/eip4844_blobs/spec.py -
 34
+          
 33
+ 34
  35
  36
  37
@@ -3392,9 +3391,8 @@ 

121 122 123 -124 -125

@dataclass(frozen=True)
-class Spec(IntEnum):
+124
@dataclass(frozen=True)
+class Spec:
     """
     Parameters from the EIP-4844 specifications as defined at
     https://eips.ethereum.org/EIPS/eip-4844#parameters
@@ -3457,8 +3455,8 @@ 

@classmethod def calc_excess_data_gas(cls, parent: BlockHeaderDataGasFields) -> int: """ - Calculate the excess data gas for a block given the parent excess data gas - and the number of blobs in the block. + Calculate the excess data gas for a block given the excess data gas + and data gas used from the parent block header. """ if parent.excess_data_gas + parent.data_gas_used < cls.TARGET_DATA_GAS_PER_BLOCK: return 0 @@ -3473,7 +3471,7 @@

# """ # if tx.blob_versioned_hashes is None: # return 0 - # return cls.DATA_GAS_PER_BLOB.value * len(tx.blob_versioned_hashes) + # return cls.DATA_GAS_PER_BLOB * len(tx.blob_versioned_hashes) @classmethod def get_data_gasprice(cls, *, excess_data_gas: int) -> int: @@ -3481,9 +3479,9 @@

Calculate the data gas price from the excess. """ return cls.fake_exponential( - cls.MIN_DATA_GASPRICE.value, + cls.MIN_DATA_GASPRICE, excess_data_gas, - cls.DATA_GASPRICE_UPDATE_FRACTION.value, + cls.DATA_GASPRICE_UPDATE_FRACTION, )

@@ -3523,8 +3521,6 @@

-

- Bases: Enum

Define parameters and helper functions that are tightly coupled to the 4844 @@ -3533,7 +3529,8 @@

Source code in tests/cancun/eip4844_blobs/spec.py -
128
+          
127
+128
 129
 130
 131
@@ -3590,9 +3587,8 @@ 

182 183 184 -185 -186

@dataclass(frozen=True)
-class SpecHelpers(Enum):
+185
@dataclass(frozen=True)
+class SpecHelpers:
     """
     Define parameters and helper functions that are tightly coupled to the 4844
     spec but not strictly part of it.
@@ -3605,14 +3601,14 @@ 

""" Returns the maximum number of blobs per block. """ - return Spec.MAX_DATA_GAS_PER_BLOCK.value // Spec.DATA_GAS_PER_BLOB.value + return Spec.MAX_DATA_GAS_PER_BLOCK // Spec.DATA_GAS_PER_BLOB @classmethod def target_blobs_per_block(cls) -> int: """ Returns the target number of blobs per block. """ - return Spec.TARGET_DATA_GAS_PER_BLOCK.value // Spec.DATA_GAS_PER_BLOB.value + return Spec.TARGET_DATA_GAS_PER_BLOCK // Spec.DATA_GAS_PER_BLOB @classmethod def calc_excess_data_gas_from_blob_count( @@ -3622,7 +3618,7 @@

Calculate the excess data gas for a block given the parent excess data gas and the number of blobs in the block. """ - parent_consumed_data_gas = parent_blob_count * Spec.DATA_GAS_PER_BLOB.value + parent_consumed_data_gas = parent_blob_count * Spec.DATA_GAS_PER_BLOB return Spec.calc_excess_data_gas( BlockHeaderDataGasFields(parent_excess_data_gas, parent_consumed_data_gas) ) @@ -3635,7 +3631,7 @@

current_excess_data_gas = 0 current_data_gas_price = 1 while current_data_gas_price < data_gas_price: - current_excess_data_gas += Spec.DATA_GAS_PER_BLOB.value + current_excess_data_gas += Spec.DATA_GAS_PER_BLOB current_data_gas_price = Spec.get_data_gasprice( excess_data_gas=current_excess_data_gas ) @@ -3648,7 +3644,7 @@

""" return ( cls.get_min_excess_data_gas_for_data_gas_price(data_gas_price) - // Spec.DATA_GAS_PER_BLOB.value + // Spec.DATA_GAS_PER_BLOB )

diff --git a/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts/index/test_cases/index.html b/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts/index/test_cases/index.html index 96f4b9b006..7144d1e5d0 100644 --- a/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts/index/test_cases/index.html +++ b/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts/index/test_cases/index.html @@ -3216,7 +3216,7 @@

Test Blobhash Opcode Contexts - Test Cases

Test cases generated from tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts.py

-

Parametrized test cases generated from the test module tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts.py:

+

Parametrized test cases generated from the test module tests/cancun/eip4844_blobs/test_blobhash_opcode_contexts.py:

test_blobhash_opcode_contexts[opcode_context=on_top_level_call_stack-fork=Cancun]
 test_blobhash_opcode_contexts[opcode_context=on_max_value-fork=Cancun]
 test_blobhash_opcode_contexts[opcode_context=on_CALL-fork=Cancun]
diff --git a/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_excess_data_gas/index.html b/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_excess_data_gas/index.html
index debbf29bba..eb09b1468c 100644
--- a/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_excess_data_gas/index.html
+++ b/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_excess_data_gas/index.html
@@ -3317,7 +3317,7 @@
 
 
 

Test Excess Data Gas

-

Documentation for tests/cancun/eip4844_blobs/test_excess_data_gas.py.

+

Documentation for tests/cancun/eip4844_blobs/test_excess_data_gas.py.

Generate fixtures for these test cases for Cancun with:

Cancun only: @@ -3384,8 +3384,6 @@

-

- Bases: IntEnum

Parameters from the EIP-4844 specifications as defined at @@ -3396,7 +3394,8 @@

Source code in tests/cancun/eip4844_blobs/spec.py -
 34
+          
 33
+ 34
  35
  36
  37
@@ -3486,9 +3485,8 @@ 

121 122 123 -124 -125

@dataclass(frozen=True)
-class Spec(IntEnum):
+124
@dataclass(frozen=True)
+class Spec:
     """
     Parameters from the EIP-4844 specifications as defined at
     https://eips.ethereum.org/EIPS/eip-4844#parameters
@@ -3551,8 +3549,8 @@ 

@classmethod def calc_excess_data_gas(cls, parent: BlockHeaderDataGasFields) -> int: """ - Calculate the excess data gas for a block given the parent excess data gas - and the number of blobs in the block. + Calculate the excess data gas for a block given the excess data gas + and data gas used from the parent block header. """ if parent.excess_data_gas + parent.data_gas_used < cls.TARGET_DATA_GAS_PER_BLOCK: return 0 @@ -3567,7 +3565,7 @@

# """ # if tx.blob_versioned_hashes is None: # return 0 - # return cls.DATA_GAS_PER_BLOB.value * len(tx.blob_versioned_hashes) + # return cls.DATA_GAS_PER_BLOB * len(tx.blob_versioned_hashes) @classmethod def get_data_gasprice(cls, *, excess_data_gas: int) -> int: @@ -3575,9 +3573,9 @@

Calculate the data gas price from the excess. """ return cls.fake_exponential( - cls.MIN_DATA_GASPRICE.value, + cls.MIN_DATA_GASPRICE, excess_data_gas, - cls.DATA_GASPRICE_UPDATE_FRACTION.value, + cls.DATA_GASPRICE_UPDATE_FRACTION, )

@@ -3617,8 +3615,6 @@

-

- Bases: Enum

Define parameters and helper functions that are tightly coupled to the 4844 @@ -3627,7 +3623,8 @@

Source code in tests/cancun/eip4844_blobs/spec.py -
128
+          
127
+128
 129
 130
 131
@@ -3684,9 +3681,8 @@ 

182 183 184 -185 -186

@dataclass(frozen=True)
-class SpecHelpers(Enum):
+185
@dataclass(frozen=True)
+class SpecHelpers:
     """
     Define parameters and helper functions that are tightly coupled to the 4844
     spec but not strictly part of it.
@@ -3699,14 +3695,14 @@ 

""" Returns the maximum number of blobs per block. """ - return Spec.MAX_DATA_GAS_PER_BLOCK.value // Spec.DATA_GAS_PER_BLOB.value + return Spec.MAX_DATA_GAS_PER_BLOCK // Spec.DATA_GAS_PER_BLOB @classmethod def target_blobs_per_block(cls) -> int: """ Returns the target number of blobs per block. """ - return Spec.TARGET_DATA_GAS_PER_BLOCK.value // Spec.DATA_GAS_PER_BLOB.value + return Spec.TARGET_DATA_GAS_PER_BLOCK // Spec.DATA_GAS_PER_BLOB @classmethod def calc_excess_data_gas_from_blob_count( @@ -3716,7 +3712,7 @@

Calculate the excess data gas for a block given the parent excess data gas and the number of blobs in the block. """ - parent_consumed_data_gas = parent_blob_count * Spec.DATA_GAS_PER_BLOB.value + parent_consumed_data_gas = parent_blob_count * Spec.DATA_GAS_PER_BLOB return Spec.calc_excess_data_gas( BlockHeaderDataGasFields(parent_excess_data_gas, parent_consumed_data_gas) ) @@ -3729,7 +3725,7 @@

current_excess_data_gas = 0 current_data_gas_price = 1 while current_data_gas_price < data_gas_price: - current_excess_data_gas += Spec.DATA_GAS_PER_BLOB.value + current_excess_data_gas += Spec.DATA_GAS_PER_BLOB current_data_gas_price = Spec.get_data_gasprice( excess_data_gas=current_excess_data_gas ) @@ -3742,7 +3738,7 @@

""" return ( cls.get_min_excess_data_gas_for_data_gas_price(data_gas_price) - // Spec.DATA_GAS_PER_BLOB.value + // Spec.DATA_GAS_PER_BLOB )

diff --git a/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_excess_data_gas/index/test_cases/index.html b/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_excess_data_gas/index/test_cases/index.html index 594a637582..a2136a395e 100644 --- a/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_excess_data_gas/index/test_cases/index.html +++ b/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_excess_data_gas/index/test_cases/index.html @@ -3216,7 +3216,7 @@

Test Excess Data Gas - Test Cases

Test cases generated from tests/cancun/eip4844_blobs/test_excess_data_gas.py

-

Parametrized test cases generated from the test module tests/cancun/eip4844_blobs/test_excess_data_gas.py:

+

Parametrized test cases generated from the test module tests/cancun/eip4844_blobs/test_excess_data_gas.py:

test_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=0]
 test_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=1]
 test_correct_excess_data_gas_calculation[fork=Cancun-new_blobs=1-parent_excess_blobs=0-parent_blobs=2]
diff --git a/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition/index.html b/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition/index.html
index 4b432ab797..e0e78ab6a2 100644
--- a/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition/index.html
+++ b/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition/index.html
@@ -3254,7 +3254,7 @@
 
 
 

Test Excess Data Gas Fork Transition

-

Documentation for tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition.py.

+

Documentation for tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition.py.

Generate fixtures for these test cases for Cancun with:

Cancun only: @@ -3304,8 +3304,6 @@

-

- Bases: IntEnum

Parameters from the EIP-4844 specifications as defined at @@ -3316,7 +3314,8 @@

Source code in tests/cancun/eip4844_blobs/spec.py -
 34
+          
 33
+ 34
  35
  36
  37
@@ -3406,9 +3405,8 @@ 

121 122 123 -124 -125

@dataclass(frozen=True)
-class Spec(IntEnum):
+124
@dataclass(frozen=True)
+class Spec:
     """
     Parameters from the EIP-4844 specifications as defined at
     https://eips.ethereum.org/EIPS/eip-4844#parameters
@@ -3471,8 +3469,8 @@ 

@classmethod def calc_excess_data_gas(cls, parent: BlockHeaderDataGasFields) -> int: """ - Calculate the excess data gas for a block given the parent excess data gas - and the number of blobs in the block. + Calculate the excess data gas for a block given the excess data gas + and data gas used from the parent block header. """ if parent.excess_data_gas + parent.data_gas_used < cls.TARGET_DATA_GAS_PER_BLOCK: return 0 @@ -3487,7 +3485,7 @@

# """ # if tx.blob_versioned_hashes is None: # return 0 - # return cls.DATA_GAS_PER_BLOB.value * len(tx.blob_versioned_hashes) + # return cls.DATA_GAS_PER_BLOB * len(tx.blob_versioned_hashes) @classmethod def get_data_gasprice(cls, *, excess_data_gas: int) -> int: @@ -3495,9 +3493,9 @@

Calculate the data gas price from the excess. """ return cls.fake_exponential( - cls.MIN_DATA_GASPRICE.value, + cls.MIN_DATA_GASPRICE, excess_data_gas, - cls.DATA_GASPRICE_UPDATE_FRACTION.value, + cls.DATA_GASPRICE_UPDATE_FRACTION, )

@@ -3537,8 +3535,6 @@

-

- Bases: Enum

Define parameters and helper functions that are tightly coupled to the 4844 @@ -3547,7 +3543,8 @@

Source code in tests/cancun/eip4844_blobs/spec.py -
128
+          
127
+128
 129
 130
 131
@@ -3604,9 +3601,8 @@ 

182 183 184 -185 -186

@dataclass(frozen=True)
-class SpecHelpers(Enum):
+185
@dataclass(frozen=True)
+class SpecHelpers:
     """
     Define parameters and helper functions that are tightly coupled to the 4844
     spec but not strictly part of it.
@@ -3619,14 +3615,14 @@ 

""" Returns the maximum number of blobs per block. """ - return Spec.MAX_DATA_GAS_PER_BLOCK.value // Spec.DATA_GAS_PER_BLOB.value + return Spec.MAX_DATA_GAS_PER_BLOCK // Spec.DATA_GAS_PER_BLOB @classmethod def target_blobs_per_block(cls) -> int: """ Returns the target number of blobs per block. """ - return Spec.TARGET_DATA_GAS_PER_BLOCK.value // Spec.DATA_GAS_PER_BLOB.value + return Spec.TARGET_DATA_GAS_PER_BLOCK // Spec.DATA_GAS_PER_BLOB @classmethod def calc_excess_data_gas_from_blob_count( @@ -3636,7 +3632,7 @@

Calculate the excess data gas for a block given the parent excess data gas and the number of blobs in the block. """ - parent_consumed_data_gas = parent_blob_count * Spec.DATA_GAS_PER_BLOB.value + parent_consumed_data_gas = parent_blob_count * Spec.DATA_GAS_PER_BLOB return Spec.calc_excess_data_gas( BlockHeaderDataGasFields(parent_excess_data_gas, parent_consumed_data_gas) ) @@ -3649,7 +3645,7 @@

current_excess_data_gas = 0 current_data_gas_price = 1 while current_data_gas_price < data_gas_price: - current_excess_data_gas += Spec.DATA_GAS_PER_BLOB.value + current_excess_data_gas += Spec.DATA_GAS_PER_BLOB current_data_gas_price = Spec.get_data_gasprice( excess_data_gas=current_excess_data_gas ) @@ -3662,7 +3658,7 @@

""" return ( cls.get_min_excess_data_gas_for_data_gas_price(data_gas_price) - // Spec.DATA_GAS_PER_BLOB.value + // Spec.DATA_GAS_PER_BLOB )

diff --git a/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition/index/test_cases/index.html b/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition/index/test_cases/index.html index 087a3616ab..1680345c3e 100644 --- a/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition/index/test_cases/index.html +++ b/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition/index/test_cases/index.html @@ -3216,7 +3216,7 @@

Test Excess Data Gas Fork Transition - Test Cases

Test cases generated from tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition.py

-

Parametrized test cases generated from the test module tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition.py:

+

Parametrized test cases generated from the test module tests/cancun/eip4844_blobs/test_excess_data_gas_fork_transition.py:

test_invalid_pre_fork_block_with_blob_fields[fork=ShanghaiToCancunAtTime15k-excess_data_gas_present=True-data_gas_used_present=False]
 test_invalid_pre_fork_block_with_blob_fields[fork=ShanghaiToCancunAtTime15k-excess_data_gas_present=False-data_gas_used_present=True]
 test_invalid_pre_fork_block_with_blob_fields[fork=ShanghaiToCancunAtTime15k-excess_data_gas_present=True-data_gas_used_present=True]
diff --git a/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_point_evaluation_precompile/index.html b/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_point_evaluation_precompile/index.html
index 9c89af39ad..5bde250878 100644
--- a/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_point_evaluation_precompile/index.html
+++ b/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_point_evaluation_precompile/index.html
@@ -3268,7 +3268,7 @@
 
 
 

Test Point Evaluation Precompile

-

Documentation for tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py.

+

Documentation for tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py.

Generate fixtures for these test cases for Cancun with:

Cancun only: @@ -3340,8 +3340,6 @@

-

- Bases: IntEnum

Parameters from the EIP-4844 specifications as defined at @@ -3352,7 +3350,8 @@

Source code in tests/cancun/eip4844_blobs/spec.py -
 34
+          
 33
+ 34
  35
  36
  37
@@ -3442,9 +3441,8 @@ 

121 122 123 -124 -125

@dataclass(frozen=True)
-class Spec(IntEnum):
+124
@dataclass(frozen=True)
+class Spec:
     """
     Parameters from the EIP-4844 specifications as defined at
     https://eips.ethereum.org/EIPS/eip-4844#parameters
@@ -3507,8 +3505,8 @@ 

@classmethod def calc_excess_data_gas(cls, parent: BlockHeaderDataGasFields) -> int: """ - Calculate the excess data gas for a block given the parent excess data gas - and the number of blobs in the block. + Calculate the excess data gas for a block given the excess data gas + and data gas used from the parent block header. """ if parent.excess_data_gas + parent.data_gas_used < cls.TARGET_DATA_GAS_PER_BLOCK: return 0 @@ -3523,7 +3521,7 @@

# """ # if tx.blob_versioned_hashes is None: # return 0 - # return cls.DATA_GAS_PER_BLOB.value * len(tx.blob_versioned_hashes) + # return cls.DATA_GAS_PER_BLOB * len(tx.blob_versioned_hashes) @classmethod def get_data_gasprice(cls, *, excess_data_gas: int) -> int: @@ -3531,9 +3529,9 @@

Calculate the data gas price from the excess. """ return cls.fake_exponential( - cls.MIN_DATA_GASPRICE.value, + cls.MIN_DATA_GASPRICE, excess_data_gas, - cls.DATA_GASPRICE_UPDATE_FRACTION.value, + cls.DATA_GASPRICE_UPDATE_FRACTION, )

@@ -4123,7 +4121,7 @@

ty=2, nonce=0, data=precompile_input, - to=to_address(Spec.POINT_EVALUATION_PRECOMPILE_ADDRESS.value), + to=to_address(Spec.POINT_EVALUATION_PRECOMPILE_ADDRESS), value=0, gas_limit=call_gas + intrinsic_gas_cost, max_fee_per_gas=7, @@ -4301,7 +4299,7 @@

storage={b: 1 for b in range(1, len(PRE_FORK_BLOCK_RANGE) + 1)}, # The tx in last block succeeds; storage 0 by default. ), - to_address(Spec.POINT_EVALUATION_PRECOMPILE_ADDRESS.value): Account( + to_address(Spec.POINT_EVALUATION_PRECOMPILE_ADDRESS): Account( balance=len(PRE_FORK_BLOCK_RANGE), ), } diff --git a/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_point_evaluation_precompile/index/test_cases/index.html b/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_point_evaluation_precompile/index/test_cases/index.html index c01f76c570..f7bf7f56f2 100644 --- a/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_point_evaluation_precompile/index/test_cases/index.html +++ b/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_point_evaluation_precompile/index/test_cases/index.html @@ -3216,7 +3216,7 @@

Test Point Evaluation Precompile - Test Cases

Test cases generated from tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py

-

Parametrized test cases generated from the test module tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py:

+

Parametrized test cases generated from the test module tests/cancun/eip4844_blobs/test_point_evaluation_precompile.py:

test_valid_precompile_calls[fork=Cancun-success=True-in_bounds_z]
 test_invalid_precompile_calls[fork=Cancun-success=False-out_of_bounds_z]
 test_invalid_precompile_calls[fork=Cancun-success=False-out_of_bounds_y]
diff --git a/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas/index.html b/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas/index.html
index 9d1979e9ac..7997d3a27c 100644
--- a/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas/index.html
+++ b/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas/index.html
@@ -3233,7 +3233,7 @@
 
 
 

Test Point Evaluation Precompile Gas

-

Documentation for tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas.py.

+

Documentation for tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas.py.

Generate fixtures for these test cases for Cancun with:

Cancun only: @@ -3282,8 +3282,6 @@

-

- Bases: IntEnum

Parameters from the EIP-4844 specifications as defined at @@ -3294,7 +3292,8 @@

Source code in tests/cancun/eip4844_blobs/spec.py -
 34
+          
 33
+ 34
  35
  36
  37
@@ -3384,9 +3383,8 @@ 

121 122 123 -124 -125

@dataclass(frozen=True)
-class Spec(IntEnum):
+124
@dataclass(frozen=True)
+class Spec:
     """
     Parameters from the EIP-4844 specifications as defined at
     https://eips.ethereum.org/EIPS/eip-4844#parameters
@@ -3449,8 +3447,8 @@ 

@classmethod def calc_excess_data_gas(cls, parent: BlockHeaderDataGasFields) -> int: """ - Calculate the excess data gas for a block given the parent excess data gas - and the number of blobs in the block. + Calculate the excess data gas for a block given the excess data gas + and data gas used from the parent block header. """ if parent.excess_data_gas + parent.data_gas_used < cls.TARGET_DATA_GAS_PER_BLOCK: return 0 @@ -3465,7 +3463,7 @@

# """ # if tx.blob_versioned_hashes is None: # return 0 - # return cls.DATA_GAS_PER_BLOB.value * len(tx.blob_versioned_hashes) + # return cls.DATA_GAS_PER_BLOB * len(tx.blob_versioned_hashes) @classmethod def get_data_gasprice(cls, *, excess_data_gas: int) -> int: @@ -3473,9 +3471,9 @@

Calculate the data gas price from the excess. """ return cls.fake_exponential( - cls.MIN_DATA_GASPRICE.value, + cls.MIN_DATA_GASPRICE, excess_data_gas, - cls.DATA_GASPRICE_UPDATE_FRACTION.value, + cls.DATA_GASPRICE_UPDATE_FRACTION, )

@@ -3559,9 +3557,9 @@

@pytest.mark.parametrize( "call_gas", [ - Spec.POINT_EVALUATION_PRECOMPILE_GAS.value, - Spec.POINT_EVALUATION_PRECOMPILE_GAS.value - 1, - Spec.POINT_EVALUATION_PRECOMPILE_GAS.value + 1, + Spec.POINT_EVALUATION_PRECOMPILE_GAS, + Spec.POINT_EVALUATION_PRECOMPILE_GAS - 1, + Spec.POINT_EVALUATION_PRECOMPILE_GAS + 1, ], ids=["exact_gas", "insufficient_gas", "extra_gas"], ) diff --git a/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas/index/test_cases/index.html b/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas/index/test_cases/index.html index 9ea77defc0..29df40eaed 100644 --- a/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas/index/test_cases/index.html +++ b/v1.0.1b1-refactor-4844-specs/tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas/index/test_cases/index.html @@ -3216,7 +3216,7 @@

Test Point Evaluation Precompile Gas - Test Cases

Test cases generated from tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas.py

-

Parametrized test cases generated from the test module tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas.py:

+

Parametrized test cases generated from the test module tests/cancun/eip4844_blobs/test_point_evaluation_precompile_gas.py:

test_point_evaluation_precompile_gas_usage[fork=Cancun-proof=correct-exact_gas-call_type=CALL]
 test_point_evaluation_precompile_gas_usage[fork=Cancun-proof=correct-exact_gas-call_type=DELEGATECALL]
 test_point_evaluation_precompile_gas_usage[fork=Cancun-proof=correct-exact_gas-call_type=CALLCODE]
diff --git a/v1.0.1b1-refactor-4844-specs/tests/cancun/index.html b/v1.0.1b1-refactor-4844-specs/tests/cancun/index.html
index 3ac3e3a1e7..acdf4c19b0 100644
--- a/v1.0.1b1-refactor-4844-specs/tests/cancun/index.html
+++ b/v1.0.1b1-refactor-4844-specs/tests/cancun/index.html
@@ -3215,7 +3215,7 @@
 
 
 

Cancun

-

Documentation for tests/cancun.

+

Documentation for tests/cancun.

Generate fixtures for these test cases for Cancun with:

Cancun only: diff --git a/v1.0.1b1-refactor-4844-specs/tests/frontier/index.html b/v1.0.1b1-refactor-4844-specs/tests/frontier/index.html index c4a940c35d..7da09c41c1 100644 --- a/v1.0.1b1-refactor-4844-specs/tests/frontier/index.html +++ b/v1.0.1b1-refactor-4844-specs/tests/frontier/index.html @@ -3215,7 +3215,7 @@

Frontier

-

Documentation for tests/frontier.

+

Documentation for tests/frontier.

Generate fixtures for these test cases with:

fill -v tests/frontier
diff --git a/v1.0.1b1-refactor-4844-specs/tests/frontier/opcodes/index.html b/v1.0.1b1-refactor-4844-specs/tests/frontier/opcodes/index.html
index 9d99a26957..9e4026f484 100644
--- a/v1.0.1b1-refactor-4844-specs/tests/frontier/opcodes/index.html
+++ b/v1.0.1b1-refactor-4844-specs/tests/frontier/opcodes/index.html
@@ -3217,7 +3217,7 @@
 
 
 

Opcodes

-

Documentation for tests/frontier/opcodes.

+

Documentation for tests/frontier/opcodes.

Generate fixtures for these test cases with:

fill -v tests/frontier/opcodes
diff --git a/v1.0.1b1-refactor-4844-specs/tests/frontier/opcodes/test_dup/index.html b/v1.0.1b1-refactor-4844-specs/tests/frontier/opcodes/test_dup/index.html
index d1bbcadc37..b7b4a7bedb 100644
--- a/v1.0.1b1-refactor-4844-specs/tests/frontier/opcodes/test_dup/index.html
+++ b/v1.0.1b1-refactor-4844-specs/tests/frontier/opcodes/test_dup/index.html
@@ -3226,7 +3226,7 @@
 
 
 

Test DUP

-

Documentation for tests/frontier/opcodes/test_dup.py.

+

Documentation for tests/frontier/opcodes/test_dup.py.

Generate fixtures for these test cases with:

fill -v tests/frontier/opcodes/test_dup.py
diff --git a/v1.0.1b1-refactor-4844-specs/tests/frontier/opcodes/test_dup/index/test_cases/index.html b/v1.0.1b1-refactor-4844-specs/tests/frontier/opcodes/test_dup/index/test_cases/index.html
index c2c74705e1..948c38ab5c 100644
--- a/v1.0.1b1-refactor-4844-specs/tests/frontier/opcodes/test_dup/index/test_cases/index.html
+++ b/v1.0.1b1-refactor-4844-specs/tests/frontier/opcodes/test_dup/index/test_cases/index.html
@@ -3214,7 +3214,7 @@
 

Test DUP - Test Cases

Test cases generated from tests/frontier/opcodes/test_dup.py

-

Parametrized test cases generated from the test module tests/frontier/opcodes/test_dup.py:

+

Parametrized test cases generated from the test module tests/frontier/opcodes/test_dup.py:

test_dup[fork=Frontier]
 test_dup[fork=Homestead]
 test_dup[fork=Byzantium]
diff --git a/v1.0.1b1-refactor-4844-specs/tests/homestead/index.html b/v1.0.1b1-refactor-4844-specs/tests/homestead/index.html
index 966c526304..549ffcfabc 100644
--- a/v1.0.1b1-refactor-4844-specs/tests/homestead/index.html
+++ b/v1.0.1b1-refactor-4844-specs/tests/homestead/index.html
@@ -3215,7 +3215,7 @@
 
 
 

Homestead

-

Documentation for tests/homestead.

+

Documentation for tests/homestead.

Generate fixtures for these test cases with:

fill -v tests/homestead
diff --git a/v1.0.1b1-refactor-4844-specs/tests/homestead/yul/index.html b/v1.0.1b1-refactor-4844-specs/tests/homestead/yul/index.html
index ee25548e96..04a847c400 100644
--- a/v1.0.1b1-refactor-4844-specs/tests/homestead/yul/index.html
+++ b/v1.0.1b1-refactor-4844-specs/tests/homestead/yul/index.html
@@ -3217,7 +3217,7 @@
 
 
 

Yul

-

Documentation for tests/homestead/yul.

+

Documentation for tests/homestead/yul.

Generate fixtures for these test cases with:

fill -v tests/homestead/yul
diff --git a/v1.0.1b1-refactor-4844-specs/tests/homestead/yul/test_yul_example/index.html b/v1.0.1b1-refactor-4844-specs/tests/homestead/yul/test_yul_example/index.html
index 8f78f375d0..cb60a94501 100644
--- a/v1.0.1b1-refactor-4844-specs/tests/homestead/yul/test_yul_example/index.html
+++ b/v1.0.1b1-refactor-4844-specs/tests/homestead/yul/test_yul_example/index.html
@@ -3226,7 +3226,7 @@
 
 
 

Test Yul Example

-

Documentation for tests/homestead/yul/test_yul_example.py.

+

Documentation for tests/homestead/yul/test_yul_example.py.

Generate fixtures for these test cases with:

fill -v tests/homestead/yul/test_yul_example.py
diff --git a/v1.0.1b1-refactor-4844-specs/tests/homestead/yul/test_yul_example/index/test_cases/index.html b/v1.0.1b1-refactor-4844-specs/tests/homestead/yul/test_yul_example/index/test_cases/index.html
index 6c232bfc0d..e23352b140 100644
--- a/v1.0.1b1-refactor-4844-specs/tests/homestead/yul/test_yul_example/index/test_cases/index.html
+++ b/v1.0.1b1-refactor-4844-specs/tests/homestead/yul/test_yul_example/index/test_cases/index.html
@@ -3216,7 +3216,7 @@
 

Test Yul Example - Test Cases

Test cases generated from tests/homestead/yul/test_yul_example.py

-

Parametrized test cases generated from the test module tests/homestead/yul/test_yul_example.py:

+

Parametrized test cases generated from the test module tests/homestead/yul/test_yul_example.py:

test_yul[fork=Homestead]
 test_yul[fork=Byzantium]
 test_yul[fork=Constantinople]
diff --git a/v1.0.1b1-refactor-4844-specs/tests/index.html b/v1.0.1b1-refactor-4844-specs/tests/index.html
index 10c7d48e40..af38894898 100644
--- a/v1.0.1b1-refactor-4844-specs/tests/index.html
+++ b/v1.0.1b1-refactor-4844-specs/tests/index.html
@@ -3213,7 +3213,7 @@
 
 
 

Test case reference

-

Documentation for tests.

+

Documentation for tests.

Generate fixtures for these test cases for all forks deployed to mainnet with:

fill -v tests
diff --git a/v1.0.1b1-refactor-4844-specs/tests/istanbul/eip1344_chainid/index.html b/v1.0.1b1-refactor-4844-specs/tests/istanbul/eip1344_chainid/index.html
index 29fab6868c..dcd41f3285 100644
--- a/v1.0.1b1-refactor-4844-specs/tests/istanbul/eip1344_chainid/index.html
+++ b/v1.0.1b1-refactor-4844-specs/tests/istanbul/eip1344_chainid/index.html
@@ -3217,7 +3217,7 @@
 
 
 

EIP-1344 CHAINID

-

Documentation for tests/istanbul/eip1344_chainid.

+

Documentation for tests/istanbul/eip1344_chainid.

Generate fixtures for these test cases with:

fill -v tests/istanbul/eip1344_chainid
diff --git a/v1.0.1b1-refactor-4844-specs/tests/istanbul/eip1344_chainid/test_chainid/index.html b/v1.0.1b1-refactor-4844-specs/tests/istanbul/eip1344_chainid/test_chainid/index.html
index a35d9daa23..16a756dc2c 100644
--- a/v1.0.1b1-refactor-4844-specs/tests/istanbul/eip1344_chainid/test_chainid/index.html
+++ b/v1.0.1b1-refactor-4844-specs/tests/istanbul/eip1344_chainid/test_chainid/index.html
@@ -3226,7 +3226,7 @@
 
 
 

Test CHAINID

-

Documentation for tests/istanbul/eip1344_chainid/test_chainid.py.

+

Documentation for tests/istanbul/eip1344_chainid/test_chainid.py.

Generate fixtures for these test cases with:

fill -v tests/istanbul/eip1344_chainid/test_chainid.py
diff --git a/v1.0.1b1-refactor-4844-specs/tests/istanbul/eip1344_chainid/test_chainid/index/test_cases/index.html b/v1.0.1b1-refactor-4844-specs/tests/istanbul/eip1344_chainid/test_chainid/index/test_cases/index.html
index 5186c1c8d2..80d3819f4a 100644
--- a/v1.0.1b1-refactor-4844-specs/tests/istanbul/eip1344_chainid/test_chainid/index/test_cases/index.html
+++ b/v1.0.1b1-refactor-4844-specs/tests/istanbul/eip1344_chainid/test_chainid/index/test_cases/index.html
@@ -3216,7 +3216,7 @@
 

Test CHAINID - Test Cases

Test cases generated from tests/istanbul/eip1344_chainid/test_chainid.py

-

Parametrized test cases generated from the test module tests/istanbul/eip1344_chainid/test_chainid.py:

+

Parametrized test cases generated from the test module tests/istanbul/eip1344_chainid/test_chainid.py:

test_chainid[fork=Istanbul]
 test_chainid[fork=Berlin]
 test_chainid[fork=London]
diff --git a/v1.0.1b1-refactor-4844-specs/tests/istanbul/index.html b/v1.0.1b1-refactor-4844-specs/tests/istanbul/index.html
index d49a3f77fa..bdec9613d5 100644
--- a/v1.0.1b1-refactor-4844-specs/tests/istanbul/index.html
+++ b/v1.0.1b1-refactor-4844-specs/tests/istanbul/index.html
@@ -3215,7 +3215,7 @@
 
 
 

Istanbul

-

Documentation for tests/istanbul.

+

Documentation for tests/istanbul.

Generate fixtures for these test cases with:

fill -v tests/istanbul
diff --git a/v1.0.1b1-refactor-4844-specs/tests/merge/index.html b/v1.0.1b1-refactor-4844-specs/tests/merge/index.html
index d3b9bee826..bbe90307bb 100644
--- a/v1.0.1b1-refactor-4844-specs/tests/merge/index.html
+++ b/v1.0.1b1-refactor-4844-specs/tests/merge/index.html
@@ -3215,7 +3215,7 @@
 
 
 

Merge

-

Documentation for tests/merge.

+

Documentation for tests/merge.

Generate fixtures for these test cases with:

fill -v tests/merge
diff --git a/v1.0.1b1-refactor-4844-specs/tests/merge/security/index.html b/v1.0.1b1-refactor-4844-specs/tests/merge/security/index.html
index 7e6c2d1af7..c78b803f56 100644
--- a/v1.0.1b1-refactor-4844-specs/tests/merge/security/index.html
+++ b/v1.0.1b1-refactor-4844-specs/tests/merge/security/index.html
@@ -3217,7 +3217,7 @@
 
 
 

Security

-

Documentation for tests/merge/security.

+

Documentation for tests/merge/security.

Generate fixtures for these test cases with:

fill -v tests/merge/security
diff --git a/v1.0.1b1-refactor-4844-specs/tests/merge/security/test_selfdestruct_balance_bug/index.html b/v1.0.1b1-refactor-4844-specs/tests/merge/security/test_selfdestruct_balance_bug/index.html
index f106a382ad..b3922711bd 100644
--- a/v1.0.1b1-refactor-4844-specs/tests/merge/security/test_selfdestruct_balance_bug/index.html
+++ b/v1.0.1b1-refactor-4844-specs/tests/merge/security/test_selfdestruct_balance_bug/index.html
@@ -3226,7 +3226,7 @@
 
 
 

Test Selfdestruct Balance Bug

-

Documentation for tests/merge/security/test_selfdestruct_balance_bug.py.

+

Documentation for tests/merge/security/test_selfdestruct_balance_bug.py.

Generate fixtures for these test cases with:

fill -v tests/merge/security/test_selfdestruct_balance_bug.py
diff --git a/v1.0.1b1-refactor-4844-specs/tests/merge/security/test_selfdestruct_balance_bug/index/test_cases/index.html b/v1.0.1b1-refactor-4844-specs/tests/merge/security/test_selfdestruct_balance_bug/index/test_cases/index.html
index 7efe173885..03a2390d4b 100644
--- a/v1.0.1b1-refactor-4844-specs/tests/merge/security/test_selfdestruct_balance_bug/index/test_cases/index.html
+++ b/v1.0.1b1-refactor-4844-specs/tests/merge/security/test_selfdestruct_balance_bug/index/test_cases/index.html
@@ -3216,7 +3216,7 @@
 

Test Selfdestruct Balance Bug - Test Cases

Test cases generated from tests/merge/security/test_selfdestruct_balance_bug.py

-

Parametrized test cases generated from the test module tests/merge/security/test_selfdestruct_balance_bug.py:

+

Parametrized test cases generated from the test module tests/merge/security/test_selfdestruct_balance_bug.py:

test_tx_selfdestruct_balance_bug[fork=Constantinople]
 test_tx_selfdestruct_balance_bug[fork=ConstantinopleFix]
 test_tx_selfdestruct_balance_bug[fork=Istanbul]
diff --git a/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip3651_warm_coinbase/index.html b/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip3651_warm_coinbase/index.html
index 61b652ea7f..23934123be 100644
--- a/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip3651_warm_coinbase/index.html
+++ b/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip3651_warm_coinbase/index.html
@@ -3217,7 +3217,7 @@
 
 
 

EIP-3651 Warm Coinbase

-

Documentation for tests/shanghai/eip3651_warm_coinbase.

+

Documentation for tests/shanghai/eip3651_warm_coinbase.

Generate fixtures for these test cases with:

fill -v tests/shanghai/eip3651_warm_coinbase
diff --git a/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase/index.html b/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase/index.html
index 5310f73250..fc15c14139 100644
--- a/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase/index.html
+++ b/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase/index.html
@@ -3233,7 +3233,7 @@
 
 
 

Test Warm Coinbase

-

Documentation for tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase.py.

+

Documentation for tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase.py.

Generate fixtures for these test cases with:

fill -v tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase.py
diff --git a/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase/index/test_cases/index.html b/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase/index/test_cases/index.html
index 55f8b8fa38..d3f8897bb2 100644
--- a/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase/index/test_cases/index.html
+++ b/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase/index/test_cases/index.html
@@ -3216,7 +3216,7 @@
 

Test Warm Coinbase - Test Cases

Test cases generated from tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase.py

-

Parametrized test cases generated from the test module tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase.py:

+

Parametrized test cases generated from the test module tests/shanghai/eip3651_warm_coinbase/test_warm_coinbase.py:

test_warm_coinbase_call_out_of_gas[fork=Shanghai-CALL-sufficient_gas]
 test_warm_coinbase_call_out_of_gas[fork=Shanghai-CALL-insufficient_gas]
 test_warm_coinbase_call_out_of_gas[fork=Shanghai-CALLCODE-sufficient_gas]
diff --git a/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip3855_push0/index.html b/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip3855_push0/index.html
index ef61936cb1..5d734a305f 100644
--- a/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip3855_push0/index.html
+++ b/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip3855_push0/index.html
@@ -3217,7 +3217,7 @@
 
 
 

EIP-3855 Push0

-

Documentation for tests/shanghai/eip3855_push0.

+

Documentation for tests/shanghai/eip3855_push0.

Generate fixtures for these test cases with:

fill -v tests/shanghai/eip3855_push0
diff --git a/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip3855_push0/test_push0/index.html b/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip3855_push0/test_push0/index.html
index 1ba255bcd0..b5b5ef9e96 100644
--- a/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip3855_push0/test_push0/index.html
+++ b/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip3855_push0/test_push0/index.html
@@ -3268,7 +3268,7 @@
 
 
 

Test Push0

-

Documentation for tests/shanghai/eip3855_push0/test_push0.py.

+

Documentation for tests/shanghai/eip3855_push0/test_push0.py.

Generate fixtures for these test cases with:

fill -v tests/shanghai/eip3855_push0/test_push0.py
diff --git a/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip3855_push0/test_push0/index/test_cases/index.html b/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip3855_push0/test_push0/index/test_cases/index.html
index 299be760dc..bd3aa314f1 100644
--- a/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip3855_push0/test_push0/index/test_cases/index.html
+++ b/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip3855_push0/test_push0/index/test_cases/index.html
@@ -3216,7 +3216,7 @@
 

Test Push0 - Test Cases

Test cases generated from tests/shanghai/eip3855_push0/test_push0.py

-

Parametrized test cases generated from the test module tests/shanghai/eip3855_push0/test_push0.py:

+

Parametrized test cases generated from the test module tests/shanghai/eip3855_push0/test_push0.py:

test_push0_key_sstore[fork=Shanghai]
 test_push0_key_sstore[fork=Cancun]
 test_push0_fill_stack[fork=Shanghai]
diff --git a/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip3860_initcode/index.html b/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip3860_initcode/index.html
index bcc3677223..d4aec1adef 100644
--- a/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip3860_initcode/index.html
+++ b/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip3860_initcode/index.html
@@ -3217,7 +3217,7 @@
 
 
 

EIP-3860 Initcode

-

Documentation for tests/shanghai/eip3860_initcode.

+

Documentation for tests/shanghai/eip3860_initcode.

Generate fixtures for these test cases with:

fill -v tests/shanghai/eip3860_initcode
diff --git a/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip3860_initcode/test_initcode/index.html b/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip3860_initcode/test_initcode/index.html
index 6e166873b4..525f4ce488 100644
--- a/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip3860_initcode/test_initcode/index.html
+++ b/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip3860_initcode/test_initcode/index.html
@@ -3266,7 +3266,7 @@
 
 
 

Test Initcode

-

Documentation for tests/shanghai/eip3860_initcode/test_initcode.py.

+

Documentation for tests/shanghai/eip3860_initcode/test_initcode.py.

Generate fixtures for these test cases with:

fill -v tests/shanghai/eip3860_initcode/test_initcode.py
diff --git a/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip3860_initcode/test_initcode/index/test_cases/index.html b/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip3860_initcode/test_initcode/index/test_cases/index.html
index 732667bf58..00df55d185 100644
--- a/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip3860_initcode/test_initcode/index/test_cases/index.html
+++ b/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip3860_initcode/test_initcode/index/test_cases/index.html
@@ -3216,7 +3216,7 @@
 

Test Initcode - Test Cases

Test cases generated from tests/shanghai/eip3860_initcode/test_initcode.py

-

Parametrized test cases generated from the test module tests/shanghai/eip3860_initcode/test_initcode.py:

+

Parametrized test cases generated from the test module tests/shanghai/eip3860_initcode/test_initcode.py:

test_contract_creating_tx[fork=Shanghai-max_size_zeros]
 test_contract_creating_tx[fork=Shanghai-max_size_ones]
 test_contract_creating_tx[fork=Shanghai-over_limit_zeros]
diff --git a/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip4895_withdrawals/index.html b/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip4895_withdrawals/index.html
index b76b2e5bd1..9d0314a6c5 100644
--- a/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip4895_withdrawals/index.html
+++ b/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip4895_withdrawals/index.html
@@ -3217,7 +3217,7 @@
 
 
 

EIP-4895 Withdrawals

-

Documentation for tests/shanghai/eip4895_withdrawals.

+

Documentation for tests/shanghai/eip4895_withdrawals.

Generate fixtures for these test cases with:

fill -v tests/shanghai/eip4895_withdrawals
diff --git a/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip4895_withdrawals/test_withdrawals/index.html b/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip4895_withdrawals/test_withdrawals/index.html
index 588b45d0bd..fb993938a4 100644
--- a/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip4895_withdrawals/test_withdrawals/index.html
+++ b/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip4895_withdrawals/test_withdrawals/index.html
@@ -3315,7 +3315,7 @@
 
 
 

Test Withdrawals

-

Documentation for tests/shanghai/eip4895_withdrawals/test_withdrawals.py.

+

Documentation for tests/shanghai/eip4895_withdrawals/test_withdrawals.py.

Generate fixtures for these test cases with:

fill -v tests/shanghai/eip4895_withdrawals/test_withdrawals.py
diff --git a/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip4895_withdrawals/test_withdrawals/index/test_cases/index.html b/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip4895_withdrawals/test_withdrawals/index/test_cases/index.html
index ad0a6e5fa7..6b9e559a5b 100644
--- a/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip4895_withdrawals/test_withdrawals/index/test_cases/index.html
+++ b/v1.0.1b1-refactor-4844-specs/tests/shanghai/eip4895_withdrawals/test_withdrawals/index/test_cases/index.html
@@ -3216,7 +3216,7 @@
 

Test Withdrawals - Test Cases

Test cases generated from tests/shanghai/eip4895_withdrawals/test_withdrawals.py

-

Parametrized test cases generated from the test module tests/shanghai/eip4895_withdrawals/test_withdrawals.py:

+

Parametrized test cases generated from the test module tests/shanghai/eip4895_withdrawals/test_withdrawals.py:

TestUseValueInTx
 TestUseValueInTx
 TestUseValueInTx
diff --git a/v1.0.1b1-refactor-4844-specs/tests/shanghai/index.html b/v1.0.1b1-refactor-4844-specs/tests/shanghai/index.html
index 4fc8f7dab1..ad7217b7c9 100644
--- a/v1.0.1b1-refactor-4844-specs/tests/shanghai/index.html
+++ b/v1.0.1b1-refactor-4844-specs/tests/shanghai/index.html
@@ -3215,7 +3215,7 @@
 
 
 

Shanghai

-

Documentation for tests/shanghai.

+

Documentation for tests/shanghai.

Generate fixtures for these test cases with:

fill -v tests/shanghai