Skip to content

Conversation

@dimazhornyk
Copy link
Contributor

@dimazhornyk dimazhornyk commented Oct 30, 2025

This PR adds a JS tracer implementation.
It uses Boa JS runtime to call the JS functions when zksync-os execution triggers a corresponding hook.

State access is implemented by using the captured StateView and storage overlays in the JS context.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added JavaScript-based EVM transaction tracing with advanced debugging capabilities, including state inspection and call stack tracking.
    • Enabled state override support for transaction debugging and tracing operations.
    • Enhanced contract instrumentation with calculation event logging and result tracking.
  • Tests

    • Added comprehensive integration tests for JavaScript tracer validation across multiple scenarios and node configurations.

✏️ Tip: You can customize this high-level summary in your review settings.

@github-actions
Copy link

github-actions bot commented Oct 30, 2025

Test results

164 tests   164 ✅  12m 31s ⏱️
 23 suites    0 💤
  1 files      0 ❌

Results for commit 1aded93.

♻️ This comment has been updated with latest results.

@0xVolosnikov
Copy link
Contributor

Would be nice to compare it to the Geth/Reth implementation somehow - it's very easy to introduce some divergence in some obscure corner case

@0xVolosnikov
Copy link
Contributor

0xVolosnikov commented Oct 31, 2025

Also, do we want to limit this functionality somehow?

  • Protect from DDoS spamming trace requests
  • Reject huge / malicious JS payloads?

@dimazhornyk
Copy link
Contributor Author

Would be nice to compare it to the Geth/Reth implementation somehow - it's very easy to introduce some divergence in some obscure corner case

Yeah, I was also concerned about it. Maybe we can add an integration test that would send a set of requests to our node and the Reth node and compare the outputs.

@dimazhornyk
Copy link
Contributor Author

Also, do we want to limit this functionality somehow?

  • Protect from DDoS spamming trace requests
  • Reject huge / malicious JS payloads?

I didn't consider it, but it definitely makes sense. I will think about it

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 21, 2025

Walkthrough

This PR introduces JavaScript-based EVM tracing via Boa JavaScript engine integration, updates multiple dependencies to newer rc and patch versions (notably zksync-os components and adding boa_engine/boa_gc), and extends test coverage with cross-node tracer comparisons and contract state tracking functionality.

Changes

Cohort / File(s) Summary
Dependency Updates
Cargo.toml, lib/rpc/Cargo.toml
Updated zksync-os component versions (0.0.9→0.0.10, v0.1.0→v0.1.0-rc1, v0.2.2→v0.2.3). Added boa_engine, boa_gc, zk_os_evm_interpreter, and serde_json as dependencies.
Core JS Tracer Implementation
lib/rpc/src/js_tracer/mod.rs, lib/rpc/src/js_tracer/tracer.rs, lib/rpc/src/js_tracer/host.rs, lib/rpc/src/js_tracer/types.rs, lib/rpc/src/js_tracer/utils.rs
New module structure with JsTracer struct managing Boa context and state overlays; EvmTracer trait implementation; host environment bootstrapping with method dispatch (getBalance, getNonce, getCode, getState, exists); comprehensive overlay/checkpoint system for transactional state tracking; utility functions for gas calculation, address parsing, and JS config extraction.
RPC Integration
lib/rpc/src/lib.rs, lib/rpc/src/debug_impl.rs, lib/rpc/src/eth_call_handler.rs, lib/rpc/src/sandbox.rs
Exposed pub mod js_tracer; added CallConfig import and multi-branch tracer support (CallTracer and JsTracer) in debug tracing; introduced call_js_tracer_impl method and CallTracerError variant in EthCallHandler; increased visibility of helper functions (maybe_revert_reason, fmt_error_msg).
OS Component Path Updates
lib/multivm/src/apps/mod.rs
Replaced include_bytes! environment variable keys from ZKSYNC_OS_0_1_0_SOURCE_PATH→ZKSYNC_OS_0_1_0_RC1_SOURCE_PATH and ZKSYNC_OS_0_2_2_SOURCE_PATH→ZKSYNC_OS_0_2_3_SOURCE_PATH.
Library Maintenance
lib/genesis/src/lib.rs, lib/revm_consistency_checker/src/helpers.rs
Replaced digest.as_slice() with digest.as_ref() in load_genesis_upgrade_tx; updated error formatting syntax from positional to named debug formatting.
Test Contracts & Infrastructure
integration-tests/test-contracts/src/TracingPrimary.sol, integration-tests/tests/js_tracer_cross_node.rs, integration-tests/tests/tracing.rs
Added lastCalculated state variable and CalculationDone event to TracingPrimary; modified calculate() to emit events; new cross-node JS tracer test with helper utilities (configure_call_request, trace_with_js, normalize_hex_strings); extended tracing test suite with geth-style tracer configurations and output validation.
Build Formatting
node/bin/src/batcher/mod.rs
Updated error message formatting in ensure! assertion from positional to named format syntax.

Sequence Diagram

sequenceDiagram
    participant Caller
    participant RPC as RPC Layer
    participant EthCall as EthCallHandler
    participant JsTracer as JsTracer
    participant Boa as Boa Context
    participant Host as Host Environment
    participant State as State View

    Caller->>RPC: debug_trace_call (with JsTracer config)
    RPC->>EthCall: call_js_tracer_impl()
    EthCall->>JsTracer: new(state_view, js_cfg)
    JsTracer->>Boa: Create context
    JsTracer->>Host: init_host_env_in_boa_context()
    Host->>Host: install_host_bindings(__hostCall)
    Host->>Host: install_db_wrapper()
    Host->>Boa: bootstrap_tracer(source)
    
    EthCall->>JsTracer: execute transaction (EVM hooks)
    loop EVM Execution Steps
        JsTracer->>Boa: before_step / after_step hooks
        Boa->>Host: invoke __hostCall(method, payload)
        Host->>Host: dispatch_host_call()
        Host->>State: resolve balance/code/storage
        State-->>Host: state data
        Host-->>Boa: JSON result
    end
    
    JsTracer-->>EthCall: JsonValue trace output
    EthCall-->>RPC: trace result
    RPC-->>Caller: traced execution
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • js_tracer/tracer.rs — Dense state management with frame stack, overlay commits/rollbacks, and multiple hook implementations; non-trivial lifecycle transitions and error propagation
  • js_tracer/host.rs — Complex host-method dispatch, state resolution with fallback chains, balance delta arithmetic with overflow checks, and Rust-to-JS error bridging
  • js_tracer/types.rs — Intricate overlay checkpoint/revert mechanism with journaling; OverlayState<K,V> generics and transactional semantics require careful verification
  • debug_impl.rs & eth_call_handler.rs — Integration points must correctly route CallTracer vs JsTracer paths; state override handling consistency across both paths
  • Integration tests — Cross-node comparison logic with hex normalization; complex setup and teardown for dual-provider environments
  • Dependency alignment — Multiple version updates across 9+ components; verify semver compatibility and feature interactions (especially Boa integration)

Poem

🐰 A tracer swift with JavaScript grace,
Through overlays and state we race,
Boa's engine powers the way,
EVM secrets we can display,
From zksync lands, new versions play! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 17.24% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Description check ❓ Inconclusive The description briefly explains the JS tracer implementation but is minimal and lacks structured detail; the template's summary section requires more comprehensive explanation of the problem being solved. Expand the summary to explain the purpose and benefits of the JS tracer, or clarify what problem it addresses in the zkSync ecosystem.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: JS tracer' clearly describes the main feature added—a JavaScript tracer implementation—and follows conventional commit format.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat-js-tracer

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
lib/rpc/src/sandbox.rs (1)

443-471: Small typo in MemoryLimitOOG error message.

The formatted string currently has an extra closing parenthesis ("out of gas (memory limit reached {}))"). Consider fixing it while you’re here.

-        EvmError::MemoryLimitOOG => format!("out of gas (memory limit reached {}))", u32::MAX - 31),
+        EvmError::MemoryLimitOOG => {
+            format!("out of gas (memory limit reached {})", u32::MAX - 31)
+        }
♻️ Duplicate comments (1)
integration-tests/tests/tracing.rs (1)

608-608: Remove leftover debug print

println!("{:?}", trace); is still sitting here from debugging and will spam the test logs. Let’s drop it before merging.

🧹 Nitpick comments (6)
lib/rpc/src/lib.rs (1)

19-19: Confirm that making js_tracer public is the desired API surface.

Exporting js_tracer from the crate root exposes the JS tracing types to external crates. If this is still experimental or primarily internal, consider pub(crate) or re‑exporting only a narrow façade (e.g., selected entry points) instead.

lib/rpc/src/debug_impl.rs (2)

31-112: Tracer selection in debug_trace_block_by_id_impl looks correct; consider richer error reporting and JS safeguards.

Dispatching between the built‑in call tracer and JS tracer based on the requested tracer type is clean, and the per‑tx mapping into TraceResult with attached hashes is correct. Right now, any tracing failure (both built‑in and JS) is logged and surfaced as a generic InternalError; if you want closer geth/reth parity and easier debugging, consider:

  • Converting failures into TraceResult::Error with a trimmed message, or
  • At least embedding the underlying error message into the InternalError text.

Given the Boa‑based JS tracer can be relatively heavy and receives untrusted input, it’s also worth thinking about limits here (or in the js_tracer/EthCallHandler layer): e.g. maximum JS tracer payload size, capped tx ranges per request, or other guardrails to reduce the blast radius of expensive debug calls.


144-193: debug_trace_call_impl branching between built‑in and JS tracers is consistent with block tracing.

The call‑tracer path derives a config from the tracer options and delegates to EthCallHandler, and the JS path reuses the same plumbing via call_js_tracer_impl, returning a GethTrace::JS result, which keeps behavior aligned with block‑level tracing. Similar to the block path, consider:

  • Validating JS tracer payload size and shape early (before hitting the engine), and
  • Ensuring JS tracer runtime errors are surfaced to clients in a debuggable form rather than being overly generic, subject to whatever constraints you have on the external API.
lib/rpc/src/js_tracer/host.rs (1)

332-339: Consider optimizing the storage overlay check.

The storage overlay is checked by iterating over all keys (lines 333-338). For large overlays, this could be inefficient. If this becomes a performance bottleneck, consider maintaining a separate set of addresses that have storage entries.

lib/rpc/src/js_tracer/tracer.rs (1)

462-472: Consider continuing stack dump after errors.

If stack.peek_n(idx) fails (line 465), the loop breaks and the stack dump is incomplete (line 469). Depending on the tracer's needs, consider using a placeholder value (e.g., "<error>") and continuing the dump, so the tracer receives a complete (albeit partial) stack representation.

lib/rpc/src/js_tracer/types.rs (1)

218-226: Simplify commit_map - retain is a no-op.

The retain call always returns true (line 224), so no entries are ever removed. Consider using a simple iteration instead:

-    fn commit_map(map: &mut HashMap<K, OverlayEntry<V>>) {
-        map.retain(|_, entry| {
-            if !entry.committed {
-                entry.committed = true;
-                entry.previous = None;
-            }
-            true
-        });
-    }
+    fn commit_map(map: &mut HashMap<K, OverlayEntry<V>>) {
+        for entry in map.values_mut() {
+            if !entry.committed {
+                entry.committed = true;
+                entry.previous = None;
+            }
+        }
+    }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 33a7224 and 52aa5a0.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (18)
  • Cargo.toml (3 hunks)
  • integration-tests/test-contracts/src/TracingPrimary.sol (2 hunks)
  • integration-tests/tests/js_tracer_cross_node.rs (1 hunks)
  • integration-tests/tests/tracing.rs (2 hunks)
  • lib/genesis/src/lib.rs (1 hunks)
  • lib/multivm/src/apps/mod.rs (6 hunks)
  • lib/revm_consistency_checker/src/helpers.rs (1 hunks)
  • lib/rpc/Cargo.toml (3 hunks)
  • lib/rpc/src/debug_impl.rs (4 hunks)
  • lib/rpc/src/eth_call_handler.rs (5 hunks)
  • lib/rpc/src/js_tracer/host.rs (1 hunks)
  • lib/rpc/src/js_tracer/mod.rs (1 hunks)
  • lib/rpc/src/js_tracer/tracer.rs (1 hunks)
  • lib/rpc/src/js_tracer/types.rs (1 hunks)
  • lib/rpc/src/js_tracer/utils.rs (1 hunks)
  • lib/rpc/src/lib.rs (1 hunks)
  • lib/rpc/src/sandbox.rs (2 hunks)
  • node/bin/src/batcher/mod.rs (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (8)
integration-tests/tests/js_tracer_cross_node.rs (2)
integration-tests/src/lib.rs (1)
  • ProviderBuilder (279-279)
lib/rpc/src/js_tracer/tracer.rs (1)
  • new (74-107)
lib/rpc/src/eth_call_handler.rs (3)
lib/rpc/src/js_tracer/tracer.rs (1)
  • new (74-107)
lib/storage_api/src/state_override_view.rs (1)
  • new (26-34)
lib/multivm/src/lib.rs (1)
  • simulate_tx (86-138)
integration-tests/tests/tracing.rs (2)
integration-tests/src/lib.rs (1)
  • setup (68-70)
integration-tests/src/contracts.rs (3)
  • address (105-107)
  • address (138-140)
  • address (165-167)
lib/rpc/src/js_tracer/tracer.rs (5)
lib/rpc/src/js_tracer/host.rs (1)
  • init_host_env_in_boa_context (52-74)
lib/rpc/src/js_tracer/utils.rs (4)
  • extract_js_source_and_config (11-37)
  • gas_used_from_resources (7-9)
  • wrap_js_invocation (71-74)
  • serde_json (12-12)
lib/rpc/src/sandbox.rs (2)
  • fmt_error_msg (443-472)
  • maybe_revert_reason (422-438)
lib/rpc/src/js_tracer/types.rs (5)
  • new (162-167)
  • checkpoint (177-179)
  • credit (76-89)
  • debit (91-104)
  • new_pending (58-64)
lib/multivm/src/lib.rs (1)
  • run_block (22-84)
lib/rpc/src/js_tracer/utils.rs (1)
lib/rpc/src/js_tracer/tracer.rs (1)
  • new (74-107)
lib/rpc/src/js_tracer/host.rs (2)
lib/rpc/src/js_tracer/utils.rs (4)
  • format_hex_u256 (59-65)
  • parse_address (39-47)
  • parse_b256 (49-57)
  • anyhow_error_to_js_error (67-69)
lib/rpc/src/js_tracer/tracer.rs (1)
  • new (74-107)
lib/rpc/src/debug_impl.rs (2)
lib/rpc/src/sandbox.rs (1)
  • call_trace (67-91)
lib/rpc/src/js_tracer/tracer.rs (2)
  • trace_block (873-898)
  • new (74-107)
lib/rpc/src/js_tracer/types.rs (1)
lib/rpc/src/js_tracer/tracer.rs (1)
  • new (74-107)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: build-prover-tests
  • GitHub Check: build
  • GitHub Check: test
  • GitHub Check: format-and-lint
  • GitHub Check: cargo-audit
🔇 Additional comments (19)
node/bin/src/batcher/mod.rs (1)

351-355: Error message refactor is clear and correct

The anyhow::ensure! condition is unchanged, and the new named-format message is valid, more readable, and less error‑prone than positional arguments. No further changes needed here.

lib/revm_consistency_checker/src/helpers.rs (1)

125-125: LGTM! Modern Rust formatting with better error context.

The inline format argument {e:?} is cleaner than the older style with separate arguments, and the descriptive prefix "Failed to build TxEnv: " improves error diagnostics.

lib/multivm/src/apps/mod.rs (2)

1-153: Clarify the relationship between binary version updates and the JS tracer feature.

The PR description mentions implementing a JavaScript tracer with Boa runtime and state access hooks, but this file only updates zksync-os binary dependency versions. Could you clarify how these binary version updates relate to the JS tracer functionality? Do the new binaries (v4 RC1 and v5 0.2.3) include hooks or support required for the JS tracer?


83-83: <!-- [scratchpad_start]
[task review_verify_env_var_migration_final]
Verification complete. All checks passed.

[observations]

  • Cargo.toml workspace dependencies: forward_system at v0.2.3 ✅
  • build.rs auto-generates ZKSYNC_OS_{version}_SOURCE_PATH from git tag ✅
  • apps/mod.rs all three occurrences (lines 83, 107, 131) use ZKSYNC_OS_0_2_3_SOURCE_PATH ✅
  • No references to old ZKSYNC_OS_0_2_2_SOURCE_PATH remain ✅

[analysis]

  • Original review asked to verify build system configuration
  • Verification shows the system is AUTOMATICALLY configured via:
    1. Cargo.toml dependency tag update (v0.2.3)
    2. build.rs dynamically generates env var from tag
    3. apps/mod.rs correctly references generated var
  • No manual CI/CD configuration needed - this is self-contained in build.rs
  • Migration is complete and correct across all three v5 binary paths
  • Build will succeed with this configuration

[conclusion]
All concerns from original review have been addressed:

  • Build system IS configured (via Cargo.toml dependency tag)
  • Environment variable IS properly set up (auto-generated by build.rs)
  • Code correctly references the new variable name
  • No breaking changes or missing dependencies

[status DONE]

No further action required—build system is properly configured.

The environment variable migration has been correctly implemented. Verification confirms:

  • Cargo.toml workspace dependencies updated to tag = "v0.2.3" for forward_system, zk_ee, and zk_os_basic_system
  • build.rs automatically generates ZKSYNC_OS_0_2_3_SOURCE_PATH from the v0.2.3 git tag (v0.2.3 → 0_2_3 → env var name)
  • apps/mod.rs correctly references the new variable at all three locations (lines 83, 107, 131)
  • Old variable (ZKSYNC_OS_0_2_2_SOURCE_PATH) completely removed with no dangling references

The build system is self-configuring: dependency tag changes in Cargo.toml automatically trigger correct env var generation via build.rs, requiring no manual CI/CD or environment variable setup.

lib/genesis/src/lib.rs (1)

353-356: No functional change in digest handling; usage is correct.

Switching to digest.as_ref() still yields a 32‑byte slice for copy_from_slice, so the digest→[u8; 32] conversion remains safe and unchanged in behavior.

lib/rpc/src/sandbox.rs (1)

421-438: Crate‑level exposure of maybe_revert_reason preserves semantics.

Returning None on decode failure or empty reasons is still the behavior, and making it pub(crate) cleanly enables reuse from other RPC modules.

lib/rpc/src/js_tracer/mod.rs (1)

1-4: JS tracer module visibility layering is sensible.

Keeping host, types, and utils crate‑private while exposing only tracer gives you a focused public surface and leaves room to evolve internals.

Cargo.toml (1)

71-99: Workspace dependency bumps and JS‑tracer crates are coherently aligned.

Verification confirms no lingering older version tags (v0.2.2) exist in Cargo.toml. The zk_os stack is consistently pinned to the v0.2.3 line, and Boa (boa_engine, boa_gc) are both at 0.21.0 at the workspace level, preventing version skew across crates.

lib/rpc/Cargo.toml (1)

24-47: Dependency wiring verified as correct.

All four dependencies are properly defined in the root Cargo.toml and correctly referenced via workspace = true in lib/rpc/Cargo.toml. Each dependency is actively used in lib/rpc/src/js_tracer/ code, confirming no dead or orphaned bindings. The workspace configuration aligns with repository practices.

lib/rpc/src/js_tracer/host.rs (3)

346-383: LGTM! Proper overflow/underflow handling.

The balance delta resolution correctly checks for overflow when applying additions and underflow when applying subtractions, with appropriate error messages.


223-243: The review's characterization of method inconsistency is inaccurate.

The actual code shows all three methods handle invalid address parsing identically—they all return default values ("0x0" for balance/nonce, "0x" for code). The methods only diverge when an account exists but isn't found in state: host_get_nonce and host_get_code error, while host_get_balance's behavior depends on the resolve_balance() function (not shown).

However, the underlying concern is valid: geth's getNonce, getBalance, and getCode all return default values (0, 0, empty) for non-existent accounts, whereas the current implementation errors on missing accounts. This diverges from geth behavior for existing addresses missing from state—but this is a geth divergence issue, not an inconsistency between methods.

Likely an incorrect or invalid review comment.


18-28: No issues found — design is inherently single-threaded.

Verification confirms that the #[unsafe_ignore_trace] usage on RefCell and Rc fields is safe. The JsTracer is always stack-allocated and used in synchronous, single-threaded contexts (via call_js_tracer_impl). BoaContext itself is not Send/Sync and enforces single-threaded use by design. The tracer is passed by reference to simulate_tx without being moved across threads, preventing any cross-thread access to the non-Send/Sync fields.

lib/rpc/src/js_tracer/tracer.rs (4)

496-535: Complex but correct balance delta tracking.

The apply_balance_delta logic carefully manages committed/pending state and preserves original values for rollback (lines 512-514). The optimization at lines 519-521 removes no-op entries. While complex, the logic appears sound.


621-638: LGTM! Proper frame failure handling with overlay rollback.

The frame completion correctly rolls back overlays on failure (line 628) and propagates transaction failure when the top-level frame fails (lines 631-633).


734-783: LGTM! Comprehensive transaction finalization with proper cleanup.

The finish_tx method correctly handles errors, missing frames, and performs appropriate commit/rollback. The cleanup at lines 779-782 ensures the tracer is ready for the next transaction.


73-107: The clone operation is cheap by design.

The state_view.clone() at line 88 is intentionally inexpensive:

  • PersistentPreimages contains only a RocksDB handle, explicitly documented in code as "cheap to clone"
  • StorageMapView uses Arc<DashMap<>> fields, which clone in O(1) by incrementing the reference count
  • StateView derives Clone and is documented as a "thin wrapper"
  • The parent StateHandle is documented as "thread-safe and cheaply clonable"

No changes required.

lib/rpc/src/js_tracer/types.rs (3)

69-109: LGTM! Proper overflow handling in BalanceDelta.

Both credit and debit methods correctly check for overflow using overflowing_add and return appropriate errors. The is_empty helper is also correctly implemented.


147-189: LGTM! Sound journal-based overlay design.

The OverlayAction enum and journal-based approach provide a clean mechanism for tracking and reverting overlay changes. The design correctly supports nested checkpoints.


191-204: No changes needed—checkpoint validity is guaranteed by design.

The revert_to_checkpoint method is safe. Checkpoints are snapshots of journal length captured at frame entry time, and the LIFO stack discipline ensures they are always valid when used. The while journal.len() > checkpoint condition guarantees the journal is never empty when pop() is called, making the expect() safe. It functions as a defensive invariant check rather than a panic risk.

Copy link
Contributor

@0xVolosnikov 0xVolosnikov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

In the long term we should continuously compare our tracers to the Reth/Geth versions to catch potential bugs

@dimazhornyk dimazhornyk merged commit c991043 into main Dec 9, 2025
16 checks passed
@dimazhornyk dimazhornyk deleted the feat-js-tracer branch December 9, 2025 16:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants