Revm
Revm is a highly efficient and stable implementation of the Ethereum Virtual Machine (EVM) written in Rust.
Known for its robustness, it stands as one of the most popular libraries and a critical component of the Ethereum ecosystem. Revm plays a crucial role across various projects, being widely utilized by almost all tooling and block builders. It is integrated into Reth, multiple Layer 2 variants and other clients and serving as a standard for zkVMs.
Revm offers two primary applications: firstly, it functions as an executor where users can set up block info and process mainnet transactions; secondly, it acts as a framework that facilitates the extension and support of different EVM variants such as op-revm.
How to use:
Here is a straightforward example of using the Execution API: It allows us to create an Ethereum Virtual Machine (EVM) and execute transactions. Additionally, it can be utilized to generate traces with the inspector or more complex example of foundry cheatcodes.
let mut evm = Context::mainnet().with_block(block).build_mainnet();
let out = evm.transact(tx);
// or you can use powerful inspection tool to trace it
let mut evm = evm.with_inspector(tracer);
let out = evm.inspect_tx(tx);
The Evm Framework API is somewhat complex to use, but this document provides a detailed explanation. It enables users to extend logic, incorporate various context types, and offers built-in support for inspection. For a practical example, you can refer to the op-revm crate.
Users:
As previously noted, there are several groups of projects that utilize this technology:
- Major block builders.
- Clients: Reth, Helios, Trin,..
- Tooling: Foundry, Hardhat,..
- L2s: Optimism, Coinbase, Scroll,..
- zkVM: Risc0, Succinct,..
The full list of projects that use Revm is available in the awesome-revm section of the book.
How to, dev section
The book and Architecture and API
page is the best starting resource.
Some quick links can be found here. Some point to code documentation or the book. code docs are there to explain usage of a particular part of the code where the book is to get more of an overview of the architecture or how components/projects fit together.
- How to build and use revm can be found here. book
- Architecture overview can be seen here. book
- Structure of the project (list of crates and their versions) can be seen here. book
- How to use Revm Framework can be found in MyEvm example. book
- Release procedure and changelogs explanation. book
- How to use revme (Revm binary with few commands) can be found here. code
- How to run Ethereum test can be found here: book
- If there is more need for explanations please open a PR request.
Community:
For questions please open a github issue or join the public telegram group: https://t.me/+Ig4WDWOzikA3MzA0
Licence
Revm is licensed under MIT Licence.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in these crates by you, shall be licensed as above, without any additional terms or conditions.
If gmp
feature flag is used, GPL code gets compiled, if enabled please make sure to follow this license.
Security
For any security questions or findings, please reach out to me directly via email at dragan0rakita@gmail.com or contact me on Keybase under the username @draganrakita.
Awesome Revm
A curated list of excellent Revm-related resources. Feel free to contribute to this list!
Repositories
- Main Repo: Revm Repository - The central code repository for Revm.
- Book: - Comprehensive user documentation for Revm.
Audits
API Extensions:
- alloy-evm is an abstraction layer on top of revm providing common implementations of EVMs
- Trevm is a typestate API wrapper for revm
Clients
- Reth: A modular, contributor-friendly, and ultra-fast implementation of the Ethereum protocol.
- Helios is a trustless, efficient, and portable multichain light client written in Rust.
- Trin is a Rust implementation of a Portal Network client.
EVM Variants
- Optimism is a ethereum L2 network.
- Base is an Ethereum Layer 2 (L2) chain that offers a safe, low-cost, developer-friendly way to build on-chain
- Scroll is its own Layer 2 network built on Ethereum (more specifically, a “zero-knowledge rollup”).
Tools
- Foundry: A portable and modular toolkit for rapid Ethereum application development in Rust.
- Hardhat: A comprehensive development environment for compiling, deploying, testing, and debugging Ethereum software.
- Arbiter: smart-contract simulation.
Frameworks and Libraries
- revm-inspectors: Hooks for EVM execution.
- eip3074-instructions: Implements custom instructions for AUTH and AUTHCALL operations.
- Revmc: JIT and AOT compiler for the Ethereum Virtual Machine, leveraging Revm.
- Risc0-ethereum is a zero-knowledge verifiable general computing platform, with Ethereum integration
- Kona is a suite of portable implementations of the OP Stack rollup state transition, namely the derivation pipeline and the block execution logic.
- mevlog-rs: Rust-based CLI tool for querying and monitoring Ethereum blockchain transactions, with flexible filtering and EVM tracing capabilities. It's a tool for MEV searchers who prefer command-line workflows over web-based explorers.
Tutorials
- MyEvm: Custom EVM Implementation Example
- Revm is All You Need:: Guide on building simulated blockchain environments.
- Uniswap Swap Example: Demonstrates a USDC swap on Uniswap V2.evm is available in the awesome-revm section o
- revm-by-example: Practical examples using the Rust Ethereum Virtual Machine.
- How to Discover long-tail MEV Strategies using Revm
Architecture and API
REVM is a flexible implementation of the Ethereum Virtual Machine (EVM). It follows the rules of the Ethereum mainnet and stays up to date with changes through hardforks as defined in the official Ethereum execution specs.
You can use REVM in two main ways:
- Run regular Ethereum transactions using an Execution API
- Create your own custom version of the EVM (for Layer 2 solutions or other chains) using the EVM framework
To see usage examples you can check the examples folder. Other than documentation, examples are the main resource to see and learn about Revm.
The main revm
library combines all crates into one package and reexports them, standalone libraries are useful if there is a need to import functionality with smaller scope. You can see an overview of all revm crates in the crates folder.
REVM works in no_std
environments which means it can be used in zero-knowledge virtual machines (zkVMs) and it is the standard library in that use case. It also has very few external dependencies.
Execution API
The Execution API provides the primary interface for running Ethereum transactions and interacting with the EVM. Whether you're building a blockchain client, testing framework, or analysis tool, this API offers multiple execution modes to suit your needs.
The API is designed around four key execution patterns:
- Basic execution: Run transactions and get results
- Execution with commit: Run transactions and automatically persist state changes
- Execution with inspection: Run transactions with detailed tracing and observation
Evm
the main structure for executing mainnet ethereum transaction is built with a Context
and a builder, code for it looks like this:
let mut evm = Context::mainnet().with_block(block).build_mainnet();
let out = evm.transact(tx);
Evm
struct contains:
Context
- Environment and evm state.Instructions
- EVM opcode implementationsPrecompiles
- Built-in contract implementationsInspector
- Used for tracing.
And Context
contains data used in execution:
- Environment data, the data that is known before execution starts are
Transaction
,Block
,Cfg
. Journal
is the place where internal state is stored. Internal state is returned after execution ends.- And
Database
is an interface that allows fetching external data that is needed at runtime. That data are account, storage and bytecode. When loaded they are stored inJournal
- And
REVM provides four ways to execute transactions through traits (API):
transact(tx)
andreplay()
are function ofExecuteEvm
trait that allow execution transactions. They return the status of execution with reason, changed state and in case of failed execution an error.transact_commit(tx)
andreplay_commit()
are part ofExecuteCommitEvm
that internally commits the state diff to the database and returns status of execution. Database is required to supportDatabaseCommit
trait.inspect()
,inspect_replay(tx)
and a few others are part ofInspectEvm
trait that allow execution with inspection. This is how tracers are called.inspect_commit()
,inspect_replay_commit(tx)
are part of theInspectCommitEvm
trait that extendsInspectEvm
to allow committing state diff after tracing.
For inspection API to be enabled, Evm
needs to be created with inspector.
let mut evm = Context::mainnet().with_block(block).build_mainnet().with_inspector(inspector);
let _ = evm.inspect_tx(tx);
Inspector - EVM Execution Tracing
The Inspector
trait is REVM's powerful mechanism for observing EVM execution. It provides hooks into every aspect of transaction execution, enabling sophisticated debugging, tracing and custom tooling.
Key capabilities include:
- Step-by-step execution tracing: Hook into every opcode before and after execution
- State monitoring: Track stack, memory, and storage changes in real-time
- Call and creation tracing: Observe contract interactions and deployments
- Event capture: Record logs, self-destructs, and other EVM events
- Execution override: Optionally modify execution flow and outcomes
The Inspector is ideal for building debuggers, gas analyzers, security tools, testing frameworks, and any application that needs deep visibility into EVM execution. For detailed usage examples and advanced features, see the Inspector documentation.
EVM Framework
To learn how to build your own custom EVM:
- Check out the example-my-evm guide
- Look at op-revm to see how Optimism uses REVM
Each trait needed to build custom EVM has detailed documentation explaining how it works and is worth reading.
In summary, REVM is built around several key traits that enable customizable EVM functionality. The core traits include:
EvmTr
: The core EVM trait that provides access toContext
,Instruction
,Precompiles
:ContextTr
: Accessed through EvmTr, defines the execution environment including Tx/Block/Journal/Db.Handler
: Implements the core execution logic, taking an EvmTr implementation. The default implementation follows Ethereum consensus.
And traits that provide support for inspection and tracing:
InspectorEvmTr
: Extends EvmTr to enable inspection mode execution with an associatedInspector
typeInspectorHandler
: Extends Handler with inspection-enabled execution paths that makeInspector
callbacksInspector
: User-implementable trait for EVM inspection/tracing
Inspector - EVM Execution Tracing
The Inspector trait is REVM's powerful mechanism for observing and tracing EVM execution. It provides hooks into every aspect of transaction execution, making it ideal for building debuggers, analyzers, and custom tooling.
What is the Inspector?
The Inspector
trait defines callbacks that are invoked during EVM execution. It allows you to:
- Step through execution: Hook into every opcode before and after execution
- Monitor state changes: Track stack, memory, and storage modifications
- Trace calls: Observe contract calls, creations, and their outcomes
- Capture events: Record logs, self-destructs, and other EVM events
- Override behavior: Optionally modify execution flow and results
Core Inspector Methods
pub trait Inspector<CTX, INTR: InterpreterTypes> {
// Opcode-level tracing
fn step(&mut self, interp: &mut Interpreter<INTR>, context: &mut CTX) {}
fn step_end(&mut self, interp: &mut Interpreter<INTR>, context: &mut CTX) {}
// Call and creation tracing
fn call(&mut self, context: &mut CTX, inputs: &mut CallInputs) -> Option<CallOutcome> { None }
fn call_end(&mut self, context: &mut CTX, inputs: &CallInputs, outcome: &mut CallOutcome) {}
fn create(&mut self, context: &mut CTX, inputs: &mut CreateInputs) -> Option<CreateOutcome> { None }
fn create_end(&mut self, context: &mut CTX, inputs: &CreateInputs, outcome: &mut CreateOutcome) {}
// Event tracing
fn log(&mut self, interp: &mut Interpreter<INTR>, context: &mut CTX, log: Log) {}
fn selfdestruct(&mut self, contract: Address, target: Address, value: U256) {}
}
Basic Usage
1. Create an Inspector
#[derive(Default)]
struct MyInspector {
gas_used: u64,
call_count: usize,
}
impl<CTX, INTR: InterpreterTypes> Inspector<CTX, INTR> for MyInspector {
fn step(&mut self, interp: &mut Interpreter<INTR>, _context: &mut CTX) {
self.gas_used += interp.gas.spent();
}
fn call(&mut self, _context: &mut CTX, _inputs: &mut CallInputs) -> Option<CallOutcome> {
self.call_count += 1;
None // Don't override the call
}
}
2. Use with EVM
let inspector = MyInspector::default();
let mut evm = Context::mainnet()
.with_db(db)
.build_mainnet_with_inspector(inspector);
// Execute with inspection
let result = evm.inspect_one_tx(tx)?;
println!("Gas used: {}", evm.inspector.gas_used);
println!("Calls made: {}", evm.inspector.call_count);
Advanced Features
State Inspection
Access complete interpreter state during execution:
fn step(&mut self, interp: &mut Interpreter<INTR>, _context: &mut CTX) {
let pc = interp.bytecode.pc();
let opcode = interp.bytecode.opcode();
let stack_len = interp.stack.len();
let memory_size = interp.memory.size();
println!("PC: {}, Opcode: 0x{:02x}, Stack: {}, Memory: {}",
pc, opcode, stack_len, memory_size);
}
Call Override
Modify execution by returning custom outcomes:
fn call(&mut self, _context: &mut CTX, inputs: &mut CallInputs) -> Option<CallOutcome> {
if inputs.target_address == SPECIAL_ADDRESS {
// Override this call with custom logic
return Some(CallOutcome::new(
InterpreterResult::new(InstructionResult::Return, Bytes::from("custom")),
0..0
));
}
None // Let normal execution continue
}
Event Logging
Capture and process EVM events:
fn log(&mut self, _interp: &mut Interpreter<INTR>, _ctx: &mut CTX, log: Log) {
println!("LOG emitted from: {:?}", log.address);
println!("Topics: {:?}", log.topics());
println!("Data: {}", hex::encode(log.data.data));
}
Built-in Inspectors
REVM provides several ready-to-use inspectors:
GasInspector
: Tracks gas consumption throughout executionTracerEip3155
: Generates EIP-3155 compatible execution tracesNoOpInspector
: Default no-operation inspector for when inspection is disabled
Performance Considerations
- Inspector callbacks have minimal overhead when not implemented (empty default methods)
- Use inspection judiciously in production - detailed tracing can impact performance
- Consider batching inspector data collection for high-throughput scenarios
Common Use Cases
- Debuggers: Step-by-step execution analysis
- Gas analyzers: Detailed gas consumption tracking
- Security tools: Detecting suspicious patterns or calls
- Development tools: Contract interaction tracing
- Testing frameworks: Execution verification and state checking
The Inspector trait makes REVM very observable EVM implementations available, enabling sophisticated tooling and analysis capabilities.
External State Transitions (EIP-4788 & EIP-2935)
Some Ethereum Improvement Proposals (EIPs) require state transitions that are not triggered by regular user transactions, but are instead performed by the client using special system calls (such as transact_system_call
). These transitions are part of the EVM state changes, but are initiated by the client at specific block boundaries (pre- or post-block hooks), as required by the EIP.
What are external state transitions?
External state transitions refer to updates to the Ethereum state that are not performed by regular user transactions, but are instead performed by the client using system calls at block boundaries. These are typically required for EIPs that introduce new system contracts or require special state updates at block boundaries.
EIP-4788: Beacon block root in the EVM
EIP-4788 requires that the root of each beacon chain block is committed to the execution layer and made available in the EVM via a special contract. This is achieved by the client calling a system contract at a fixed address (0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02
) with the beacon root as input, at the start of each block. The contract maintains a ring buffer of recent roots.
- The system call is performed by the client, not by EVM transaction execution.
- If the contract does not exist, the call fails silently.
- See EIP-4788 for full details.
- Example implementation in Reth: reth#4457
EIP-2935: Add blockHash and blockNumber to the EVM
EIP-2935 introduces a system contract that stores recent block hashes, allowing contracts to query them. The client is responsible for updating this contract at each block, by calling a system contract at a fixed address (0x0000F90827F1C53a10cb7A02335B175320002935
) with the new block hash.
- The system call is performed by the client, not by EVM transaction execution.
- See EIP-2935 for full details.
- Example implementation in Reth: reth#7818
How does this affect REVM users?
- To perform these block state transitions, the client or test harness should use the system call mechanism (
transact_system_call
) provided by REVM. - REVM itself does not automatically perform these transitions; it expects the client to initiate them at the appropriate block boundaries, as specified by the EIPs.
- If you are building a full Ethereum client or a test harness, you are responsible for performing these system calls at the appropriate block boundaries, as specified in the EIPs.
- If you are only using REVM for transaction execution, you may need to ensure that the state of these system contracts is kept up to date externally.
References
- EIP-4788: Beacon block root in the EVM
- EIP-2935: Add blockHash and blockNumber to the EVM
- reth#4457: EIP-4788 implementation
- reth#7818: EIP-2935 implementation
Building from source
It requires running
git clone https://github.com/bluealloy/revm.git
cd revm
cargo build --release
Note: This project tends to use the newest rust version, so if you're encountering a build error try running rustup update first.
Note: clang
is required for building revm with c-kzg
or secp256k1
feature flags as they depend on C
libraries. If you don't have it installed, you can install it with apt install clang
.
Revme
Is a binary that allows running statetest and eof validation.
$: revme --help
Usage: revme <COMMAND>
Commands:
statetest Execute Ethereum state tests
evm Run arbitrary EVM bytecode
bytecode Print the structure of an EVM bytecode
bench Run bench from specified list
help Print this message or the help of the given subcommand(s)
Options:
-h, --help Print help
Running eth tests
Eth tests are a suite of tests from the Ethereum Foundation that are used to test EVM implementations.
Part of these tests are included in the revm repository in the tests
folder.
Test suites for the latest hardforks can be found in EEST releases https://github.com/ethereum/execution-spec-tests/releases, and there are additional tests that cover older hardforks in https://github.com/ethereum/legacytests
Revm can run statetest type of tests with revme
using the following command:
cargo run --release -p revme -- statetest folder_path
For running EEST tests, we can use the ./scripts/run-tests.sh.
For legacy tests, we need to first to download the repo git clone https://github.com/ethereum/legacytests
and then run it with cargo run --release -p revme -- statetest legacytests/Cancun/GeneralStateTests
All statetest that can be run by revme can be found in the GeneralStateTests
folder.
Release procedure
This document describes the procedure for releasing a new version of the revm
project. The repository is hosted on github and published to crates.io. Every published crate is part of one tag (currently tag v55) that contains all crates versions. The versions depending on the change can be major, minor, or patch; we don't have one version for all packages.
Link of tag to the particular version of the crate can be found in CHANGELOG file.
Contact
The git repository can be found at https://github.com/bluealloy/revm/
For questions please open a github issue or join the public telegram group: https://t.me/+Ig4WDWOzikA3MzA0
Licence
Licensed under MIT Licence.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in these crates by you, shall be licensed as above, without any additional terms or conditions.
Security
If there is a security question or finding please contact me directly via email at dragan0rakita@gmail.com
or on keybase @draganrakita