At Altius, we spend a lot of time thinking about performance. We envision a world where blockchain infrastructure behaves more like high-frequency trading systems — parallel, memory-oriented, and anti-unnecessary I/O.
So, when we started digging into the Reth Paradigm codebase, it wasn't just curiosity. We were evaluating ways to neatly integrate a modular and scalable status layer underneath the existing EVM engine, which supports our work on Parallel Scalable Storage (PSS) and distributed Merkle trie sharding.
What we found surprised us.
Unforeseen Obstacles
We saw something strange while examining how Reth handles database access, especially during status reads. Even for a simple account lookup, the engine makes unnecessary calls to the database, calls that could be completely short-circuited and skipped.
In a system like Reth, where state is stored in a Merkle-Patricia Trie (MPT) and backed by disk, every additional DB call has a real cost in terms of disk latency. And in Reth's case, we observed substantial unnecessary disk access.
So we opened GitHub Issue #14558 in the reth repo. We documented its behavior, explained its impact on performance, and even suggested various optimizations, some of which utilized existing Paradigm data structures.
What We Found — and How We Fixed It Together!
Indonesian: After a quick reply in the GitHub issue with unhelpful suggestions, we did not receive further updates. Since this clearly obstructed our own goals, we decided to dive into the code and figure it out. Note that the diagram below discusses the various entries in the MDBX database 1 touched by a regular account lookup to get the final information for the actual account. Unsurprisingly, the actual DB layout is thoughtfully designed, and the AccountsTrie table reflects the Ethereum MPT. This made everything surprising when we discovered what was happening behind the scenes. To find this out, we added tracking log messages to every database access we could find and really tracked everything until we knew what was happening.
We want to delve into the (extra) terrible details, but it may be easier to see the difference between our implementation by looking at how the trie walk is done. Again, credit to the DB layout, we found that there is a bitmask stored in each node that roughly indicates exactly what is there or not in the node directly below it. So, instead of walking through a large part of the trie, we only walk through the necessary parts. This is reth v1.3.2:
For example, at the top level, even though we know that we will need all level 1 nodes to compute the root hash after updating the MPT, and even though the available bitmask already tells us that these nodes exist, reth still keeps searching each node. There is no full visit to each node, but many nodes are unnecessarily visited. Let's move on to our solution. We did the simple thing that people expected!
We use the existing information embedded in the bitmask of each node to figure out whether the corresponding node exists in the HashedAccounts table. Additionally, we simply traverse the tree to all the nodes we need to compute the root hash.
As you can see in the diagram, there are fewer orders of magnitude of DB operations. And as we know, every disk access we can avoid is crucial for the speed of each execution layer. The diagram above is the result of a single random transaction we tracked. Of course, 1 transaction is not a real metric, so we tracked between 500 and 1000 blocks and saw improvements of between 70% — 80% across various block ranges. However, what matters is the actual disk IOPS, so we analyzed that next.
Translating these DB operations into read IOPS reduction led us to test performance by executing 100 blocks (19476587–19476686) and leveraging Linux cgroups to isolate reth's IOPS performance during execution. For our testing, we did 12 tests that first cleared the disk cache, isolating IOPS to the reth process and mdbx database on NVMe storage devices, then calculated the average of 6 midpoint tests (discarding the first 3 tests and the last 3 tests using the standard practice known as interquartile range or IQR). This work was done on standard Amazon Web Services EC2 instances (i8g.4xlarge). The result was a 44% reduction in read IOPS from our optimizations.
Why We Saw This from the Start
At Altius, our architecture is built on several core ideas:
Execution must be parallel. Sequential transaction processing fails to fully utilize processor computing power, but this requires account information to be available before the transaction needs it!
State should exist as much as possible in memory and be intelligently cached.
Disk I/O is the enemy of performance. Especially in competition.
That’s why we built Parallel Scalable Storage, which includes a distributed Merkle trie implementation and prioritizes memory. The ultimate goal is to allow the execution layer to treat our system like a black box: fast, reliable, and horizontally scalable. But to do that, we need clean abstraction boundaries, and clean abstractions demand predictable behavior from upstream code. That's why, after observing the DB access patterns in Reth, we decided to fix it ourselves.
What Makes This Possible
With optimized and more consistent access patterns, the Altius state engine can fit into existing clients. For chains using Reth, this means:
Direct I/O reduction without changes to consensus or VM.
Support for distributed trie storage — run your state across multiple nodes, not just one.
Better developer ergonomics for testing status modules separately.
We continue to build adapter layers and plan to make the integration work open source.
We Believe in Open Performance
It's not about accolades. It's about execution performance. This writing is not an invitation. It's a call to action.
Reth from Paradigm is great engineering, and one of the reasons for its existence is for the community to contribute and collaborate. We will continue to surface things we find. And we will keep building modular, open components that allow any chain to run at scale without rebuilding the world from scratch.
Because in the end, every I/O still counts.
Reth Team Improvement Update
After about 3 weeks, as we were hard at work on our own solution, there was actually an update on the GitHub issue. It turns out our investigation and analysis had opened the door to fantastic improvements. It seems our solution took a slightly different approach, but using the same ideas, the Paradigm team added similar optimizations to reth.
As a team that just started building with reth, we are still conservative regarding our performance. We usually start from a position assuming we are wrong, and there must be a reason behind something. Knowing that we are right certainly gives us greater confidence that we are on the right path!
Footnote: (1) in MDBX jargon, tables are referred to as databases and databases are called environments. However, to simplify conceptual understanding for most readers who may not have used MDBX before, I refer to MDBX as a database, and the environment as a table. Reference https://pkg.go.dev/github.com/torquem-ch/mdbx-go/mdbx