feat: upgrade to reth v2.4.1 - #147
Open
sprites0 wants to merge 5 commits into
Open
Conversation
sprites0
force-pushed
the
feat/reth-v2.4.1
branch
from
July 26, 2026 07:55
dc1cfbf to
8e9a5f3
Compare
Ports nanoreth from the 1.8.2-based fork to one based on upstream v2.4.1, 3,127 upstream commits later. The fork is hl-archive-node/reth v2.4.1-fork, carrying four commits: the HL state-root drop, a metrics panic fix, the revmc pin, and a `JitEvm` re-export. Dependency moves that drove most of the diff: alloy 1.0.37 -> 2.1.1/2.2.0, revm 29 -> 41, alloy-evm 0.21 -> 0.37, vergen 9 -> 10. Storage is now storage_v2, so state lives in static files and RocksDB rather than MDBX tables. Notable fixes along the way: * Legacy transactions no longer round-trip through msgpack. alloy 2.x serializes `TxLegacy::gas_price` as `U128` but deserializes it through `U256`, so S3 blocks failed to decode with "invalid length 16, expected 256 bits". `WireTxLegacy` mirrors the wire shape and is covered by two tests. * The pseudo peer never connected: `local_node_record()` returns the NAT-resolved address even with `disable_nat()`, so the node dialled a public IPv6 address instead of the in-process peer. It now dials `local_addr()`. * `--debug-cutoff-height` was honoured by the block poller but not by the forkchoice trigger, which still used the real tip. New: a runtime-configurable revmc JIT for HL execution (`--hl.jit`, default on, with `--hl.jit.hot-threshold` and `--hl.jit.worker-count`). Measured over 1,000,000 mainnet blocks from genesis, execution runs 593s with the JIT against 903s without it, and 14 table checksums are identical across both. Validated by syncing 5,000,000 mainnet blocks from genesis through all 13 stages with no errors. The revm inspector selfdestruct backport carries over: revm 41 does not have the fix (it landed upstream in 42, and no released alloy-evm or revm-inspectors supports 42 yet), so the patch is rebased onto the 41.0.0 series as hl-archive-node/revm@ed244b83. Its regression test fails without the handler change and passes with it.
sprites0
force-pushed
the
feat/reth-v2.4.1
branch
from
July 26, 2026 08:17
8e9a5f3 to
d34f3b5
Compare
`EvmTr`'s ctx, ctx_ref, ctx_instructions, ctx_precompiles and frame_stack all have `#[inline]` defaults that project out of `all()`/`all_mut()`, which this impl already overrides with the field references. The five hand-written accessors returned exactly what those projections produce. `to_range` is now `pub` in reth-provider and byte-identical to the copy here. Verified by resyncing 1,000,000 mainnet blocks from genesis: all 14 table checksums are unchanged, covering headers, transactions, receipts, senders, both change-set segments, the three RocksDB history tables, hashed state, both tries and bytecodes. Left alone, despite also having defaults: `Encodable::length` (the default allocates and encodes just to count bytes), `recover_unchecked_with_buf` (the default discards the caller's buffer, costing an allocation per transaction during batch sender recovery) and `send_raw_transaction` (the default decodes before reaching the unreachable stub).
Every job failed at `llvm-sys`: the `jit` feature is on by default and needs LLVM 22 to link, which the runners do not carry. Install it the way reth does, with the same `install_llvm_ubuntu.sh` script, rather than dropping the feature from CI -- the JIT path is default-on and should not go untested. The release build had the same problem waiting for the next tag: it passes `--features` without `--no-default-features`, so `jit` was already in its graph. revmc is pinned with `llvm-prefer-static`, so the released binary stays self-contained. Also fixes the redundant closure the clippy job would have failed on once it got far enough to run.
udeps flags it, and it is genuinely unused: nothing in src, tests or build.rs has ever referenced it, on this branch or on node-builder. Only tikv-jemallocator is used, for the global allocator in main.rs. It has been declared since the first commit; what changed is that the job installs cargo-udeps unpinned, so a newer version now catches it.
Matches reth's posture more closely. reth ships `jit` in the binary's default features but leaves the runtime flag off, opting in with `--jit` or the `reth_jit` RPC method. This goes one step further and drops the feature from the default set too, so a plain `cargo build` needs no LLVM 22 at all. Both gates must now be open: build with `--features jit`, then start the node with `--hl.jit true`. A build without the feature ignores the flag. Knock-on changes: * The Dockerfile no longer needs `--no-default-features --features jemalloc`. That existed only because dropping `jit` also dropped `jemalloc`; with `jit` out of the defaults it is just `--features jit` when ENABLE_JIT=true. * release.yml no longer installs LLVM. Its feature set does not pull revmc any more, confirmed with `cargo tree -i revmc`. * Cargo Test now runs `--features jit`. Without this the feature would ship untested, since a plain `cargo test` no longer compiles it. Cargo Check keeps the default set, so both configurations stay covered. Verified: default, jit, and release feature sets all compile, and the suite passes under `--features jit`.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Ports nanoreth from its 1.8.2-based fork to one based on upstream v2.4.1 — 3,127 upstream commits later.
The fork
hl-archive-node/reth@v2.4.1-fork, pinned at5c43bf8cdc362fad776cdd7040dcabac67c648e8, four commits on top of the upstream tag:c8db7d76dhl: drop state root verification— unconditional, since we don't support chains with non-zero state rootscbdf9d7eefix(db): do not panic on tables outside the default TableSet— upstream bug; nanoreth'sBlockReadPrecompileCallstripped it70c06137chl: pin revmc— revmcmainhas moved to a build against a newer revm and no longer compiles against revm 415c43bf8cdfeat(evm): re-export revm_evm::JitEvm— lets nanoreth wrap its own EVM without a direct revmc dependencyThe last two are generic and would be reasonable upstream PRs.
Dependency moves
alloy 1.0.37 → 2.1.1/2.2.0 · revm 29 → 41 · alloy-evm 0.21 → 0.37 · vergen 9 → 10. Storage is now storage_v2, so state lives in static files and RocksDB rather than MDBX tables.
Fixes found on the way
TxLegacy::gas_priceasU128but deserializes it throughU256, so S3 blocks failed to decode withinvalid length 16, expected 256 bits.WireTxLegacymirrors the wire shape; two regression tests cover it. Confirmed a regression by decoding the same blocks with the pre-upgrade binary.local_node_record()returns the NAT-resolved address even withdisable_nat(), so the node dialled a public IPv6 address instead of the in-process peer and sat atconnected_peers=0. It now dialslocal_addr().--debug-cutoff-heightwas half-honoured — the block poller respected it, the forkchoice trigger still used the real tip.New: opt-in JIT
revmc JIT for HL execution, opt-in at both build and run time, matching reth's posture. Build with
--features jit, then start with--hl.jit true; a build without the feature ignores the flag. Also--hl.jit.hot-thresholdand--hl.jit.worker-count. A plain build drops revmc and its LLVM 22 requirement from the graph entirely.JIT is disabled below block 243,538 on mainnet, where
BLOCKHASHgoes through a patched instruction handler that JIT-compiled code would bypass.Validation
0x917a0420060727e291a569c6de3c4688d2e0ed3a7f737590448b477bc973ffc4, matching the forkchoice trigger.PlainAccountState/PlainStorageStatehash zero entries under storage_v2 and are excluded rather than counted as passes.)cargo checkis warning-clean.jemalloc.Docker
The
jitfeature needs LLVM 22.1, newer than the base image carries, so image builds leave it off unless you pass--build-arg ENABLE_JIT=truewith a suitable base. Added a.dockerignoreallowlist — the build context was 1.85GB — and cache mounts fortargetand the cargo registry, since cooking reth's dependency tree wrote a single 74GB layer underlto = "thin".