Library / SDK
ipsilon/evmone avatar
ipsilon/evmone

evmone is a standalone EVM that plugs into a client through EVMC

Fast Ethereum Virtual Machine implementation

982 stars341 forksC++Apache-2.0

At a glance

What is it?
evmone is a C++20 implementation of the Ethereum Virtual Machine, written to be imported as an execution module rather than embedded in a client, and it ships two interpreters, a baseline one and an advanced one that dispatches through indirect call threading. The interesting parts for an integrator are the EVMC interface, the precompile exceptions and the fact that a prebuilt shared library can replace geth's own EVM.
Who is it for?
evmone fits an Ethereum client developer who wants to swap the execution engine without forking the client, and the EVMC boundary is what makes that a configuration change rather than a rewrite, and it fits a benchmarking team that wants a reproducible EVM across machines.
Can I use it commercially?
Yes. Apache-2.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 received new commits within the last day.
What is it written in?
Mainly C++, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

An execution module, not a client

evmone is a C++ implementation of the Ethereum Virtual Machine, created by members of the Ipsilon team, previously known as Ewasm. The stated aim is a clean, standalone EVM implementation that can be imported as an execution module by Ethereum Client projects, and the codebase is optimized for fast and efficient execution of EVM smart contracts. The boundary that makes this possible is EVMC, which evmone exposes. That is the design decision to hold on to. A client that speaks EVMC does not care how the EVM is implemented, so the engine becomes a swappable component, and the same library can be pointed at by a client, by a test harness or by a benchmark runner. The technical requirements are also stated plainly: the C++20 standard is required, the intx library provides 256-bit integer precision, and the ethash library provides the Keccak hash implementation needed for the KECCAK256 instruction. The maintainer is Pawel Bylica, and the licence is Apache 2.0.

Baseline and Advanced differ in how they dispatch

The two interpreters are the heart of the project, and the difference is a dispatch strategy rather than a feature set. The baseline interpreter is the default and provides a relatively straightforward but efficient EVM implementation, performing only minimalistic JUMPDEST analysis, which is the static scan that finds the valid jump destinations in the bytecode. The advanced interpreter uses indirect call threading as its dispatch method, where a loaded EVM program becomes a table of pointers to functions implementing the virtual instructions, so the dispatch is a table lookup rather than a switch. That approach is paid for up front. The advanced interpreter precomputes the gas cost and stack requirements of a block of instructions and applies them once per block during execution, and it performs extensive and expensive bytecode analysis before execution starts. So the two modes trade startup cost against steady state speed, and which one wins depends on whether the workload is many short transactions or long running contracts. The repository documents the gas calculation approach in a separate file on efficient gas calculation algorithm for EVM.

Replacing geth's internal EVM

The most concrete use case in the README is running evmone inside geth. Since evmone implements the EVMC API, it can be used as a plugin replacing geth's internal EVM, but the README is careful to note that this requires a modified version of geth, and points at the Ewasm fork of go-ethereum, which publishes binary releases of geth with EVMC support. The workflow is then short. Download evmone from the releases page, and start the downloaded geth with the --vm.evm option pointing at the evmone shared library:

bash
geth --vm.evm=./libevmone.so

The consequence for an integrator is that this is a drop-in replacement at the execution layer only. Everything above the EVM, the networking, the transaction pool, the state management, stays the same, and the client can be pointed at either implementation for comparison. That makes it a natural fit for A/B testing an engine change, and for a client team that wants to evaluate an alternative interpreter without maintaining a fork of the client itself.

Building the module, the tests and the benchmarks

The build instructions are conventional CMake and cover Linux, macOS and Windows. Fetch the source with the submodules, which matters because the intx and ethash dependencies are brought in that way:

bash
git clone --recursive https://github.com/ethereum/evmone
cd evmone

On Linux and macOS the configuration step enables the testing targets:

bash
cmake -S . -B build -DEVMONE_TESTING=ON

and on Windows the generator and architecture are added, for example -G "Visual Studio 16 2019" -A x64. The build itself is:

bash
cmake --build build --parallel

and the result gives you both the unit test binary and the benchmarking tool:

bash
build/bin/evmone-unittests
build/bin/evmone-bench test/evm-benchmarks/benchmarks

The benchmark corpus lives in the test directory, and the tools/ and lib/ directories at the top of the tree hold the shared library and the command line helpers. The CI setup is visible too, with CircleCI and AppVeyor configurations, a codecov configuration, and a Codspeed badge, which indicates that benchmark regressions are tracked as part of continuous integration rather than measured by hand.

The precompiles are where the caveats are

Ethereum precompiled contracts are supported with some exceptions, and the exceptions are the ones to read before you rely on the engine. The ecrecover precompile is implemented directly by evmone and has degraded performance, which matters because signature recovery is on the hot path of many contracts. For expmod, stubs are enabled by default, and they will correctly respond to known inputs, while the full implementation is behind the CMake option EVMONE_PRECOMPILES_GMP=1, which requires the GMP library at both build and execution time. That is a real operational dependency rather than a build detail, since the library has to be present wherever the module runs. The pattern is worth noting generally. evmone is optimised for the common path of the EVM, and the specialised precompiles are the place where the shortcuts are visible, so an integrator with heavy precompile usage should measure rather than assume.

The container is a benchmark environment

Docker images with evmone are published on Docker Hub under the ethereum organisation, and the README is refreshingly blunt about their purpose. Having the evmone shared library inside a Docker container is not very useful on its own, but the image can be used as the base of another image, or you can run benchmarks with it. The command for the second case is:

bash
docker run --entrypoint evmone-bench ethereum/evmone /src/test/benchmarks

The container build itself shows the shape of the artifact. It starts from debian:testing, installs a C++ compiler, cmake and ninja-build, copies the tree into /src, configures with Ninja and EVMONE_TESTING=ON, installs the build, and then drops privileges to a dedicated unprivileged user:

dockerfile
FROM debian:testing as evmone

RUN apt-get update -q && apt-get install -qy --no-install-recommends \
    ca-certificates g++ cmake ninja-build \
 && rm -rf /var/lib/apt/lists/*

ADD . /src
RUN mkdir /build \
 && cmake -S /src -B /build -G Ninja -DEVMONE_TESTING=ON -DHUNTER_ROOT=/build \
 && cmake --build /build --target install \
 && ldconfig \
 && rm /build -rf \
 && adduser --disabled-password --no-create-home --gecos '' evmone
USER evmone

Running the container as a non-root user with no home directory is a small but correct choice for an image that is likely to be run in CI.

Releases are named after Ethereum upgrades

The release history is a good sign of a project that is still moving with the protocol. The listed versions are 0.25.0 with the name Amsterdam, published on 2026-10-14, 0.24.0 named Second dimension on 2026-09-23, and 0.23.0 named Signatures verified on 2026-08-11. The naming convention follows the Ethereum upgrade names, which makes the version history readable to anyone who follows the protocol, and the dates show a release roughly every three to six weeks. The repository is not archived and the last push was on 2026-10-14, the same day as the newest release. The top level of the tree shows how seriously the project takes its own tooling, with a .clang-format and .clang-tidy for the C++ style, a .gdbinit and gdb_pretty_printers.py for debugging, a .bumpversion.cfg for version bumps, a CHANGELOG.md, a Dockerfile, an AUTHORS file and a codealike.json. A .gitmodules file sits next to them, which is the reminder that a recursive clone is required to build at all.

Editorial conclusion

evmone fits an Ethereum client developer who wants to swap the execution engine without forking the client, and the EVMC boundary is what makes that a configuration change rather than a rewrite, and it fits a benchmarking team that wants a reproducible EVM across machines. It does not fit someone who needs every precompile to be fully and quickly implemented, since ecrecover is implemented directly with degraded performance and expmod is a stub unless you build with GMP, and it does not fit a Linux user who expects a package, because the documented installation is a download of the shared library or a build from source. Before you integrate it, read the precompile section, decide between the baseline and the advanced interpreter, and check the release notes for the version you pin, since the series is moving quickly with 0.25.0 published on 2026-10-14 and the last push on the same day.

Frequently asked questions

What is evmone?

It is a C++20 implementation of the Ethereum Virtual Machine, created by members of the Ipsilon team, that exposes the EVMC API so it can be imported as an execution module by Ethereum client projects rather than being embedded in one.

What is the difference between the baseline and advanced interpreters?

The baseline is the default and does only minimalistic JUMPDEST analysis. The advanced one uses indirect call threading, precomputes gas cost and stack requirements per instruction block and performs extensive bytecode analysis before execution, trading startup cost for faster steady state execution.

Can I use evmone with geth?

Yes, as a plugin that replaces geth's internal EVM, but it needs a modified geth with EVMC support, and you start it with geth --vm.evm=./libevmone.so pointing at the downloaded shared library.

Are the Ethereum precompiles fully supported?

Not entirely. ecrecover is implemented directly by evmone with degraded performance, and expmod runs as a stub that responds correctly to known inputs unless you build with EVMONE_PRECOMPILES_GMP=1, which requires the GMP library at build and run time.

How do I build and test evmone?

Clone the repository recursively, configure with cmake -S . -B build -DEVMONE_TESTING=ON, build with cmake --build build --parallel, then run build/bin/evmone-unittests or build/bin/evmone-bench against the benchmark corpus in test/evm-benchmarks.

Official sources

  1. ipsilon/evmone on GitHub
  2. Issues
  3. License: Apache-2.0
  4. README
  5. Releases
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/ipsilon-evmone.svg)](https://hysenlabs.com/projects/ipsilon-evmone)

Was this useful?