feat(tokamak): JIT-compiled EVM with proven execution infrastructure#2
feat(tokamak): JIT-compiled EVM with proven execution infrastructure#2
Conversation
Complete Phase 0 analysis: evaluate ethrex, Reth, from-scratch, and revm-only options via weighted decision matrix. ethrex fork selected (score 4.85/5) for its custom LEVM, ZK-native architecture, Hook system, and manageable 133K-line codebase. Includes vision, competitive landscape, feature specs, team discussion summaries, Volkov review history, and branch strategy.
- Rebalance decision matrix to ethrex vs Reth binary comparison; move "from scratch" and "revm only" to appendix - Adjust Reth scores: ZK 1→2 (Zeth exists), manageability 2→3 (modular arch acknowledged), sync 5→4 for ethrex (less battle-tested) - Add EXIT criteria with 4 elements: metric, deadline, action, owner - Add Tier S PoC section: perf_opcode_timings build verification and code path analysis - Add JIT technical barriers (dynamic jumps, revmc reference) - Fix weighted sum arithmetic (Reth 2.85→2.80)
Record completed work: DECISION.md creation, Volkov R6 review (6.5/10), three mandatory fixes (matrix rebalance, EXIT criteria, Tier S PoC), Reth/Zeth/ExEx research findings, and next steps for Phase 1.1.
- DECISION.md: DRAFT → FINAL - Replace human staffing model with AI Agent development model - Add bus factor policy (Kevin as interim decision-maker) - Replace staffing risks with agent-specific risks - Remove Senior Rust 2명 EXIT criterion - Add 11 custom commands (.claude/commands/): - Development: /rust, /evm, /jit, /debugger, /l2 - Verification: /quality-gate, /safety-review, /diff-test - Operations: /rebase-upstream, /phase, /bench - Volkov R8: 7.5/10 PROCEED achieved
Architecture analysis documents: - OVERVIEW.md: 25+2 crate dependency graph, node startup flow, CI inventory - LEVM.md: VM struct, execution flow, dual-dispatch loop, hook system - MODIFICATION-POINTS.md: 5 modification points, hybrid isolation strategy - PHASE-1-1.md: Phase 1.1 execution plan with success criteria Phase 1.1 infrastructure: - Skeleton crates: tokamak-jit, tokamak-bench, tokamak-debugger - Feature flag: `tokamak` propagation chain (cmd → vm → levm) - Workspace registration for 3 new crates
- Fix OpcodeTimings: remove false min/max claim, document 4 actual fields - Fix CallFrame: caller→msg_sender, Bytes→Code, return_data→output/sub_return_data - Fix opcode table: describe const fn chaining pattern accurately - Label all pseudocode snippets consistently (JIT, debugger, L2 hook) - Plan feature flag split: tokamak → tokamak-jit/debugger/l2 - Add JIT-VM interface complexity analysis (5 challenges) - Add failure scenarios & mitigations table (5 scenarios) - Record build results: 5m53s clean, 718 tests passed - Fix line count ~133K → ~103K (verified via wc -l) - Add tokamak feature to OVERVIEW.md feature tables
Split monolithic `tokamak` feature into 3 independent features (tokamak-jit, tokamak-debugger, tokamak-l2) with umbrella re-export. Add pr-tokamak.yaml CI workflow for quality-gate and format checks. Update snapsync action default image to tokamak-network/ethrex. Document sync architecture, Hive test matrix, and success criteria.
Add structured benchmark infrastructure to tokamak-bench crate: - timings.rs: reset(), raw_totals(), raw_counts() accessors - tokamak-bench: types, runner, report, regression modules + CLI binary - CI workflow: pr-tokamak-bench.yaml (bench PR vs base, post comparison) - 11 unit tests covering regression detection, JSON roundtrip, reporting
Feature unification causes these modules to be compiled during L2 workspace clippy. Add targeted allows for arithmetic_side_effects, as_conversions, expect_used, and unsafe_code lints.
Add the core JIT tiered compilation modules that were missing from the branch: execution counter, code cache dispatch, types, and module declaration. These provide the lightweight in-process infrastructure gated behind the tokamak-jit feature flag.
- tokamak-jit: compiler, backend, adapter, validation, error modules - JIT backend CI job with LLVM 18 in pr-tokamak.yaml - jit_bench module in tokamak-bench for interpreter vs JIT comparison - Phase 2 architecture documentation - Updated HANDOFF with current status
🤖 Kimi Code ReviewAutomated review by Kimi (Moonshot AI) |
Summary of ChangesHello @cd4761, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! 이 풀 리퀘스트는 Tokamak 이더리움 클라이언트의 기반을 다지는 중요한 진전을 나타냅니다. JIT EVM, 연속 벤치마킹, 타임-트래블 디버거와 같은 핵심 기능을 위한 아키텍처적 토대를 마련하는 데 중점을 두었습니다. 이를 위해 새로운 크레이트와 CI 워크플로우를 도입하고, 기존 LEVM(Lambda EVM)에 JIT 관련 인프라를 통합하며, 프로젝트의 방향과 구현 세부 사항을 명확히 하는 광범위한 문서를 추가했습니다. 이 작업은 향후 Tokamak 클라이언트의 성능, 검증 가능성 및 디버깅 용이성을 향상시키기 위한 초석이 될 것입니다. Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Changelog
Ignored Files
Activity
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
이 PR은 Tokamak Ethereum 클라이언트의 기반을 마련하는 중요한 작업입니다. JIT 컴파일, 벤치마킹, 디버깅을 위한 새로운 크레이트(tokamak-jit, tokamak-bench, tokamak-debugger)를 도입하고, 기존 ethrex-levm에 JIT 인프라와 벤치마킹을 위한 접근자 메소드를 추가했습니다. 또한, 기능별로 분리된 tokamak-* 피처 플래그와 CI 워크플로우를 설정하여 프로젝트의 구조를 체계적으로 잡았습니다. 전반적으로 코드 품질이 높고, 아키텍처에 대한 깊은 고민이 엿보입니다. 몇 가지 유지보수성 및 잠재적 메모리 누수와 관련된 개선점을 제안했지만, 이는 이 훌륭한 기반 작업의 가치를 훼손하지 않습니다.
| // SAFETY: The compiled function pointer is stored in CompiledCode | ||
| // which is kept alive in the CodeCache. The LLVM JIT memory backing | ||
| // the function is not freed (no `free_function` call in PoC). | ||
| #[expect(unsafe_code)] | ||
| let f: EvmCompilerFn = unsafe { | ||
| compiler | ||
| .jit(&hash_hex, bytecode, SpecId::CANCUN) | ||
| .map_err(|e| JitError::CompilationFailed(format!("{e}")))? | ||
| }; |
There was a problem hiding this comment.
안전성 주석에 "no free_function call in PoC"라고 언급되어 있는데, 이는 컴파일된 코드가 메모리에서 해제되지 않아 메모리 누수가 발생할 수 있음을 시사합니다. PoC 단계에서는 괜찮을 수 있지만, 프로덕션 환경에서는 반드시 해결해야 할 문제입니다. 향후 JIT 코드 캐시에서 엔트리가 제거될 때 (예: LRU 정책에 의해) 컴파일된 함수 메모리도 함께 해제하는 메커니즘을 설계해야 합니다. revmc가 컴파일된 함수를 해제하는 API를 제공하는지 확인하고, 이를 CodeCache의 invalidate나 Drop 구현과 연동하는 것을 고려해야 합니다.
| #![allow( | ||
| clippy::arithmetic_side_effects, | ||
| clippy::as_conversions, | ||
| clippy::type_complexity | ||
| )] |
There was a problem hiding this comment.
Tokamak Benchmark Results: BaselineNo baseline benchmark found on the base branch. |
Benchmark Results ComparisonNo significant difference was registered for any benchmark run. Detailed ResultsBenchmark Results: BubbleSort
Benchmark Results: ERC20Approval
Benchmark Results: ERC20Mint
Benchmark Results: ERC20Transfer
Benchmark Results: Factorial
Benchmark Results: FactorialRecursive
Benchmark Results: Fibonacci
Benchmark Results: FibonacciRecursive
Benchmark Results: ManyHashes
Benchmark Results: MstoreBench
Benchmark Results: Push
Benchmark Results: SstoreBench_no_opt
|
Add Phase 3 JIT execution wiring so JIT-compiled bytecode actually runs through the VM dispatch instead of only being compiled. Key changes: - JitBackend trait in dispatch.rs for dependency inversion (LEVM defines interface, tokamak-jit implements) - LevmHost: revm Host v14.0 implementation backed by LEVM state (GeneralizedDatabase, Substate, Environment) - Execution bridge: builds revm Interpreter, wraps state in LevmHost, transmutes CompiledCode to EvmCompilerFn, maps result to JitOutcome - vm.rs wiring: try_jit_dispatch() && execute_jit() before interpreter loop, with fallback on failure - register_jit_backend() for startup registration - E2E tests: fibonacci JIT execution + JIT vs interpreter validation (behind revmc-backend feature, requires LLVM 21)
Close 7 gaps preventing production use of the JIT system: - 4A: Propagate is_static from CallFrame to revm Interpreter - 4B: Sync gas refunds after JIT execution, pass storage_original_values through JIT chain for correct SSTORE original vs present value - 4C: Add LRU eviction to CodeCache (VecDeque + max_entries) - 4D: Auto-compile when execution counter hits threshold, add compile() to JitBackend trait and backend() accessor to JitState - 4E: Detect CALL/CREATE/DELEGATECALL/STATICCALL opcodes in analyzer, skip JIT compilation for contracts with external calls - 4F: Skip JIT when tracer is active, add JitMetrics with atomic counters, log fallback events via eprintln
…compilation, and validation Phase 5 addresses three remaining JIT gaps: 5A — Multi-fork support: Cache key changed from H256 to (H256, Fork) so the same bytecode compiled at different forks gets separate cache entries. fork_to_spec_id() adapter added. Hardcoded SpecId::CANCUN removed from compiler, execution, and host — all now use the environment's fork. 5B — Background async compilation: New CompilerThread with std::sync::mpsc channel and a single background thread. On threshold hit, vm.rs tries request_compilation() first (non-blocking); falls back to synchronous compile if no thread is registered. register_jit_backend() now also starts the background compiler thread. 5C — Validation mode wiring: JitConfig.max_validation_runs (default 3) gates logging to first N executions per (hash, fork). JitState tracks validation_counts and logs [JIT-VALIDATE] with gas_used and output_len for offline comparison. Full dual-execution deferred to Phase 6.
M1: CompilerThread now implements Drop — drops sender to signal
shutdown, then joins the background thread. Panics are caught
and logged (no silent swallowing). Fields changed to Option
for take-on-drop pattern.
M2: SELFDESTRUCT (0xFF) added to has_external_calls detection in
analyzer.rs. Bytecodes containing SELFDESTRUCT are now skipped
by the JIT compiler, preventing the incomplete Host::selfdestruct
(missing balance transfer) from being exercised.
M3: Negative gas refund cast fixed in execution.rs. Previously
`refunded as u64` would wrap negative i64 (EIP-3529) to a huge
u64. Now uses `u64::try_from(refunded)` — negative values are
silently ignored (already reflected in gas remaining).
M4: Documented fork assumption in counter.rs and vm.rs. Counter is
keyed by bytecode hash only (not fork). Safe because forks don't
change during a node's runtime; cache miss on new fork falls back
to interpreter.
… flag (F-3) - TokamakFeeConfig + JitPolicy types (crates/common) - TokamakL2Hook wrapping L2Hook via composition (crates/vm/levm) - VMType::TokamakL2 variant + hook dispatch + Evm constructors - BlockchainType::TokamakL2 + 5 match arm updates (blockchain.rs) - --tokamak-l2 CLI flag with env var support - Feature propagation across 6 Cargo.toml files - P256Verify precompile extended via is_l2_type() helper - 7 unit tests (4 fee config serde + 3 hook)
Test coverage (+28 tests across 3 crates): - tokamak-jit: SELFDESTRUCT E2E tests (basic, self-target, nonexistent, double, gas) — 31→36 - tokamak-bench: runner/regression/report edge cases (load_bytecode, empty baseline, zero-div, no-stats) — 35→48 - tokamak-debugger: error handling (revert, stop, OOG, empty bytecode) + recorder edge cases (empty/partial/zero stack capture) — 18→28 F-5 Mainnet Full Sync CI: - Add mainnet option to tokamak-sync.yaml (48h timeout) - Use ethrex-sync self-hosted runner for mainnet (6h GitHub-hosted limit insufficient) - Conditional Kurtosis install (GitHub-hosted) vs Docker cleanup (self-hosted) - Dynamic runner selection via matrix.runner field
Add a /compare page with JIT speedup trend chart and cross-client performance table. Extend landing page with JIT Speedup and Cross-Client sections. Generate cross-client fixture data for all 7 dates with realistic Geth/Reth ratios. New components: JitSpeedupTable, CrossClientTable, CompareView New data function: fetchCrossClientSuite Tests: 76 pass (was 62), 3 pages build (was 2)
…ycle (G-1)
Introduces an arena allocator that groups JIT-compiled functions by LLVM
context. When all functions in an arena are evicted from the cache, the
arena and its LLVM resources are freed — eliminating the 1-5 MB per
compilation memory leak caused by std::mem::forget(compiler).
Key changes:
- arena.rs: ArenaManager, ArenaEntry, FuncSlot types with CAS-based
concurrent eviction tracking (12 tests incl. 100-thread stress)
- compiler.rs: ArenaCompiler stores compilers instead of leaking them;
compile_in_arena() alongside existing compile() for backward compat
- lib.rs: thread_local ArenaState in background compiler handler manages
arena rotation, eviction-triggered freeing, and FreeArena requests
- cache.rs: func_id → arena_slot; insert() returns Option<FuncSlot>
- compiler_thread.rs: Free{slot} and FreeArena{arena_id} request variants
- dispatch.rs: JitState gains arena_manager field + send_free/send_free_arena
- types.rs: JitConfig +arena_capacity/max_arenas/max_memory_mb;
JitMetrics +arenas_created/arenas_freed/functions_evicted
… STATUS Add Phase G section to ROADMAP-REMAINING.md with full G-1 entry, update STATUS.md architecture decision (mem::forget → arena allocator), bump overall completion to ~92%. Also fix minor unused-variable warnings in compiler_thread.rs and storage.rs caught during verification.
…odes (G-3) Remove the `!compiled.has_external_calls` guard that skipped validation for bytecodes containing CALL/CREATE/DELEGATECALL/STATICCALL. The interpreter replay handles sub-calls natively, so the state-swap mechanism works correctly for all bytecodes. - vm.rs: remove has_external_calls guard from needs_validation condition - dual_execution.rs: add 5 G-3 tests (CALL, STATICCALL, DELEGATECALL, pure regression, combined metrics), extract shared MismatchBackend, setup_call_vm() helper, make_external_call_bytecode() builder (1258→751 lines, -40%) - docs: mark G-2 complete (auto-resolved by G-1 arena system)
…on report JIT-LIMITATIONS-ROADMAP.md: G-1~G-8 resolution roadmap with severity tiers, solution options, acceptance criteria, and dependency graph. THREE-PILLARS.md: Completion report covering JIT compiler (~80%), continuous benchmarking (~80%), and time-travel debugger (~85%) with 15,507 lines of code and 332 tests across all three pillars.
Add 16 new binary opcodes (DIV, SDIV, MOD, SMOD, EXP, SIGNEXTEND, LT, GT, SLT, SGT, EQ, SHL, SHR, SAR) and 2 unary opcodes (NOT, ISZERO) to the bytecode constant folding optimizer. Each opcode replicates exact LEVM semantics including signed arithmetic helpers, divide-by-zero returning 0, and shift >= 256 returning 0. Extract eval_op arms into named helpers (eval_sdiv, eval_smod, eval_signextend, signed_compare, eval_sar, eval_shift) reducing eval_op from 120 to 25 lines. Extract shared bytecode rewrite logic into write_folded_push() eliminating duplication between binary and unary fold loops (optimize: 100 → 44 lines). 68 optimizer unit tests (31 new), 8 integration tests (3 new), proptest convergence check updated for unary patterns.
Replace single-threaded CompilerThread (std::sync::mpsc) with multi-worker CompilerThreadPool using crossbeam-channel for MPMC work distribution. Default worker count: num_cpus/2 (minimum 1). Key changes: - CompilerThreadPool with configurable N workers (crossbeam-channel) - Deduplication guard (compiling_in_progress FxHashSet) prevents duplicate compilations across workers - CompilationGuard drop struct for panic-safe dedup cleanup - compile_workers field in JitConfig - 4 new integration tests, 48 total tokamak-jit tests passing
…UDIT - ROADMAP-REMAINING: G-7 section + D-3 cross-reference + execution timeline - STATUS: G-7 feature bullet + recently completed entry - JIT-LIMITATIONS-ROADMAP: G-1/G-2/G-3/G-5/G-7 marked DONE, updated severity overview, execution order, timeline (5/8 done, 44-66h remaining) - THREE-PILLARS: limitation tables updated to reflect completions, Pillar 1 ~88%, constant folding expanded to 22 opcodes - SAFETY_AUDIT: added optimizer scope section documenting G-7 expansion (22 opcodes, signed arithmetic safety, wrapping/checked operations) - proptest-regressions: preserve discovered regression test case
…s (G-4) When a JIT-compiled parent contract hits CALL, the VM now checks if the child bytecode is also in the JIT cache and executes it directly via JitState.execute_jit(), bypassing the full LEVM interpreter dispatch. Key design decisions: - VM-layer fast dispatch (no revmc upstream changes needed) - Cache lookup at dispatch time via try_jit_dispatch() — O(1) - CREATE excluded (init code needs validate_contract_creation) - Precompile addresses always bypass JIT dispatch - JIT errors in child treated as revert (state may be mutated) - Configurable via enable_jit_dispatch config (default: true) - Observable via jit_to_jit_dispatches metric in JitMetrics Phase 2 (v1.1 SIGNIFICANT) is now ALL RESOLVED: G-3, G-4, G-5. security-scan: pass
…stamps (G-6) Replace VecDeque-based FIFO eviction in JIT code cache with per-entry AtomicU64 timestamps for LRU eviction. The get() hot path uses only a read lock plus two atomic ops (~2-5ns overhead), while eviction runs an O(n) min_by_key scan under write lock on insert(). - Add CacheEntry struct wrapping CompiledCode + AtomicU64 last_access - Move access_counter Arc<AtomicU64> outside RwLock for lock-free get() - Evict least-recently-used entry on capacity overflow (not oldest inserted) - Return evicted entry's FuncSlot for arena memory reclamation - Add 9 cache unit tests + 5 integration tests (53 total tokamak-jit tests) - Update SAFETY_AUDIT.md: resolve LRU eviction recommendation
When JIT-compiled code suspends on a CALL to a precompile address, handle_jit_subcall() already executes the precompile inline without creating a full child call frame. G-8 adds observability and config: - Add precompile_fast_dispatches AtomicU64 metric to JitMetrics - Add enable_precompile_fast_dispatch config toggle to JitConfig - Track metric in handle_jit_subcall() precompile arm (vm.rs) - Add is_precompile_fast_dispatch_enabled() to JitState - 9 tests: 5 interpreter correctness + 4 JIT differential (58 total) - Update snapshot() return type from 7-tuple to 8-tuple
…udit after Phase G - STATUS.md: overall 94% → 99%, JIT 80% → 92% - THREE-PILLARS.md: tokamak-jit tests 73 → 58, debugger 45 → 55, summary table updated - ROADMAP-REMAINING.md: added commit hashes for G-6 (3b2861b) and G-8 (ccf34e6) - SAFETY_AUDIT.md: added G-5 parallel compilation and G-6 LRU cache eviction sections
Reduce per-CALL overhead in JIT suspend/resume cycles without modifying revmc. Three runtime-level optimizations target DeFi router patterns (5-10 CALLs per tx): - Tier 1: Bytecode zero-copy — cache Arc<Bytes> in CompiledCode at compile time, use Arc::clone in execute_jit instead of Bytes::copy_from_slice (~1-5us/CALL saved) - Tier 2: Resume state pool — thread-local pool of JitResumeStateInner boxes (16-entry cap) eliminates Box alloc/dealloc per suspend/resume - Tier 3: TX-scoped bytecode cache — FxHashMap<H256, Code> on VM avoids repeated db.get_code() for same contract in multi-CALL transactions Adds bytecode_cache_hits metric to JitMetrics (9-tuple snapshot). 11 new tests in recursive_call_opt.rs, 69 total tokamak-jit tests.
|
@cd4761 Please change the base branch of this PR from |
|
@cd4761 Please address the following items from the Gemini Code Assist review: High Priority:
Medium Priority:
|
|
@cd4761 The "PR title" CI check is failing because the scope Error:
Fix options:
|
…ntainability - CORS: restrict origin to Tauri dev/prod allowlist (Copilot #1) - open-url: use execFile with arg arrays instead of shell exec (Copilot #2) - fs browse: restrict path traversal to home directory (Copilot #3) - test-e2e-fork: move RPC URL to SEPOLIA_RPC_URL env var (Copilot #4) - docker-remote: clear timeout on stream close, close stream on timeout (Copilot #5) - docker-remote: add shell quoting (q()) and assertSafeName for all interpolated shell args to prevent injection (Copilot #6-8) - genesis.rs: add ChainConfig::validate() for pre-startup checks (Copilot #9) - listings.js: use named params (@id, @name, ...) instead of 30 positional ? args for upsertListing (Gemini #1)
…to-logout on 401 - Bug #1 (critical): getProgramById → getProgramByProgramId for slug lookup Pass program.id (UUID) to createDeployment and incrementUseCount - Bug #2: incrementUseCount now receives UUID instead of slug - Bug #3: fetch() headers properly merged (options can't overwrite auth) - Bug #8: auto-logout on 401 response (expired token)
- Add cross-platform keychain support: macOS uses `security` CLI, Windows/Linux uses `keyring` crate via cfg(target_os) (#1) - Restore keychain key validation with allowed prefixes (pinata_, deployer_pk_, ai-) for security boundary (#3) - Add warning log to empty catch block in tools container status (#2) - Extract magic number 9 to LOCAL_L1_CHAIN_ID constant (#4)
- Add cross-platform keychain support: macOS uses `security` CLI, Windows/Linux uses `keyring` crate via cfg(target_os) (#1) - Restore keychain key validation with allowed prefixes (pinata_, deployer_pk_, ai-) for security boundary (#3) - Add warning log to empty catch block in tools container status (#2) - Extract magic number 9 to LOCAL_L1_CHAIN_ID constant (#4)
…te detection * fix(manager): prompt — download bridge UI source, reorder firewall before tools - Step 6: download bridge UI source files (Dockerfile, HTML, entrypoint.sh) from GitHub before tools compose up (fixes build path not found) - Move firewall (Step 7→6) before tools (Step 6→7) so ports are open for external monitoring before tools deployment - Public URLs already set via VM_IP metadata for dashboard Explorer links * feat(manager): auto-detect deployment success + save & complete button - Monitor: when all services are healthy, show success message with URLs - "배포 완료 — 정보 저장" button saves IP/port to DB, sets phase=running - Navigates to dashboard detail view after save - Guide text: "아래 버튼을 누르면 대시보드 화면으로 이동합니다" * feat(messenger): Open Appchain public interface — API integration, metadata push, publish UX - Replace mock data in OpenL2View with Platform API (getPublicAppchains) - Add registration modal for external appchain publishing (name, RPC, chain ID) - OpenL2DetailView: real screenshots (IPFS), RPC status check, reviews/comments/announcements - L2DetailPublishTab: allow description/screenshots/social links input before publish toggle - Platform server: metadata-push.js — push/delete metadata to GitHub repo via Contents API - New routes: POST /deployments/:id/push-metadata, /delete-metadata - Debounced metadata push (5s) after description/screenshot/social link saves - Security: name length validation, status escalation guard, commit message sanitization, 409 retry - i18n: loading/error/retry/nativeToken/rating/reviews/comments/noScreenshots/announcements - Tests: 24 unit tests (metadata-push), e2e-store.js (11-step lifecycle test) * fix(messenger): add save button for publish tab — persist draft to localStorage before publish * fix(messenger): block publishing with localhost RPC URL — require publicly accessible endpoint * fix(messenger): fix publish toggle disabled for non-local appchains — remove false localhost check * feat(platform): server-side screenshot upload — no Pinata required - POST /api/deployments/:id/screenshots — multer-based image upload (5MB, images only) - platformAPI.uploadScreenshots() — FormData upload to Platform server - L2DetailPublishTab: use server upload when platformId exists, IPFS fallback, data URL fallback - Remove Pinata requirement for screenshot upload button * fix(messenger): detect AWS deployments correctly — show AWS badge, fix L1 chain ID, enable publishing - networkMode detection: config.mode > host_id (AWS) > l1_chain_id > local - L1 chain ID: read from DB l1_chain_id field first, then config fallback - Add AWS (orange), Mainnet (green) badges alongside existing Testnet/Local - Add hostId, publicRpcUrl, deployMethod to L2Config interface * fix(messenger): allow publishing when public URL or remote host exists, not just by networkMode * fix(messenger): add missing DB fields (l1_chain_id, host_id, public_l2_rpc_url) to DeploymentRow - Rust: add l1_chain_id, host_id, platform_deployment_id, public_l2_rpc_url, public_domain to SELECT - TS: add matching fields to DeploymentFromDB interface - Now AWS deployments show correctly (not as Local), L1 Chain ID displays properly * fix(messenger): correct networkMode detection — use l1_port to distinguish local vs testnet - l1_port exists → local (has bundled L1 node in Docker) - host_id exists → AWS (remote deployment) - l1_chain_id exists but no l1_port → testnet (external L1) - Fixes: local Docker showing as Testnet, AWS showing as Local * fix(messenger): detect AWS via config.cloud, read l1ChainId from config fallback * docs: add deployment network mode detection documentation * fix(manager): fix status showing stopped for AI-deploy local Docker — distinguish remote vs local - AI Deploy with ec2IP → SSH remote status check - AI Deploy without ec2IP (local Docker) → local docker compose ps - Remote host deployments → SSH status check - Fixes: local Docker containers showing as stopped, (pending) hostname * fix(messenger): use l2.programSlug for publish instead of non-existent 'ethrex-appchain' - Fixes 'Load failed' error when publishing — Platform has no 'ethrex-appchain' program - L2DetailPublishTab: programId = l2.programSlug || 'evm-l2' - OpenL2View registration modal: programId = 'evm-l2' - Rename labels: '오픈 앱체인 공개' → '앱체인 공개 설정' * fix: critical publish bugs — program lookup by slug, header merge, auto-logout on 401 - Bug #1 (critical): getProgramById → getProgramByProgramId for slug lookup Pass program.id (UUID) to createDeployment and incrementUseCount - Bug #2: incrementUseCount now receives UUID instead of slug - Bug #3: fetch() headers properly merged (options can't overwrite auth) - Bug #8: auto-logout on 401 response (expired token) * feat(messenger): make Platform URL configurable via VITE_PLATFORM_URL env var * feat(messenger): metadata registry submission with auto register/update detection - Add appchain-registry API client with check/submit/status endpoints - Auto-detect register vs update by checking existing file on GitHub main branch - Preserve immutable fields (l2ChainId, nativeToken, createdAt) on updates - Fetch actual chain ID from L2 RPC (eth_chainId) for accuracy - Map social links to correct schema fields (website → top-level, twitter → xUrl, etc.) - Fix bridges.url empty string validation failure (omit if no dashboardUrl) - Add GitHub PR title/body update when resubmitting to existing open PR - Add keychain-based metadata signing (SECURITY_COUNCIL role) - Open PR links in external browser via Tauri shell plugin * fix(messenger): include dashboard URL in metadata — fallback to port 3000 for remote deployments * fix(platform): sync metadata schema fields — resolve URLs from supportResources, explorers, bridges listings.js was reading legacy top-level fields (dashboardUrl, explorerUrl, bridgeUrl) that don't exist in the new appchain metadata schema. Now reads from: - supportResources.dashboardUrl → dashboard_url - explorers[0].url → explorer_url - bridges[0].url → bridge_url - top-level website → operator_website - supportResources xUrl/communityUrl/telegramUrl/documentationUrl → social_links * fix: address PR #66 code review feedback - Add cross-platform keychain support: macOS uses `security` CLI, Windows/Linux uses `keyring` crate via cfg(target_os) (#1) - Restore keychain key validation with allowed prefixes (pinata_, deployer_pk_, ai-) for security boundary (#3) - Add warning log to empty catch block in tools container status (#2) - Extract magic number 9 to LOCAL_L1_CHAIN_ID constant (#4) * fix: address Copilot PR #66 review feedback - Fix signing message indentation bug — spaces before each line caused signature mismatch with server (array.join instead of multiline string) - Fix saveDraft stale state — pass fresh result to avoid missing prNumber - Add NaN timestamp validation in submit endpoint - Add rate limit map cleanup to prevent unbounded memory growth - Strict address validation in getRepoFilePath (0x + 40 hex chars) - findOpenPR verifies actual PR files instead of title-only matching - Remove .deployed-*-tools.env from tracking, add to .gitignore
- Return 503 instead of {exists:false} on check endpoint errors (#1)
- Sanitize all error messages — log internally, return generic to client (#2,#3,#4,#5)
- Add serverless rate limit limitation comment (#6)
- Add console.warn to all empty catch blocks in github-pr.ts (#9,#10,#11)
- Note: params as Promise is correct for Next.js 15 (#7,#8)
* feat(platform): add appchain registry API routes to Next.js client Port Express server appchain-registry endpoints to Next.js API routes for Vercel deployment: - GET /api/appchain-registry/check/[l1ChainId]/[stackType]/[identityAddress] - POST /api/appchain-registry/submit - GET /api/appchain-registry/status/[prNumber] Shared logic in lib/appchain-registry.ts and lib/github-pr.ts. * fix: address PR #67 code review feedback - Return 503 instead of {exists:false} on check endpoint errors (#1) - Sanitize all error messages — log internally, return generic to client (#2,#3,#4,#5) - Add serverless rate limit limitation comment (#6) - Add console.warn to all empty catch blocks in github-pr.ts (#9,#10,#11) - Note: params as Promise is correct for Next.js 15 (#7,#8) * fix: address additional Copilot PR #67 review feedback - Add AbortSignal.timeout(15s) to all GitHub API fetch calls - Fix authHeaders error message to list both accepted env vars - Distinguish RPC errors (502) from permission denied (403) in ownership check - Add typeof validation for metadata.signedBy - Add unit test suggestion acknowledged (future work)
Summary
Complete Tokamak JIT compilation infrastructure for the ethrex Ethereum client. This branch implements a tiered JIT execution system using revmc/LLVM 21, adding ~11K lines of Rust across 4 new crates and LEVM integration modules.
Key Features
tokamak-jit): revmc/LLVM 21 backend with tiered compilation (counter threshold → compile → execute), multi-fork support, arena-based memory lifecycle (G-1), LRU cache eviction (G-6), parallel compilation pool (G-5)tokamak-debugger): Per-opcode replay engine with GDB-style CLI anddebug_timeTravelJSON-RPC endpointtokamak-bench): 12 scenarios, JIT speedup regression detection CI, cross-client comparison (vs Geth/Reth)VMType::TokamakL2,TokamakL2Hook,BlockchainType::TokamakL2with feature flag propagationJIT Benchmark Results
Phase Completion
Codebase
crates/vm/levm/src/jit/crates/vm/tokamak-jit/src/crates/tokamak-bench/src/crates/tokamak-debugger/src/CI Verification
Commit History (104 commits)
Phases 0-1: Foundation, architecture docs, feature flags, CI workflows
Phase 2: JIT compiler infrastructure (revmc adapter, LEVM integration)
Phase 3-6: Execution wiring, production hardening, CALL/CREATE resume
Phase 7: Dual-execution validation
Phase 8-9: Benchmarking infrastructure, CI regression detection
Phase A: Hive 6/6 PASS, Hoodi sync PASS, feature flag safety
Phase B: Gas alignment, BAL recording, test quality
Phase C: LLVM 21 provisioning, benchmark statistics
Phase D: Bytecode size limit, constant folding optimizer
Phase E: Time-travel debugger (engine, CLI, RPC)
Phase F: Cross-client benchmarks, dashboard, L2 scaffolding, security audit
Phase G: Arena allocator, CALL/CREATE validation, parallel compilation, JIT-to-JIT dispatch, LRU cache, constant folding enhancement, precompile fast dispatch
Test plan
cargo test -p tokamak-jit -- --test-threads=1(58 tests)cargo test -p tokamak-bench(48 tests)cargo test -p tokamak-debugger --features cli(45 tests)cargo clippy -p tokamak-jit -p tokamak-bench -p tokamak-debugger