From geth to reth: The Evolution of X Layer's Execution Client
X Layer is OKX's EVM-compatible Layer 2 network built on the OP Stack. Since its launch, X Layer has undergone two major architectural transitions: an initial migration from Polygon CDK (zkEVM Validium) to the OP Stack, followed by a swap of the execution client from geth to reth. This post covers the second transition — the rationale behind choosing reth and the engineering work required to make it production-ready for X Layer.
Background and Motivation
The default execution client for OP Stack chains is geth, a fork of go-ethereum maintained alongside the Optimism codebase. geth is battle-tested and widely deployed, but as transaction throughput scales, two structural limitations of the go-ethereum architecture become increasingly difficult to work around.The first is storage growth. Geth's archive node disk usage expands linearly with chain history, and at L2 throughput levels the rate is significant enough to create real operational pressure over time. The second is latency consistency. Go's garbage collector introduces non-deterministic pauses under sustained load, and background LevelDB/PebbleDB compaction periodically stalls block production — both of which show up as tail latency spikes that users feel directly.Reth, Paradigm's Rust reimplementation of an Ethereum execution client, addresses both at the architecture level. Rust's compile-time memory model eliminates the runtime GC entirely. reth pairs this with the MDBX storage engine and a staged sync pipeline, delivering meaningfully better disk efficiency and more predictable latency under load.Extensibility was equally important. Reth ships a full Node Builder API — a set of well-defined hooks that let you inject custom logic into the node lifecycle without modifying upstream source. For an L2 execution client that requires significant customization, this matters: upgrades stay tractable, custom logic stays isolated, and the gap between your client and upstream never quietly grows out of control.
Architecture Overview
xlayer-reth sits at the top of a three-layer dependency hierarchy:
xlayer-reth ← X Layer customization layer
└── op-reth ← OP Stack execution layer (maintained by Optimism)
└── paradigmxyz/reth ← core Rust Ethereum execution engineAll X Layer–specific code lives exclusively in the top layer, wired in through reth's extension hooks. The two layers below are consumed as-is from their respective upstream repositories, with no private patches applied. This structure makes it straightforward to pull in upstream security fixes and performance improvements — merging upstream changes doesn't require reconciling a divergent core.Each feature is organized as an independent crate: Chainspec, the legacy RPC router, Flashblocks, custom RPC extensions, and others. The main binary assembles them. Each crate evolves and is tested in isolation.
Key Features
Non-Zero Genesis Block Number
When X Layer migrated from Polygon zkEVM to the OP Stack, the old chain terminated at mainnet block 42,810,021. The OP Stack chain continued from that exact block height, preserving block number continuity for block explorers, indexers, and any on-chain or off-chain logic that references historical block numbers.Reth, however, assumed a genesis block number of zero — the number field in the genesis JSON was silently ignored during initialization. Rather than carrying a private patch indefinitely, the X Layer team filed Issue #19874 and contributed a fix via PR #19877, which has since been merged into the official reth repository. Any chain with a non-zero genesis block number can now use this natively.
Transparent Historical RPC Routing
The historical state below block 42,810,021 exists only on the legacy Polygon zkEVM node (erigon-based), not on the new reth node. Without special handling, RPC queries for pre-migration blocks return empty results.xlayer-reth solves this with a Tower middleware layer inserted into the jsonrpsee RPC stack. Before any request reaches reth, the middleware checks the requested block number against the migration cutoff. Requests below the threshold are transparently proxied to the legacy node; all others are served locally. The routing is invisible to callers — the same RPC endpoint handles the full block range.Range queries require additional handling. For eth_getLogs requests that span both sides of the cutoff, the middleware splits the request into two concurrent sub-requests, dispatches each to the appropriate node, and merges the results before returning. This covers cross-boundary log queries without any special-casing on the client side.
Hardfork Specification and Chain Configuration
xlayer-reth ships a complete Chainspec for each of X Layer's three networks: mainnet (chain ID 196), testnet, and devnet. Each spec encodes the chain ID, genesis block parameters, and the full hardfork activation schedule.Every Ethereum hardfork from Frontier through OP Stack Isthmus is activated at genesis. A newly synced node starts with full EVM capability from its genesis block, without needing to replay protocol transitions. This avoids the complexity of bootstrapping a node that must walk through historical fork rules before reaching the current execution environment.X Layer also introduces a custom hardfork named Jovian, corresponding to OP Stack Network Upgrade 17. Jovian activated on mainnet in December 2025, keeping X Layer's protocol evolution synchronized with the broader OP ecosystem.
Flashblocks
Standard OP Stack block times are around two seconds. Flashblocks is a pre-confirmation mechanism that reduces perceived transaction confirmation latency by roughly 10x: the sequencer publishes partial block execution state every approximately 250 milliseconds as a flashblock, allowing clients to observe transaction outcomes well before the full block is sealed.On the node side, RPC nodes subscribe to a WebSocket stream of flashblocks published by the upstream sequencer. Each incoming flashblock is fully executed locally and its state is written to an in-memory cache. 22 standard Ethereum JSON-RPC methods — including eth_getBlockByNumber, eth_getBalance, and eth_call — are overridden to serve responses from this cache when queried for the latest or pending block state, delivering pre-confirmed results without waiting for block finalization.To avoid redundant execution, the engine validator and the Flashblocks processor share a single execution cache. Transactions already executed during flashblock processing are not re-executed when the engine validates the final block payload.
Custom RPC Extensions
xlayer-reth exposes two X Layer–specific JSON-RPC methods alongside the standard Ethereum API:
eth_flashblocksEnabled — returns whether the node's Flashblocks service is active and receives data from the sequencer.
eth_flashblocksPeerStatus — returns the P2P peer connectivity status of the Flashblocks layer on sequencer nodes, primarily for operational monitoring.
Both methods are registered via reth's RPC extension mechanism and coexist with the standard API without modifying or conflicting with any existing method behavior.
Engineering Principles
Two principles governed how xlayer-reth was built.Extend through the framework, not around it. Any feature that can be implemented using reth's existing extension hooks — middleware registration, engine validator injection, RPC module replacement — is done that way. Custom code stays in the top layer; upstream code is never modified. This keeps upgrade costs low and makes the custom surface area easy to audit and iterate on independently.Contribute generic fixes upstream. When a feature genuinely requires modifying reth internals, the right path is a pull request to the official repository, not an accumulating private patch. Non-zero genesis block support (PR #19877) is the concrete example: the fix is now part of reth and available to any chain that needs it, without anyone having to maintain a fork.
Summary
The move from geth to reth was motivated by performance — lower block construction latency, reduced storage footprint, and faster node sync times. Realizing those gains in production required building out the execution layer features specific to X Layer's history and operational requirements: a non-zero genesis block inherited from a prior chain, years of historical state stored on a legacy node, chain configuration spanning two protocol architectures, a pre-confirmation system that fundamentally changes how clients interact with pending state, and the operational tooling to monitor the system.Building on a mature open-source framework rather than forking core infrastructure, and contributing reusable improvements back to that framework, is how X Layer approaches sustainable infrastructure development — and how the broader L2 ecosystem benefits from work done by individual teams.
Source: okx/xlayer-reth
© OKX, 2025. Эту статью можно копировать и распространять как полностью, так и в цитатах объемом не более 100 слов, при условии некоммерческого использования. При любом копировании или распространении всей статьи должно быть указано: «Разрешение на использование получено от владельца авторских прав на эту статью — © OKX, 2025. Цитаты должны содержать ссылку на название статьи и ее автора, например: «Название статьи, [имя автора, если указано], © OKX, 2025». Часть контента может быть создана с использованием инструментов искусственного интеллекта (ИИ). Создание производных материалов и любое другое использование данной статьи не допускается.







