execution-specs: an Ethereum execution spec you can run
Specification for the Execution Layer. Tracking network upgrades.
At a glance
- What is it?
- The Ethereum Execution Layer Specifications are an executable Python reference implementation of the execution layer together with the test cases that verify it, and the fixtures they generate are what production clients such as geth and reth are validated against. It is maintained by the STEEL team at the Ethereum Foundation and licensed CC0.
- Who is it for?
- Adopt the execution specs if you are writing an execution client, a fork of one, or a tool that has to agree with mainnet behaviour, and start by running the fixtures for the fork you care about against your implementation.
- Can I use it commercially?
- Yes. CC0-1.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 7, 2026, and from our analysis. They are not legal advice.
Star history
- ethereum/execution-specs1,209 ★ · +5
| Repository | 2026-10-20 | 2026-11-07 |
|---|---|---|
| ethereum/execution-specs | 1.2k | 1.2k |
5 Stars in the last 18 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
A specification that runs, and tests that check it
EELS is described as an executable Python reference implementation of Ethereum's execution layer, along with the test cases that verify it. The value it provides is a shared, runnable description of consensus-critical behaviour, and the accompanying tests generate fixtures that can be used to validate execution client implementations.
That is the whole idea in three steps. Instead of a prose specification that two implementations read differently, there is one implementation in a language designed to be read. Instead of humans writing test vectors by hand, the tests execute against that implementation and produce fixtures. And instead of every client team writing its own conformance suite, they can run the same fixtures.
The production clients that implement the spec are named in the README: besu, erigon, ethrex, geth, nethermind and reth. Six independent implementations agreeing on the same generated fixtures is the point of the exercise, and it is why the project is described as tracking network upgrades rather than as a client.
The Python package is published as ethereum-execution, and the README states that it is provided as a Python package for tooling and testing. The licence is Creative Commons Zero v1.0 Universal, which is a public domain dedication, the least restrictive option available and an unusual and deliberate choice for a consensus-critical artefact.
Setting up with uv and just
The toolchain is specific. The project uses uv to manage the Python environment and dependencies, and just as a task runner for the common commands, which are linting, building the docs and generating fixtures. The README says a Unix-like shell is required.
The setup from a clean machine is a single block:
git clone https://github.com/ethereum/execution-specs
cd execution-specs
curl -LsSf https://astral.sh/uv/install.sh | sh
uv python install 3.12
uv python pin 3.12
uv sync
uv tool install --exclude-newer "10 days" rust-just
just shell-completionsTwo details in there are worth pausing on. The Python version is pinned rather than merely required, with uv python pin 3.12, and the README explains why 3.12: Python 3.11 through 3.14 are supported and 3.12 tends to be the smoothest for local setup because pre-built wheels are available across the dependency set. On a platform without wheels for your version, the setup is a compiler away from working.
The second is the just installation, which pins the tool by age with --exclude-newer "10 days". That is a supply chain precaution rather than a version pin, ensuring the tool you install is recent but not brand new. The last command generates shell completions, which is the sort of small touch that suggests the task runner is meant to be used interactively rather than only in CI.
The reference EVM CLI: t8n, b11r and a state test runner
The tool most people want from this repository is ethereum-spec-evm, and the README is careful about where it comes from. It is a t8n transition tool, a b11r block builder and a state-test runner that execute the spec directly, and it is provided by the ethereum-execution-testing workspace package rather than by ethereum-execution itself.
That distinction matters for anyone integrating it. Inside a checkout the command is available as uv run ethereum-spec-evm, but for a standalone installation, which the README names as relevant to client CI and fuzzing setups, you go to the testing package's own README. A workspace member that behaves differently depending on how you got it is a common source of confusion in CI, and the repository layout shows why: the top level holds src/ for the specification, packages/ for the workspace packages, and tests/ for the consensus tests, and the tooling package is one of the entries under packages/.
The three verbs in that one binary cover the interesting cases. A transition tool takes a pre-state and a set of transactions and produces a post-state, a block builder assembles blocks, and the state-test runner executes the test cases. For a client team, that means the same executable can generate the expected results and then be compared against the client's own output.
Versioning that encodes the fork in the version number
The versioning scheme is documented separately in docs/specs/spec_releases.md, and the README summarises the two rules that matter. The scheme is PEP 440 compatible, the hardfork is encoded in the minor version, and rcN marks devnets.
Encoding the fork in the minor version is a good decision, because it means the dependency requirement in a downstream project states which network behaviour you are targeting. A requirement like a 0.x release where the minor carries the fork name tells a reader which upgrade semantics apply, and rcN tells them the fork is not final.
The release tags visible in the repository follow that pattern, and they are not just spec releases. There are tags such as tests-heze-devnet at version 2.0.0 dated 2026-10-15, tests-bogota-devnet at 1.1.0 from 2026-10-13 and tests-frames-devnet at 1.0.0 from 2026-10-09. Each is a test suite for a named devnet, versioned independently of the specification itself, which tells you the test fixtures are treated as a separately consumable artefact.
The default branch is forks/bogota, which is worth noticing before you clone anything. A default branch that carries a fork name means the checked-out state is a network upgrade in progress rather than a released state, and the documentation section acknowledges this by describing the docs link as being for the default branch or fork.
The fork packages and the tooling around them
The package list in pyproject.toml is the clearest map of the specification's structure. Each fork gets its own package, and the naming is a chronological record: ethereum.forks.frontier, ethereum.forks.homestead and onward, each with a utils subpackage, a vm subpackage, an instructions subpackage and, for the earliest forks, a precompiled_contracts subpackage.
That layout is the design in miniature. The virtual machine instructions live per fork, so a fork that changes the semantics of a single opcode has an obvious place to change it, and the utils and precompiled contracts sit alongside because those are also fork-dependent. On top of the fork packages there is ethereum.crypto, ethereum.utils and ethereum_optimized, plus a separate ethereum_spec_tools tree with subpackages for loaders, lint, lint rules and a new_fork module with a codemod subpackage.
That new_fork tooling is the most interesting piece for a contributor. A codemod suggests that adding a fork is partly mechanical, and the README points at docs/specs/writing_specs.md for the style rules and the ethereum_spec_tools utilities that apply to changes under src/ethereum/.
The dependencies are correspondingly specialised: pycryptodome, spec256k1 for the curve operations, py-ecc, ethereum-types, ethereum-rlp, cryptography, libcst for the codemods, and platformdirs. The presence of PyPy in the classifiers alongside CPython, and a vulture_whitelist.py and whitelist.txt at the root for dead code detection, are the marks of a codebase with a large surface and an active linting regime.
Vulnerabilities go to the bounty, not to a public issue
The security section of the README is the most unusual part of the document, and it deserves to be read as a process requirement rather than as boilerplate. It carries a caution that care is required when filing issues or pull requests for functionality that is live on Ethereum mainnet, and it asks that vulnerabilities and bounty eligibility be verified through the bug bounty programme, with the details in SECURITY.md.
Two instructions follow: do not create a pull request with a vulnerability visible, and do not file a public ticket mentioning the vulnerability.
This is the correct policy for a repository that is the reference for consensus-critical behaviour. A public issue on the reference implementation is an early warning to everyone who implements it. The SECURITY.md file at the root is the place where the process is defined, and the bounty link is the route for a researcher.
The repository is also careful about where discussion happens. Protocol changes are discussed on Ethereum Magicians, in pull requests on the EIPs repository, on the Ethereum R and D Discord in the Execution R and D category, with the el-testing channel for testing questions, and in the AllCoreDevs calls. Forkcast is named for tracking upgrade status, with EIP inclusion, client implementation progress and call summaries. The separation between the prose proposals, the implementation and the status tracker is a deliberate structure, and it maps onto the same separation that the EIP and execution-specs repositories have.
Where the execution specs are the wrong tool
The first wrong-tool case is running it in production. The implementation is a reference, written so that a reader can follow the logic, and the goal stated in the README is a shared, runnable description rather than a fast one. A production client needs a different set of trade-offs entirely, which is why the six named clients are separate projects with their own optimisations.
The second is looking for the prose. The README points at ethereum/EIPs as the prose EIP documents that EELS implements, and the EIP text is where the rationale, the trade-offs and the specification of behaviour live. The Python code shows what the behaviour is, not why it is that way, and a reader trying to understand a design decision will find it in the EIP and not here.
The third is a task that only needs the API surface. The JSON-RPC API specification lives in a separate repository, ethereum/execution-apis, and the consensus layer has its own counterpart in ethereum/consensus-specs. If you want to know what an execution client exposes over JSON-RPC, this repository is the wrong place to look, and a developer who starts here will end up in the wrong repository before finding out.
A practical caution for anyone who clones it: the default branch is a fork branch, so the state you get is mid-upgrade, and the documentation is published per branch for that reason.
Editorial conclusion
Adopt the execution specs if you are writing an execution client, a fork of one, or a tool that has to agree with mainnet behaviour, and start by running the fixtures for the fork you care about against your implementation. Do not adopt it as a production client, since it is a reference implementation written for clarity rather than for throughput, and do not treat it as a substitute for the EIP documents, since the EIPs are the prose source and this repository implements them. Before you contribute, read the writing specs and writing tests guides, check the responsible disclosure policy, because the repository asks that vulnerabilities on live mainnet functionality go through the bug bounty programme rather than a public issue, and note that the default branch is a fork branch, forks/bogota, so an ordinary clone lands on a network upgrade in progress.
Frequently asked questions
What is the Ethereum Execution Layer Specifications repository?
EELS is an executable Python reference implementation of Ethereum's execution layer, along with the test cases that verify it. It provides a shared, runnable description of consensus-critical behaviour, and the tests generate fixtures that can validate execution client implementations.
How do I set up the execution specs locally?
Clone the repository, install uv with the install script, install and pin Python 3.12 with uv python install and uv python pin, run uv sync, then install just with uv tool install --exclude-newer "10 days" rust-just. The project uses uv for the environment and just for tasks such as linting, building docs and generating fixtures.
What does ethereum-spec-evm do?
It is a t8n transition tool, a b11r block builder and a state-test runner that execute the spec directly. It is provided by the ethereum-execution-testing workspace package rather than by ethereum-execution, and inside a checkout it runs as uv run ethereum-spec-evm.
How is the version of the execution spec structured?
The scheme is PEP 440 compatible, with the hardfork encoded in the minor version and rcN marking devnets. Test suites for named devnets are versioned separately, with tags such as tests-bogota-devnet at 1.1.0 and tests-heze-devnet at 2.0.0.
How do I report a vulnerability in the execution specs?
The README asks that vulnerabilities and bounty eligibility be handled through the Ethereum bug bounty programme, with the details in SECURITY.md, and that no public ticket mentioning the vulnerability is filed and no pull request with a visible vulnerability is created.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/ethereum-execution-specs)Star history chart for your README
[](https://hysenlabs.com/projects/ethereum-execution-specs)Was this useful?