File: README.md
reth
Modular, contributor-friendly and blazing-fast implementation of the Ethereum protocol
Install
| User Docs
| Developer Docs
| Crate Docs
What is Reth?
Reth (short for Rust Ethereum, pronunciation) is a production-ready Ethereum execution layer client focused on modularity, performance, and user-friendliness. Reth is compatible with all Ethereum Consensus Layer (CL) implementations that support the Engine API. It is built and driven forward by Paradigm, and is licensed under the Apache and MIT licenses.
Note: OP-Reth has moved to ethereum-optimism/optimism. Git history has been preserved.
Goals
Modularity: Every component is built to be used as a library: well-tested, documented and benchmarked. Import crates, mix and match, and innovate on top of them. Learn more about the project's components here.
Performance: Built with Rust, Alloy, revm, and Foundry โ battle-tested and optimized for speed. Check the ethPandaOps Lab Dashboard for a third-party comparison against other Ethereum clients.
Here's what that looks like in practice on Ethereum Mainnet:Free for anyone to use any way they want: Apache/MIT licensed, no business license restrictions.
Client Diversity: More client implementations make Ethereum more antifragile.
Support as many EVM chains as possible: Reth can sync Ethereum and other EVM chains. If you're building one, reach out.
Configurability: Profiles for different use cases โ from high-performance RPC operators to hobbyists on consumer hardware.
Status
Reth is production ready, and suitable for usage in mission-critical environments such as staking or high-uptime services. We also actively recommend professional node operators to switch to Reth in production for performance and cost reasons in use cases where high performance with great margins is required such as RPC, MEV, Indexing, Simulations, and P2P activities.
- We released Reth 2.0 in April 2026. See the release notes and blog post.
- We released 1.0 "production-ready" stable Reth in June 2024.
- Reth completed an audit with Sigma Prime, the developers of Lighthouse, the Rust Consensus Layer implementation. Find it here.
- Revm (the EVM used in Reth) underwent an audit with Guido Vranken (#1 Ethereum Bug Bounty).
- We released multiple iterative beta versions, up to beta.9 on Monday June 3, 2024, the last beta release.
- We released beta on Monday March 4, 2024, our first breaking change to the database model, providing faster query speed, smaller database footprint, and allowing "history" to be mounted on separate drives.
- We shipped iterative improvements until the last alpha release on February 28, 2024, 0.1.0-alpha.21.
- We initially announced 0.1.0-alpha.1 on June 20, 2023.
Storage compatibility
Storage V2 is the default for new nodes in Reth 2.0. Existing V1 nodes continue to work, but V1 support will be removed in a future release โ all users are encouraged to migrate. V2 snapshots are available at snapshots.reth.rs.
For Users
See the Reth documentation for instructions on how to install and run Reth.
For Developers
Using reth as a library
You can use individual crates of reth in your project.
The crate docs can be found here.
For a general overview of the crates, see Project Layout.
Contributing
If you want to contribute, or follow along with contributor discussion, you can use our main telegram to chat with us about the development of Reth!
- Our contributor guidelines can be found in
CONTRIBUTING.md. - See our contributor docs for more information on the project. A good starting point is Project Layout.
Building and testing
The Minimum Supported Rust Version (MSRV) of this project is 1.95.
See the docs for detailed instructions on how to build from source.
To fully test Reth, you will need to have Geth installed, but it is possible to run a subset of tests without Geth.
First, clone the repository:
git clone https://github.com/paradigmxyz/reth
cd rethNext, run the tests:
cargo nextest run --workspace
# Run the Ethereum Foundation tests
make ef-testsWe highly recommend using cargo nextest to speed up testing.
Using cargo test to run tests may work fine, but this is not tested and does not support more advanced features like retries for spurious failures.
Note
Some tests use random number generators to generate test data. If you want to use a deterministic seed, you can set the
SEEDenvironment variable.
Getting Help
If you have any questions, first see if the answer to your question can be found in the docs.
If the answer is not there:
- Join the Telegram to get help, or
- Open a discussion with your question, or
- Open an issue with the bug
Security
See SECURITY.md.
Acknowledgements
Reth is a new implementation of the Ethereum protocol. In the process of developing the node we investigated the design decisions other nodes have made to understand what is done well, what is not, and where we can improve the status quo.
None of this would have been possible without them, so big shoutout to the teams below:
- Geth: We would like to express our heartfelt gratitude to the go-ethereum team for their outstanding contributions to Ethereum over the years. Their tireless efforts and dedication have helped to shape the Ethereum ecosystem and make it the vibrant and innovative community it is today. Thank you for your hard work and commitment to the project.
- Erigon (fka Turbo-Geth): Erigon pioneered the "Staged Sync" architecture that Reth is using, as well as introduced MDBX as the database of choice. We thank Erigon for pushing the state of the art research on the performance limits of Ethereum nodes.
- Akula: Reth uses forks of the Apache versions of Akula's MDBX Bindings, FastRLP and ECIES. Given that these packages were already released under the Apache License, and they implement standardized solutions, we decided not to reimplement them to iterate faster. We thank the Akula team for their contributions to the Rust Ethereum ecosystem and for publishing these packages.
- GMP: Reth uses the GNU Multiple Precision Arithmetic Library through the
gmp-mpfr-syscrate when built with thegmpfeature. GMP is distributed under LGPL-3.0-or-later or GPL-2.0-or-later, and the corresponding license texts are included in theLICENSESdirectory.
Warning
The NippyJar and Compact encoding formats and their implementations are designed for storing and retrieving data internally. They are not hardened to safely read potentially malicious data.
File: bin/reth-bb/README.md
reth-bb
A modified reth node for benchmarking big block execution โ payloads that merge transactions from multiple consecutive blocks into a single block to simulate high-gas workloads.
Not for production use. reth-bb disables some consensus-related validations to allow artificially large blocks. It is intended solely for performance benchmarking.
How it works
reth-bb extends the standard Ethereum node with:
Multi-segment execution โ a custom
reth_newPayloadhandler that accepts optionalBigBlockDataalongside the payload. When present, the block is executed in multiple segments, each with its own EVM environment (matching the original blocks that were merged).Relaxed consensus โ the gas-limit bound-divisor check and blob gas validation are skipped, since merged blocks exceed single-block limits.
Quick start
The full workflow has five steps: build reth-bb, install txgen tools, extract big-block payloads, start reth-bb, and replay the payloads.
Prerequisites
- A synced reth datadir for the target chain (e.g. hoodi)
- Rust toolchain
- An archive RPC endpoint that supports
debug_getRawBlock
1. Build reth-bb
cargo build --profile profiling -p reth-bb2. Install txgen tools
Install txgen-ethereum for big-block extraction and bench for Engine API replay from tempoxyz/txgen:
cargo install --git https://github.com/tempoxyz/txgen txgen-ethereum --locked
cargo install --git https://github.com/tempoxyz/txgen bench-cli --locked3. Extract big-block payloads
Merge source blocks into synthetic big-block payloads, starting at the block following the one the node is currently synced to (i.e. the next block the node would process):
txgen-ethereum extract-big-blocks \
--rpc https://rpc.hoodi.ethpandaops.io \
--from 910020 \
--count 5 \
--target-gas 2G \
--output /tmp/big-blocks.ndjsonThis produces an NDJSON file containing one reth-bb-compatible big-block payload per line. --target-gas accepts bare units or K, M, G suffixes.
4. Start reth-bb
reth-bb node \
--datadir /data/reth/hoodi \
--chain hoodi \
--http --http.api debug,eth \
--authrpc.jwtsecret /tmp/jwt.hex \
-d5. Replay payloads
bench send-blocks \
--engine http://localhost:8551 \
--jwt-secret /tmp/jwt.hex \
--input /tmp/big-blocks.ndjson \
--wait-for-persistence every:2 \
--report json:/tmp/reth-bb-report.jsonbench send-blocks submits each payload through reth's custom reth_newPayload and reth_forkchoiceUpdated Engine API methods.
File: crates/storage/rpc-provider/README.md
RPC Blockchain Provider for Reth
This crate provides an RPC-based implementation of reth's BlockchainProvider which provides access to local blockchain data, this crate offers the same functionality but for remote blockchain access via RPC.
Originally created by cakevm.
Features
- Provides the same interface as
BlockchainProviderbut for remote nodes - Implements
StateProviderFactoryfor remote RPC state access - Supports Ethereum networks
- Useful for testing without requiring a full database
- Can be used with reth ExEx (Execution Extensions) for testing
Usage
use alloy_provider::ProviderBuilder;
use reth_storage_rpc_provider::RpcBlockchainProvider;
// Initialize provider
let provider = ProviderBuilder::new()
.builtin("https://eth.merkle.io")
.await
.unwrap();
// Create RPC blockchain provider with NodeTypes
let rpc_provider = RpcBlockchainProvider::new(provider);
// Get state at specific block - same interface as BlockchainProvider
let state = rpc_provider.state_by_block_id(BlockId::number(16148323)).unwrap();Configuration
The provider can be configured with custom settings:
use reth_storage_rpc_provider::{RpcBlockchainProvider, RpcBlockchainProviderConfig};
let config = RpcBlockchainProviderConfig {
compute_state_root: true, // Enable state root computation
reth_rpc_support: true, // Use Reth-specific RPC methods (default: true)
};
let rpc_provider = RpcBlockchainProvider::new_with_config(provider, config);Configuration Options
compute_state_root: When enabled, computes state root and trie updates (requires Reth-specific RPC methods)reth_rpc_support: When enabled (default), uses Reth-specific RPC methods for better performance:eth_getAccountInfo: Fetches account balance, nonce, and code in a single calldebug_codeByHash: Retrieves bytecode by hash without needing the address
When disabled, falls back to standard RPC methods and caches bytecode locally for compatibility with non-Reth nodes.
Technical Details
The RpcBlockchainProvider uses alloy_network::AnyNetwork for network operations, providing compatibility with various Ethereum-based networks while maintaining the expected block structure with headers.
This provider implements the same traits as the local BlockchainProvider, making it a drop-in replacement for scenarios where remote RPC access is preferred over local database access.
License
Licensed under either of:
- Apache License, Version 2.0, (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
File: crates/storage/libmdbx-rs/mdbx-sys/libmdbx/ut_and_examples/README.md
Examples & Unit tests
This set of examples will be updated, and most of the examples are also publicly available tests.
C API
The example-mdbx.c is the example of using the C API.
However, it is strongly recommended to use the modern C++ API, which requires less effort
and insures against many errors related to resource leaks.
Berkeley DB
If you have already used Berkeley DB, then it will be useful to make a line-by-line comparison of example-mdbx.c and the sample-bdb.txt file.
File: crates/storage/libmdbx-rs/README.md
libmdbx-rs
Rust bindings for libmdbx.
Forked from an earlier Apache licenced version of the libmdbx-rs crate, before it changed licence to GPL.
NOTE: Most of the repo came from lmdb-rs bindings.
Updating the libmdbx Version
To update the libmdbx version you must clone it and copy the dist/ folder in mdbx-sys/.
Make sure to follow the building steps.
# clone libmdbx to a repository outside at specific tag
git clone https://github.com/erthink/libmdbx.git ../libmdbx --branch v0.7.0
make -C ../libmdbx dist
# copy the `libmdbx/dist/` folder just created into `mdbx-sys/libmdbx`
rm -rf mdbx-sys/libmdbx
cp -R ../libmdbx/dist mdbx-sys/libmdbx
# add the changes to the next commit you will make
git add mdbx-sys/libmdbxFile: crates/static-file/static-file/README.md
StaticFile
Overview
Data that has reached a finalized state and won't undergo further changes (essentially frozen) should be read without concerns about modification. This makes it unsuitable for traditional databases.
This crate aims to copy this data from the current database to multiple static files, aggregated by block ranges. At every 500_000th block, a new static file is created.
Below are four diagrams illustrating how data is served from static files to the provider. A glossary is also provided to explain the different (linked) components involved in these processes.
Query Diagrams ([`Provider`](../../storage/provider/src/providers/database/mod.rs#L41))
By block number
graph TD;
RPC-->P
P("Provider::header(block_number)")-->PF(ProviderFactory)
PF--get_-->DC1{block_number > highest static file block}
DC1 --> |true| PD1("DatabaseProvider::header(block_number)")
DC1 --> |false| SFP("StaticFileProvider::header(block_number)")
PD1 --> MDBX
SFP --find block range from block number--> JP("StaticFileJarProvider::header(block_number)")
JP --"creates"-->SC(StaticFileCursor)
SC --".get_one< HeaderMask< Header > >(number)"--->NJC("NippyJarCursor")
NJC--".row_by_number(row_index, mask)"-->NJ[NippyJar]
NJ--"&[u8]"-->NJC
NJC--"&[u8]"-->SC
SC--"Header"--> JP
JP--"Header"--> SFPBy block hash
graph TD;
RPC-->P
P("Provider::block_by_hash(block_number)")-->PF(ProviderFactory)
PF --> PD1("DatabaseProvider::block_id(block_hash)")
PD1 --block number--> DC1{block_number > highest static file block}
DC1 --> |true| PD2("DatabaseProvider::block_by_id(block_number)")
DC1 --> |false| SFP("StaticFileProvider::block_by_id(block_number)")
PD2 --> MDBX
SFP --find block range from block number--> JP("StaticFileJarProvider::block_by_id(block_number)")
JP --"creates"-->SC(StaticFileCursor)
SC --".get_one< HeaderMask< Header > >(number)"--->NJC("NippyJarCursor")
NJC--".row_by_number(row_index, mask)"-->NJ[NippyJar]
NJ--"&[u8]"-->NJC
NJC--"&[u8]"-->SC
SC--"Header"--> JP
JP--"Header"--> SFPBy transaction number
graph TD;
RPC-->P
P("Provider::transaction_by_id(transaction_number)")-->PF(ProviderFactory)
PF--get_-->DC1{transaction_number > highest static file transaction}
DC1 --> |true| PD1("DatabaseProvider::transaction_by_id(transaction_number)")
DC1 --> |false| SFP("StaticFileProvider::transaction_by_id(transaction_number)")
PD1 --> MDBX
SFP --find block range from transaction number--> JP("StaticFileJarProvider::transaction_by_id(transaction_number)")
JP --"creates"-->SC(StaticFileCursor)
SC --".get_one< HeaderMask< Header > >(number)"--->NJC("NippyJarCursor")
NJC--".row_by_number(row_index, mask)"-->NJ[NippyJar]
NJ--"&[u8]"-->NJC
NJC--"&[u8]"-->SC
SC--"Header"--> JP
JP--"Header"--> SFPBy transaction hash
graph TD;
RPC-->P
P("Provider::transaction_by_hash(transaction_number)")-->PF(ProviderFactory)
PF --> PD1("DatabaseProvider::transaction_id(transaction_hash)")
PD1 --transaction number--> DC1{transaction_number > highest static file transaction}
DC1 --> |true| PD2("DatabaseProvider::transaction_by_id(transaction_number)")
DC1 --> |false| SFP("StaticFileProvider::transaction_by_id(transaction_number)")
PD2 --> MDBX
SFP --find block range from transaction number--> JP("StaticFileJarProvider::transaction_by_id(transaction_number)")
JP --"creates"-->SC(StaticFileCursor)
SC --".get_one< HeaderMask< Header > >(number)"--->NJC("NippyJarCursor")
NJC--".row_by_number(row_index, mask)"-->NJ[NippyJar]
NJ--"&[u8]"-->NJC
NJC--"&[u8]"-->SC
SC--"Header"--> JP
JP--"Header"--> SFPGlossary
In descending order of abstraction hierarchy:
StaticFileProducer: A reth hook service that when triggered, copies finalized data from the database to the latest static file. Upon completion, it updates the internal index at StaticFileProvider with the new highest block and transaction on each specific segment.
StaticFileProvider A provider similar to DatabaseProvider, managing all existing static files and selecting the optimal one (by range and segment type) to fulfill a request. A single instance is shared across all components and should be instantiated only once within ProviderFactory. An immutable reference is given every time ProviderFactory creates a new DatabaseProvider.
StaticFileJarProvider A provider similar to DatabaseProvider that provides access to a single static file segment data on a specific block range.
StaticFileCursor An elevated abstraction of NippyJarCursor for simplified access. It associates the bitmasks with type decoding. For instance, cursor.get_two::>(tx_number) would yield Tx and Signature, eliminating the need to manage masks or invoke a decoder/decompressor.
StaticFileSegment Each static file only contains data of a specific segment, e.g., Headers, Transactions, or Receipts.
NippyJarCursor Accessor of data in a NippyJar file. It enables queries either by row number (e.g., block number 1) or by a predefined key not part of the file (e.g., transaction hashes). Currently, only queries by row number are being used. If a file has multiple columns (e.g., Header | HeaderTD | HeaderHash), and one wishes to access only one of the column values, this can be accomplished by bitmasks. (e.g., for HeaderTD, the mask would be 0b010).
NippyJar An append-or-truncate-only file format. It supports multiple columns, compression (e.g., Zstd (with and without dictionaries), lz4, uncompressed) and inclusion filters (e.g., cuckoo filter: is hash X part of this dataset). StaticFiles are organized by block ranges. (e.g., TransactionStaticFile_0_-_499_999.jar contains a transaction per row for all transactions between block 0 and block 499_999). For more, check the struct documentation.
File: crates/rpc/rpc-e2e-tests/README.md
Reth RPC E2E Tests
This crate contains end-to-end tests for Reth's RPC implementation, including compatibility testing against the official execution-apis test suite.
Overview
The RPC compatibility testing framework enables:
- Importing pre-built blockchain data from RLP files
- Initializing nodes with specific forkchoice states
- Running standardized RPC test cases from the execution-apis repository
- Comparing responses against expected results
Architecture
Key Components
RunRpcCompatTestsAction: Executes RPC test cases from .io filesInitializeFromExecutionApisAction: Applies forkchoice state from JSON files with automatic retry for syncing nodes- Test Data Format: Uses execution-apis .io file format for test cases
Test Data Structure
Expected directory structure:
test_data_path/
โโโ chain.rlp # Pre-built blockchain data
โโโ headfcu.json # Initial forkchoice state
โโโ genesis.json # Genesis configuration (optional)
โโโ eth_getLogs/ # Test cases for eth_getLogs
โโโ contract-addr.io
โโโ no-topics.io
โโโ topic-exact-match.io
โโโ topic-wildcard.io.io File Format
Test files use a simple request-response format:
// Optional comment describing the test
// speconly: marks test as specification-only
>> {"jsonrpc":"2.0","id":1,"method":"eth_getLogs","params":[...]}
<< {"jsonrpc":"2.0","id":1,"result":[...]}Usage
Basic Example
use alloy_genesis::Genesis;
use reth_chainspec::ChainSpec;
use reth_e2e_test_utils::testsuite::{
actions::{MakeCanonical, UpdateBlockInfo},
setup::{NetworkSetup, Setup},
TestBuilder,
};
use reth_rpc_e2e_tests::rpc_compat::{InitializeFromExecutionApis, RunRpcCompatTests};
#[tokio::test]
async fn test_eth_get_logs_compat() -> Result<()> {
let test_data_path = "../execution-apis/tests";
let chain_rlp_path = PathBuf::from(&test_data_path).join("chain.rlp");
let fcu_json_path = PathBuf::from(&test_data_path).join("headfcu.json");
let genesis_path = PathBuf::from(&test_data_path).join("genesis.json");
// Parse genesis.json to get chain spec with all hardfork configuration
let genesis_json = std::fs::read_to_string(&genesis_path)?;
let genesis: Genesis = serde_json::from_str(&genesis_json)?;
let chain_spec: ChainSpec = genesis.into();
let chain_spec = Arc::new(chain_spec);
let setup = Setup::<EthEngineTypes>::default()
.with_chain_spec(chain_spec)
.with_network(NetworkSetup::single_node());
let test = TestBuilder::new()
.with_setup_and_import(setup, chain_rlp_path)
.with_action(UpdateBlockInfo::default())
.with_action(
InitializeFromExecutionApis::new()
.with_fcu_json(fcu_json_path.to_string_lossy()),
)
.with_action(MakeCanonical::new())
.with_action(RunRpcCompatTests::new(
vec!["eth_getLogs".to_string()],
test_data_path.to_string_lossy(),
));
test.run::<EthereumNode>().await?;
Ok(())
}Running Tests
To run the official execution-apis test suite:
Clone the execution-apis repository:
bashgit clone https://github.com/ethereum/execution-apis.gitSet the test data path environment variable:
bashexport EXECUTION_APIS_TEST_PATH=/path/to/execution-apis/testsRun the execution-apis compatibility test:
bashcargo nextest run --test e2e_testsuite test_execution_apis_compat
This will auto-discover all RPC method directories and test each file individually, providing detailed per-file results.
Custom Test Data
You can create custom test cases following the same format:
- Create a directory structure matching the execution-apis format
- Write .io files with request-response pairs
- Use the same testing framework with your custom path
Test Multiple RPC Methods
let methods_to_test = vec![
"eth_blockNumber".to_string(),
"eth_call".to_string(),
"eth_getLogs".to_string(),
"eth_getTransactionReceipt".to_string(),
];
RunRpcCompatTests::new(methods_to_test, test_data_path)
.with_fail_fast(true) // Stop on first failureImplementation Details
JSON-RPC Request Handling
The framework handles various parameter formats:
- Empty parameters:
[] - Array parameters:
[param1, param2, ...] - Object parameters: Wrapped in array
[{...}]
Response Comparison
- Numbers: Compared with floating-point tolerance
- Arrays: Element-by-element comparison
- Objects: Key-by-key comparison (extra fields in actual response are allowed)
- Errors: Only presence is checked, not exact message
Error Handling
- Parse errors are reported with context
- RPC errors are captured and compared
- Test failures include detailed diffs
Benefits
- Standardization: Uses official execution-apis test format
- Flexibility: Works with custom test data
- Integration: Seamlessly integrates with e2e test framework
- Extensibility: Easy to add new RPC methods
- Debugging: Detailed error reporting with fail-fast option
Future Enhancements
- Support for batch requests
- WebSocket testing
- Performance benchmarking
- Automatic test discovery
- Parallel test execution
File: crates/rpc/ipc/README.md
reth-ipc
IPC server and client implementation for jsonrpsee.
File: crates/node/builder/README.md
reth-node-builder
A declarative way to configure a reth ethereum node.
Examples
The examples folder contains various examples of how to use the builder to configure a reth node.