Skip to content

Commit 862ef51

Browse files
davidtaikochaclaudeDavid
authored
feat(evm): support optional revmc JIT execution (#227)
* feat(evm): support optional revmc JIT execution Pin revmc to the exact revision the reth pin locks (incl. the revmc#394 and #400 compiled-vs-interpreter divergence fixes) and wire it into the Taiko EVM factory behind a workspace `jit` feature, on by default in the binary. Compiled code runs only behind four AND-ed gates: the `jit` build feature, the runtime `--jit`/`reth_jit` switch, the local `with_jit_support()` opt-in (engine tree and payload builder only; RPC execution stays interpreter-only), and an exhaustive fork allowlist that keeps Unzen's zk-gas metering on per-opcode interpreter hooks. Inspected execution always uses the disabled backend, and the wrapper drives the JitEvm through TaikoEvmHandler so anchor and fee-share semantics are preserved. `--jit.blocking` without `--jit` is gated off and now warns, and the differential tests cover the LOG-memory and SELFDESTRUCT builtin-forwarding classes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * ci(repo): provision LLVM 22 and cover interpreter-only builds Install LLVM 22 through a sha256-pinned apt.llvm.org helper in the test and clippy jobs and in the Docker build (bookworm has no arm64 LLVM 22, so both image stages move to trixie). New jobs prove the `--no-default-features` build stays LLVM-free and compile the `cfg(not(feature = "jit"))` test targets, and an arm64 job runs the installer inside the Docker base distribution. check_reth_pin.sh now also fails on multiple revmc revisions, and the `.github/**` paths-ignore is dropped so changes to these scripts run CI. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(repo): document revmc JIT usage and pin invariants Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(repo): steer developers away from the CI-only LLVM installer The build section pointed developers at install_llvm.sh, whose own header marks it CI/Docker-only because it force-overwrites the /usr/bin LLVM symlinks. Document the versioned-package route (distro llvm-22 or apt.llvm.org, then PATH) instead and say explicitly not to run the helper on a developer machine. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * ci(repo): verify the revmc pin matches reth's locked revision Counting revmc revisions only guards against a split graph; the documented invariant is stronger — Alethia's revmc rev must equal the one reth's own Cargo.lock pins at our reth revision, which nothing enforces at build time because reth tracks revmc by branch. Fetch reth's lockfile at the pinned rev and compare, failing closed on mismatch, a missing revmc entry, or an unfetchable lockfile. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(evm): design beacon root override integration * docs(evm): plan beacon root override integration * fix(evm): honor beacon root overrides * chore(docs): remove superpowers planning artifacts * fix(rpc): reject non-zero parent beacon block roots in attributes A non-zero root from forkchoiceUpdated attributes was committed into the built Unzen header, but getPayload's V1 payload + sidecar carry no beacon-root field and convert_payload_to_block rebuilds Unzen headers with the zero root, so the block failed every newPayload re-import with a block-hash mismatch. Nothing filtered the field on the V2 route. Fail closed instead, at engine attribute validation and again in TaikoPayloadBuilderAttributes::try_new (the constructor every payload job passes through); zero and absent roots keep round-tripping and the pending-block BlockOverrides.beacon_root path is unaffected. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: David <cai@Davids-MacBook-Pro.local>
1 parent 479fe5b commit 862ef51

30 files changed

Lines changed: 1602 additions & 105 deletions

File tree

.github/scripts/check_reth_pin.sh

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,54 @@
55
# coherent while Alethia's reth pin references the exact commit OP pins (see the
66
# reth-optimism-trie note in Cargo.toml); a drifted pin splits the workspace into two
77
# incompatible reth copies.
8+
#
9+
# Also fails on multiple paradigmxyz/revmc revisions: Alethia pins revmc by rev while reth's
10+
# own (unused) `jit` feature declares it by branch, so re-enabling that reth feature would
11+
# otherwise split the graph into two revmc copies silently.
12+
#
13+
# Finally, verifies Alethia's revmc revision equals the one reth's own Cargo.lock pins at our
14+
# reth revision. reth tracks revmc by branch in its manifest, so nothing enforces this at
15+
# build time — a reth bump that forgets to move Alethia's revmc rev would build fine while
16+
# compiled-code semantics silently drift from what upstream tested against.
817
set -euo pipefail
918

10-
revs=$(grep -oE 'github\.com/paradigmxyz/reth\?[^"]*#[0-9a-f]{40}' Cargo.lock | sed 's/.*#//' | sort -u)
11-
count=$(printf '%s' "$revs" | grep -c . || true)
19+
single_rev() {
20+
local repo=$1
21+
local revs count
22+
revs=$(grep -oE "github\.com/paradigmxyz/${repo}(\.git)?\?[^\"]*#[0-9a-f]{40}" Cargo.lock | sed 's/.*#//' | sort -u)
23+
count=$(printf '%s' "$revs" | grep -c . || true)
24+
25+
if [ "$count" -ne 1 ]; then
26+
echo "Error: expected exactly one paradigmxyz/${repo} revision in Cargo.lock, found $count:" >&2
27+
printf '%s\n' "$revs" >&2
28+
exit 1
29+
fi
30+
31+
printf '%s' "$revs"
32+
}
33+
34+
reth_rev=$(single_rev reth)
35+
echo "single reth revision in Cargo.lock: $reth_rev"
36+
revmc_rev=$(single_rev revmc)
37+
echo "single revmc revision in Cargo.lock: $revmc_rev"
38+
39+
reth_lock_url="https://raw.githubusercontent.com/paradigmxyz/reth/${reth_rev}/Cargo.lock"
40+
if ! reth_lock=$(curl -fsSL --retry 5 "$reth_lock_url"); then
41+
echo "Error: failed to fetch reth's lockfile from $reth_lock_url" >&2
42+
exit 1
43+
fi
44+
45+
reth_locked_revmc=$(grep -oE 'github\.com/paradigmxyz/revmc(\.git)?\?[^"]*#[0-9a-f]{40}' <<< "$reth_lock" | sed 's/.*#//' | sort -u)
46+
if [ -z "$reth_locked_revmc" ]; then
47+
echo "Error: found no locked revmc revision in $reth_lock_url" >&2
48+
exit 1
49+
fi
1250

13-
if [ "$count" -ne 1 ]; then
14-
echo "Error: expected exactly one paradigmxyz/reth revision in Cargo.lock, found $count:" >&2
15-
printf '%s\n' "$revs" >&2
51+
if [ "$revmc_rev" != "$reth_locked_revmc" ]; then
52+
echo "Error: Cargo.lock pins revmc $revmc_rev, but reth $reth_rev locks:" >&2
53+
printf '%s\n' "$reth_locked_revmc" >&2
54+
echo "Keep the revmc rev in Cargo.toml matched to the reth pin's locked revmc." >&2
1655
exit 1
1756
fi
1857

19-
echo "single reth revision in Cargo.lock: $revs"
58+
echo "revmc revision matches reth's locked revmc"

.github/scripts/install_llvm.sh

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#!/usr/bin/env bash
2+
set -eo pipefail
3+
4+
os=${1:?usage: install_llvm.sh <ubuntu> [version]}
5+
version=${2:-22}
6+
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
7+
8+
case "$os" in
9+
ubuntu)
10+
sudo "$script_dir/install_llvm_ubuntu.sh" "$version"
11+
;;
12+
*)
13+
echo "unsupported OS: $os" >&2
14+
exit 1
15+
;;
16+
esac
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#!/usr/bin/env bash
2+
#
3+
# CI/Docker provisioning ONLY. This installs apt.llvm.org packages system-wide and
4+
# force-overwrites the /usr/bin/{clang,llvm-config,lld,ld.lld,FileCheck} symlinks, so it must
5+
# not be run on a developer machine: install your distribution's llvm-22 package instead
6+
# (Homebrew `llvm@22` on macOS) and put its bin directory on PATH.
7+
set -eo pipefail
8+
9+
version=${1:-22}
10+
bins=(clang llvm-config lld ld.lld FileCheck)
11+
12+
# The official installer needs this package on Debian bookworm but not on newer distributions.
13+
apt-get update -qq
14+
apt-get install -y --no-install-recommends \
15+
lsb-release wget gnupg ca-certificates
16+
apt-get install -y --no-install-recommends software-properties-common 2>/dev/null || true
17+
18+
llvm_installer=$(mktemp)
19+
wget -qO "$llvm_installer" https://apt.llvm.org/llvm.sh
20+
# Pin the upstream installer so CI and Docker builds fail loudly when it changes; review the new
21+
# script before updating this hash.
22+
echo "9474ecd78b52aba6e923976b1e9773f5613027cc7e237b9956986cb536e02a36 $llvm_installer" | sha256sum -c -
23+
chmod +x "$llvm_installer"
24+
"$llvm_installer" "$version" all
25+
rm -f "$llvm_installer"
26+
27+
for bin in "${bins[@]}"; do
28+
if ! command -v "$bin-$version" &>/dev/null; then
29+
echo "Error: $bin-$version not found after install" >&2
30+
exit 1
31+
fi
32+
ln -fs "$(command -v "$bin-$version")" "/usr/bin/$bin"
33+
done
34+
35+
echo "LLVM $version installed:"
36+
llvm-config --version

.github/workflows/ci.yml

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ name: CI
33
on:
44
pull_request:
55
types: [opened, synchronize, reopened, ready_for_review]
6-
paths-ignore:
7-
- ".github/**"
86
branches-ignore:
97
- release-please--branches--**
108

@@ -17,9 +15,10 @@ jobs:
1715
runs-on: ubuntu-latest
1816
steps:
1917
- uses: actions/checkout@v5
20-
- name: Verify a single reth revision in Cargo.lock
18+
- name: Verify reth and revmc pins in Cargo.lock
2119
run: .github/scripts/check_reth_pin.sh
2220
- uses: rui314/setup-mold@v1
21+
- run: .github/scripts/install_llvm.sh ubuntu
2322
- uses: dtolnay/rust-toolchain@master
2423
with:
2524
toolchain: 1.95.0
@@ -56,6 +55,7 @@ jobs:
5655
steps:
5756
- uses: actions/checkout@v5
5857
- uses: rui314/setup-mold@v1
58+
- run: .github/scripts/install_llvm.sh ubuntu
5959
- uses: dtolnay/rust-toolchain@master
6060
with:
6161
toolchain: 1.95.0
@@ -67,3 +67,34 @@ jobs:
6767
with:
6868
just-version: 1.5.0
6969
- run: just clippy
70+
71+
check-no-jit:
72+
name: check (no default features)
73+
runs-on: ubuntu-latest
74+
timeout-minutes: 30
75+
steps:
76+
- uses: actions/checkout@v5
77+
- uses: rui314/setup-mold@v1
78+
# LLVM is deliberately not installed: this proves the interpreter-only build stays free
79+
# of the LLVM toolchain dependency.
80+
- uses: dtolnay/rust-toolchain@master
81+
with:
82+
toolchain: 1.95.0
83+
- uses: Swatinem/rust-cache@v2
84+
with:
85+
cache-on-failure: true
86+
- run: cargo check --locked -p alethia-reth-bin --no-default-features
87+
# Compiles the `cfg(not(feature = "jit"))` test targets, which no `--all-features` job
88+
# can reach (the node crate never enables `jit` by default).
89+
- run: cargo check --locked -p alethia-reth-node --all-targets
90+
91+
llvm-arm64:
92+
name: llvm install (linux/arm64)
93+
runs-on: ubuntu-24.04-arm
94+
timeout-minutes: 30
95+
steps:
96+
- uses: actions/checkout@v5
97+
# Guards the Docker build on ARM64 hosts: apt.llvm.org omits arm64 packages for some
98+
# Debian releases (bookworm has no arm64 LLVM 22), which only surfaces when installing
99+
# on an ARM64 machine. Runs the same installer inside the Docker base distribution.
100+
- run: docker run --rm -v "$PWD/.github/scripts:/scripts:ro" debian:trixie /scripts/install_llvm_ubuntu.sh

CLAUDE.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Alethia-Reth is a Rust execution client for the Taiko protocol, built atop Parad
1010

1111
- Language: Rust (`1.95.0` toolchain via `rust-toolchain.toml` / `justfile`)
1212
- Framework: Reth v2.4.x APIs (`reth_node_builder`, `reth_rpc`, `reth_engine_primitives`, etc.)
13+
- Optional revmc JIT execution (`jit` feature, on by default in the binary; needs LLVM 22)
1314
- Target protocol: Taiko rollup networks
1415
- Build & dependency manager: Cargo + `just`
1516

@@ -25,7 +26,7 @@ Alethia-Reth is a Rust execution client for the Taiko protocol, built atop Parad
2526
├── cli CLI wrapper (`TaikoCli`)
2627
├── consensus Beacon consensus extensions
2728
├── db Taiko-specific tables & codecs
28-
├── evm EVM config, handlers, execution helpers
29+
├── evm EVM config, handlers, execution helpers, revmc JIT integration
2930
├── payload Payload builder service
3031
├── primitives Shared types (engine, payload attributes)
3132
├── rpc Taiko RPC (eth / engine / auth)

0 commit comments

Comments
 (0)