Skip to content

feat(l1): implement muxTracer for debug_traceTransaction#6706

Open
azteca1998 wants to merge 5 commits into
mainfrom
feat/mux-tracer
Open

feat(l1): implement muxTracer for debug_traceTransaction#6706
azteca1998 wants to merge 5 commits into
mainfrom
feat/mux-tracer

Conversation

@azteca1998
Copy link
Copy Markdown
Contributor

Summary

  • Add muxTracer tracer type for debug_traceTransaction
  • Runs multiple sub-tracers on the same transaction and returns a combined map of tracerName -> result
  • Supported sub-tracers: callTracer, prestateTracer, opcodeTracer, 4byteTracer, noopTracer
  • Each sub-tracer re-executes the transaction independently (correct but not single-pass optimized)
  • Block-level muxTracer is not yet supported

Example

{
  "tracer": "muxTracer",
  "tracerConfig": {
    "callTracer": {"onlyTopCall": true},
    "prestateTracer": {"diffMode": false}
  }
}

Closes part of #6572

Add support for the `muxTracer` tracer type which runs multiple
sub-tracers on the same transaction and returns a combined result
map of `tracerName -> result`.

Supported sub-tracers: callTracer, prestateTracer, opcodeTracer,
4byteTracer, noopTracer.

Example config:
  {"tracer": "muxTracer", "tracerConfig": {
    "callTracer": {"onlyTopCall": true},
    "prestateTracer": {"diffMode": false}
  }}

Note: block-level muxTracer is not yet supported and returns an error.
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 21, 2026

⚠️ Known Issues — intentionally skipped tests

Source: docs/known_issues.md

Known Issues

Tests intentionally excluded from CI. Source of truth for the Known
Issues
section the L1 workflow appends to each ef-tests job summary
and posts as a sticky PR comment.

EF Tests — Stateless coverage narrowed to EIP-8025 optional-proofs

make -C tooling/ef_tests/blockchain test calls test-stateless-zkevm
instead of test-stateless. The zkevm@v0.3.3 fixtures are filled against
bal@v5.6.1, out of sync with current bal spec; the broad target trips ~549
fixtures. Re-broaden once the zkevm bundle is regenerated.

Why and resolution path

PR #6527 broadened
test-stateless to extract the entire for_amsterdam/ tree from the
zkevm bundle and run all of it under --features stateless; combined with
this branch's bal-devnet-7 semantics that scope produces ~549
GasUsedMismatch / ReceiptsRootMismatch /
BlockAccessListHashMismatch failures.

test-stateless-zkevm filters cargo to the eip8025_optional_proofs
suite, which still validates the stateless harness without the bal-version
mismatch.

Re-broaden by switching test: back to test-stateless in
tooling/ef_tests/blockchain/Makefile once the zkevm bundle is regenerated
against the current bal spec.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 21, 2026

Lines of code report

Total lines added: 409
Total lines removed: 0
Total lines changed: 409

Detailed view
+-----------------------------------------+-------+------+
| File                                    | Lines | Diff |
+-----------------------------------------+-------+------+
| ethrex/crates/networking/rpc/tracing.rs | 724   | +409 |
+-----------------------------------------+-------+------+

Tests for parse, config validation, tracer type deserialization,
and collect_four_byte_selectors helper function.
Trace a real transfer with muxTracer running callTracer and
prestateTracer simultaneously. Assert both sub-results are present.
@azteca1998 azteca1998 changed the title feat(rpc): implement muxTracer for debug_traceTransaction feat(l1): implement muxTracer for debug_traceTransaction May 21, 2026
@github-actions github-actions Bot added the L1 Ethereum client label May 21, 2026
This PR duplicated the same `collect_four_byte_selectors` body that
ships in the standalone 4byteTracer PR — including its three correctness
bugs against geth's reference (eth/tracers/native/4byte.go):

- size was `len(input)` instead of `len(input) - 4`,
- the top-level transaction call was counted (geth skips depth 0),
- every CallType was counted (geth only counts CALL + DELEGATECALL,
  skipping STATICCALL, CALLCODE, CREATE*, SELFDESTRUCT).

Fix all three here and add precompile-address skipping to match what
geth's `isPrecompiled` filter does on mainnet. Pre-existing unit tests
that asserted the buggy output are rewritten to lock in the corrected
semantics: top-frame skip, short-input skip, arg-size key, CALL/DELEGATECALL
filter, precompile skip, duplicate counting.

Two ergonomic fixes on the muxTracer handler itself:

- `debug_traceBlockByNumber` with muxTracer was surfacing as
  `RpcErr::Internal`; switched to `BadParams` since refusing the request
  is a user-input issue, not a server fault. The error message now also
  points the caller at the per-transaction form.
- Documented all three known divergences from geth on the `MuxTracer`
  variant: per-sub-tracer re-execution cost, no block-level support,
  and the closed set of routable sub-tracers (no flatCallTracer yet).

Integration coverage now actually proves the multiplexer is faithful:
three cross-validation tests assert that the mux output's `callTracer`,
`prestateTracer`, and combined-multi-tracer slots equal what each
sub-tracer returns when invoked standalone. Plus tests for the noop
shape (`{}`), unknown sub-tracer, missing `tracerConfig`, and the
block-level `BadParams` surface.

Test setup boilerplate moves into the shared `rpc::helpers` module from
#6701; the misnamed `debug_trace_tests.rs` is renamed to
`debug_mux_tracer_tests.rs`.
@azteca1998 azteca1998 marked this pull request as ready for review May 26, 2026 15:16
@azteca1998 azteca1998 requested a review from a team as a code owner May 26, 2026 15:16
@ethrex-project-sync ethrex-project-sync Bot moved this to In Review in ethrex_l1 May 26, 2026
@github-actions
Copy link
Copy Markdown

🤖 Kimi Code Review

Overall Assessment: Solid implementation with good test coverage and clear documentation. The multiplexer correctly re-runs transactions per sub-tracer (documented limitation) and the new 4byteTracer faithfully implements geth's selector collection logic.

Issues Found:

1. Timeout Multiplication (Performance/DoS)

  • File: crates/networking/rpc/tracing.rs, lines 236-243
  • Issue: Each sub-tracer receives the full timeout duration. With N sub-tracers, the total request time can be N× the intended timeout, creating a DoS vector against the RPC node.
  • Suggestion: Consider budgeting the timeout across tracers (e.g., timeout / N) or converting to a shared deadline timestamp before the loop.

2. Inconsistent Error Construction

  • File: crates/networking/rpc/tracing.rs, lines 419 vs 433
  • Issue: Line 419 uses ok_or(RpcErr::Internal(...)) (eager evaluation) while line 433 uses ok_or_else(|| RpcErr::Internal(...)) (lazy). Both allocate the string anyway, but prefer ok_or_else for consistency and to avoid cloning the error message when not needed.
  • Fix: Change line 419 to:
    .ok_or_else(|| RpcErr::Internal("Empty call trace".to_string()))?

3. Potential JSON Clone Overhead (Minor)

  • File: crates/networking/rpc/tracing.rs, line 400
  • Issue: sub_config.clone() is called for every tracer variant in the match arms, even for noopTracer which ignores it.
  • Suggestion: Move the clone inside the arms that actually need it, or pass &Value to the deserializers where possible (though serde_json::from_value takes ownership, so this may require refactoring to from_str or accepting the clone cost).

4. Missing Precompile Context (Accepted Limitation)

  • File: crates/networking/rpc/tracing.rs, lines 503-516
  • Note: The is_precompile_address function uses a static list (0x01-0x11, 0x0100) rather than checking the chain's actual precompile configuration for the current fork. The code comment acknowledges this divergence from geth ("Fork-agnostic... slightly more aggressive"), which is acceptable but should be monitored if future forks add/move precompiles.

Positive Notes:

  • Correctness: The 4byteTracer correctly skips the top-level call (depth 0), filters to only CALL/DELEGATECALL, and excludes precompile addresses per geth's implementation.
  • Testing: Excellent test coverage including round-trip verification that mux output matches standalone tracer output.
  • Documentation: Clear comments on geth divergences (re-execution cost, unsupported block-level tracing) in the MuxTracer variant docs.
  • Error Handling: Proper use of BadParams for user errors vs Internal for server faults.

Security Check: No memory safety issues found. The implementation uses safe Rust patterns throughout with proper error propagation.


Automated review by Kimi (Moonshot AI) · kimi-k2.5 · custom prompt

@github-actions
Copy link
Copy Markdown

🤖 Claude Code Review

Now I have all the context needed for a complete review.


PR Review: feat(l1): implement muxTracer for debug_traceTransaction

Overview

This PR adds muxTracer support to debug_traceTransaction, dispatching multiple sub-tracers per-transaction and merging results into a {tracerName: result} map. The implementation is correct, well-documented (especially regarding geth divergences), and ships with solid unit and integration test coverage.


Correctness

4byteTracer top-frame skip is correct.
collect_four_byte_selectors iterates top_frame.calls, skipping the top frame itself. This matches geth's 4byteTracer, which explicitly returns at depth == 0 in its OnEnter hook. The test four_byte_skips_top_level_call verifies this. ✓

is_precompile_address byte indexing is safe.
addr.as_bytes() always returns exactly 20 bytes, so the slice operations ([..19], [..18], [18], [19]) are all in-bounds. The L1 precompile range 0x01–0x11 and the L2 P256VERIFY address 0x0100 are handled correctly. ✓

Error propagation on sub-tracer failure.
The ? inside the for loop causes the first sub-tracer error to abort the entire mux call. This matches geth's semantics. ✓


Issues

1. ok_or vs ok_or_else inconsistency (style, minor)

In run_tx_sub_tracer, the "callTracer" arm (line ~433) uses eager ok_or:

.ok_or(RpcErr::Internal("Empty call trace".to_string()))?;

while the "4byteTracer" arm (line ~481) uses the lazy form:

.ok_or_else(|| RpcErr::Internal("Empty call trace".to_string()))?;

Prefer ok_or_else uniformly — the standalone CallTracer handler has the same inconsistency at line ~177. In practice the allocation is tiny, but it's worth standardizing.

2. Silently ignored sub_config for 4byteTracer and noopTracer

Neither of these arms parses sub_config, so {"4byteTracer": "this_is_invalid"} is accepted without complaint. This diverges from geth, which rejects unknown config keys. For noopTracer this is harmless, but for 4byteTracer a user typo (e.g. {"include_precompiles": true}) will be silently swallowed. Consider at minimum parsing sub_config as a Value::Object and rejecting non-objects:

"4byteTracer" => {
    if !sub_config.is_object() && !sub_config.is_null() {
        return Err(RpcErr::BadParams("4byteTracer config must be an object".into()));
    }
    // ...
}

3. Empty tracerConfig: {} returns {} silently

If a caller sends "tracer": "muxTracer" with "tracerConfig": {}, the loop runs zero iterations and returns an empty JSON object. This is technically valid but could mask misconfiguration. A warning log or documentation note would help; or if geth rejects it, match that.

4. Brittle assertion in integration test

In mux_tracer_block_level_returns_bad_params (debug_mux_tracer_tests.rs, line ~723):

assert!(msg.contains("BadParams"), ...);

where msg = format!("{err:?}"). This depends on the Debug representation of RpcErr. A more robust check is:

assert!(matches!(err, RpcErr::BadParams(_)), ...);

5. Missing integration tests for opcodeTracer and 4byteTracer sub-tracers

The integration suite covers callTracer, prestateTracer, noopTracer, and error paths, but not opcodeTracer or 4byteTracer. Since those two paths have non-trivial logic (collect_four_byte_selectors, StructLoggerResult wrapping), an end-to-end test would give stronger coverage guarantees against serialization regressions.

6. or_insert(0) should be or_default() (style, trivial)

In collect_four_byte_recursive (line ~514):

*selectors.entry(key).or_insert(0) += 1;

u64's default is 0, so prefer:

*selectors.entry(key).or_default() += 1;

7. Sequential sub-tracer execution (performance note)

The for (tracer_name, sub_config) in &mux_config loop re-executes the transaction N times sequentially. Since each sub-tracer is independent, they could be run concurrently with futures::future::try_join_all. Not a blocker, but worth tracking as a follow-up for clients that request many sub-tracers.


Positive Notes

  • The geth divergence documentation on MuxTracer is clear and accurate.
  • The is_precompile_address approach (fork-agnostic static range) is pragmatic and correctly documented.
  • Unit test coverage for collect_four_byte_selectors is thorough — it tests depth-0 skip, call-type filtering, precompile exclusion, duplicate counting, and nested recursion.
  • The muxTracer correctly rejects debug_traceBlockByNumber with a BadParams rather than Internal, signaling a user-input error rather than a server fault.

Automated review by Claude (Anthropic) · sonnet · custom prompt

@github-actions
Copy link
Copy Markdown

🤖 Codex Code Review

  1. High: the new 4byteTracer emulation skips the root frame entirely. collect_four_byte_selectors starts from top_frame.calls, and the new tests explicitly lock that in at four_byte_skips_top_level_call. That means a plain transaction that makes only the top-level contract call will produce {} from mux 4byteTracer, which is not what geth describes for 4byteTracer ("every function executed in the lifetime of a transaction"). (geth.ethereum.org)

  2. Medium: the precompile filter is fork-agnostic, which will make historical traces wrong. is_precompile_address always suppresses 0x0a..0x11 and 0x0100, but ethrex’s own VM models precompile availability as fork-dependent via precompiles_for_fork and only warms 0x0100 from Osaka onward in vm.rs. On older blocks, calls to those addresses can be normal contract calls, so this will undercount selectors in 4byteTracer.

I did not run the test suite here: cargo test fails in this environment because rustup tries to write temp files under read-only /home/runner/.rustup.


Automated review by OpenAI Codex · gpt-5.4 · custom prompt

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 26, 2026

Greptile Summary

This PR adds muxTracer support to debug_traceTransaction, allowing multiple sub-tracers (callTracer, prestateTracer, opcodeTracer, 4byteTracer, noopTracer) to be dispatched in a single RPC call and their results returned as a combined map. It also introduces the 4byteTracer implementation (function-selector harvesting from internal calls) and a new shared integration-test helper module.

  • crates/networking/rpc/tracing.rs: adds MuxTracer to TracerType, sequential sub-tracer dispatch via run_tx_sub_tracer, and the collect_four_byte_selectors/is_precompile_address helpers for the 4byteTracer; debug_traceBlockByNumber with muxTracer returns BadParams as a documented stub.
  • test/tests/rpc/debug_mux_tracer_tests.rs: integration tests validating per-sub-tracer correctness (output equality with standalone tracers), error paths, and the block-level unsupported case.
  • test/tests/rpc/helpers.rs: extracted shared store/blockchain/RPC-call setup helpers to avoid duplication across test files.

Confidence Score: 4/5

The change is additive and isolated to the tracing layer; existing tracer paths are untouched and the new muxTracer path is well-tested for the main sub-tracers.

The core mux dispatch logic is straightforward and the integration tests cover the primary sub-tracers and error cases well. The main open questions are around the 4byteTracer: the comment attributes STATICCALL filtering to geth's own behavior, but geth's native tracer does not filter by opcode, so the implementation diverges silently for transactions with STATICCALL internal calls. No integration test covers the 4byteTracer sub-tracer end-to-end within muxTracer, leaving that path untested.

crates/networking/rpc/tracing.rs — specifically the 4byteTracer helpers and the opcode-filtering comment; test/tests/rpc/debug_mux_tracer_tests.rs for the missing 4byteTracer integration test.

Important Files Changed

Filename Overview
crates/networking/rpc/tracing.rs Adds MuxTracer variant to TracerType, implements sequential sub-tracer dispatch in run_tx_sub_tracer, and introduces 4byteTracer helpers; main concerns are a misdocumented geth divergence for STATICCALL filtering and the uncapped per-sub-tracer timeout.
test/tests/rpc/debug_mux_tracer_tests.rs New integration tests covering muxTracer happy paths (callTracer, prestateTracer, noopTracer sub-tracers), error paths (unknown sub-tracer, missing config, block-level not supported); 4byteTracer sub-tracer is not exercised end-to-end.
test/tests/rpc/helpers.rs New shared test helpers module extracted for reuse across RPC integration tests; provides store setup, block building, and rpc_call/rpc_call_expect_err utilities.
test/tests/rpc/mod.rs Registers the two new test modules (debug_mux_tracer_tests, helpers) in the rpc test mod.

Sequence Diagram

sequenceDiagram
    participant Client
    participant RPC as TraceTransactionRequest::handle
    participant Sub as run_tx_sub_tracer
    participant BC as blockchain

    Client->>RPC: debug_traceTransaction(txHash, muxTracer config)
    RPC->>RPC: parse tracerConfig → HashMap
    loop for each (tracer_name, sub_config)
        RPC->>Sub: run_tx_sub_tracer(...)
        alt callTracer / prestateTracer / opcodeTracer / 4byteTracer / noopTracer
            Sub->>BC: "trace_transaction_*()"
            BC-->>Sub: result
            Sub-->>RPC: Value
        else unknown
            Sub-->>RPC: BadParams error
        end
        RPC->>RPC: results.insert(name, value)
    end
    RPC-->>Client: "{tracerName: result, ...}"
Loading
Prompt To Fix All With AI
Fix the following 4 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 4
crates/networking/rpc/tracing.rs:491-499
**Inaccurate attribution of geth's 4byteTracer opcode filtering**

The comment states "geth's tracer filters on the opcode and skips STATICCALL, CALLCODE, CREATE*, and SELFDESTRUCT," but geth's native Go implementation (`eth/tracers/native/4byte.go`) does not filter by opcode in `CaptureEnter` — it captures any call type with at least 4 bytes of input. This means STATICCALL and CALLCODE selectors are counted by geth but not by this implementation. The filtering is a real divergence, but it's being incorrectly attributed to geth's own behavior. Any contract that uses `STATICCALL` with a function selector (e.g., view-function dispatch via delegate or proxy patterns) would produce a different selector map here versus geth.

### Issue 2 of 4
crates/networking/rpc/tracing.rs:472-475
**`4byteTracer` ignores `sub_config` without validation**

The `"4byteTracer"` arm silently ignores `sub_config` — any keys the caller passes are discarded without warning. This is fine given geth's 4byteTracer accepts no configuration, but a stale or mistyped config field will never surface as an error. At minimum, asserting `sub_config` is null or an empty object makes the contract explicit and prevents silent misconfiguration.

```suggestion
        "4byteTracer" => {
            // 4byteTracer accepts no configuration; any supplied config is ignored.
            let call_trace = context
                .blockchain
                .trace_transaction_calls(tx_hash, reexec, timeout, false, false)
```

### Issue 3 of 4
crates/networking/rpc/tracing.rs:228-251
**Each sub-tracer receives the full timeout, not a proportional share**

`timeout` is passed unchanged to every `run_tx_sub_tracer` call, so with `N` sub-tracers and the default 5 s timeout the wall-clock budget is up to `N × 5 s`. A user who sets `"timeout": "2s"` expecting a 2-second cap for the whole mux request will be surprised when the call takes up to 10 s with 5 sub-tracers. The `MuxTracer` variant comment already documents the N× cost divergence, but the call site itself has no note. Consider at least noting this in a call-site comment so future maintainers don't accidentally "fix" the pass-through.

### Issue 4 of 4
test/tests/rpc/debug_mux_tracer_tests.rs:1-10
**No integration test for the `4byteTracer` sub-tracer within muxTracer**

The integration test suite validates `callTracer`, `prestateTracer`, and `noopTracer` as mux sub-tracers, but not `4byteTracer`. Given that `4byteTracer` has its own new implementation (`collect_four_byte_selectors`, `collect_four_byte_recursive`, `is_precompile_address`) rather than delegating to an existing path, an end-to-end test covering at least the happy path (e.g., a simple ETH transfer returns `{}` since there are no internal calls) would close the coverage gap.

Reviews (1): Last reviewed commit: "fix(rpc): correct 4byteTracer inside mux..." | Re-trigger Greptile

Comment on lines +491 to +499
/// Collects 4-byte function selectors and calldata sizes from a call trace
/// tree, matching geth's built-in `4byteTracer`
/// (https://github.com/ethereum/go-ethereum/blob/master/eth/tracers/native/4byte.go):
///
/// - The top-level transaction call is **not** counted; only nested calls are.
/// - Only `CALL` and `DELEGATECALL` are counted — geth's tracer filters on the
/// opcode and skips STATICCALL, CALLCODE, CREATE*, and SELFDESTRUCT.
/// - Invocations targeting precompile addresses are skipped.
/// - The reported size is `len(calldata) - 4` (the argument-bytes length).
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Inaccurate attribution of geth's 4byteTracer opcode filtering

The comment states "geth's tracer filters on the opcode and skips STATICCALL, CALLCODE, CREATE*, and SELFDESTRUCT," but geth's native Go implementation (eth/tracers/native/4byte.go) does not filter by opcode in CaptureEnter — it captures any call type with at least 4 bytes of input. This means STATICCALL and CALLCODE selectors are counted by geth but not by this implementation. The filtering is a real divergence, but it's being incorrectly attributed to geth's own behavior. Any contract that uses STATICCALL with a function selector (e.g., view-function dispatch via delegate or proxy patterns) would produce a different selector map here versus geth.

Prompt To Fix With AI
This is a comment left during a code review.
Path: crates/networking/rpc/tracing.rs
Line: 491-499

Comment:
**Inaccurate attribution of geth's 4byteTracer opcode filtering**

The comment states "geth's tracer filters on the opcode and skips STATICCALL, CALLCODE, CREATE*, and SELFDESTRUCT," but geth's native Go implementation (`eth/tracers/native/4byte.go`) does not filter by opcode in `CaptureEnter` — it captures any call type with at least 4 bytes of input. This means STATICCALL and CALLCODE selectors are counted by geth but not by this implementation. The filtering is a real divergence, but it's being incorrectly attributed to geth's own behavior. Any contract that uses `STATICCALL` with a function selector (e.g., view-function dispatch via delegate or proxy patterns) would produce a different selector map here versus geth.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +472 to +475
"4byteTracer" => {
let call_trace = context
.blockchain
.trace_transaction_calls(tx_hash, reexec, timeout, false, false)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 4byteTracer ignores sub_config without validation

The "4byteTracer" arm silently ignores sub_config — any keys the caller passes are discarded without warning. This is fine given geth's 4byteTracer accepts no configuration, but a stale or mistyped config field will never surface as an error. At minimum, asserting sub_config is null or an empty object makes the contract explicit and prevents silent misconfiguration.

Suggested change
"4byteTracer" => {
let call_trace = context
.blockchain
.trace_transaction_calls(tx_hash, reexec, timeout, false, false)
"4byteTracer" => {
// 4byteTracer accepts no configuration; any supplied config is ignored.
let call_trace = context
.blockchain
.trace_transaction_calls(tx_hash, reexec, timeout, false, false)
Prompt To Fix With AI
This is a comment left during a code review.
Path: crates/networking/rpc/tracing.rs
Line: 472-475

Comment:
**`4byteTracer` ignores `sub_config` without validation**

The `"4byteTracer"` arm silently ignores `sub_config` — any keys the caller passes are discarded without warning. This is fine given geth's 4byteTracer accepts no configuration, but a stale or mistyped config field will never surface as an error. At minimum, asserting `sub_config` is null or an empty object makes the contract explicit and prevents silent misconfiguration.

```suggestion
        "4byteTracer" => {
            // 4byteTracer accepts no configuration; any supplied config is ignored.
            let call_trace = context
                .blockchain
                .trace_transaction_calls(tx_hash, reexec, timeout, false, false)
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +228 to +251
TracerType::MuxTracer => {
let mux_config: HashMap<String, Value> =
if let Some(value) = &self.trace_config.tracer_config {
serde_json::from_value(value.clone())?
} else {
return Err(RpcErr::BadParams(
"muxTracer requires tracerConfig".to_owned(),
));
};
let mut results = serde_json::Map::new();
for (tracer_name, sub_config) in &mux_config {
let result = run_tx_sub_tracer(
tracer_name,
sub_config,
self.tx_hash,
reexec,
timeout,
&context,
)
.await?;
results.insert(tracer_name.clone(), result);
}
Ok(Value::Object(results))
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Each sub-tracer receives the full timeout, not a proportional share

timeout is passed unchanged to every run_tx_sub_tracer call, so with N sub-tracers and the default 5 s timeout the wall-clock budget is up to N × 5 s. A user who sets "timeout": "2s" expecting a 2-second cap for the whole mux request will be surprised when the call takes up to 10 s with 5 sub-tracers. The MuxTracer variant comment already documents the N× cost divergence, but the call site itself has no note. Consider at least noting this in a call-site comment so future maintainers don't accidentally "fix" the pass-through.

Prompt To Fix With AI
This is a comment left during a code review.
Path: crates/networking/rpc/tracing.rs
Line: 228-251

Comment:
**Each sub-tracer receives the full timeout, not a proportional share**

`timeout` is passed unchanged to every `run_tx_sub_tracer` call, so with `N` sub-tracers and the default 5 s timeout the wall-clock budget is up to `N × 5 s`. A user who sets `"timeout": "2s"` expecting a 2-second cap for the whole mux request will be surprised when the call takes up to 10 s with 5 sub-tracers. The `MuxTracer` variant comment already documents the N× cost divergence, but the call site itself has no note. Consider at least noting this in a call-site comment so future maintainers don't accidentally "fix" the pass-through.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +1 to +10
use serde_json::{Value, json};

use super::helpers::{rpc_call, rpc_call_expect_err, setup_single_transfer_block};

async fn trace_with(
store: &ethrex_storage::Store,
tx: ethrex_common::H256,
config: Value,
) -> Value {
rpc_call(
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 No integration test for the 4byteTracer sub-tracer within muxTracer

The integration test suite validates callTracer, prestateTracer, and noopTracer as mux sub-tracers, but not 4byteTracer. Given that 4byteTracer has its own new implementation (collect_four_byte_selectors, collect_four_byte_recursive, is_precompile_address) rather than delegating to an existing path, an end-to-end test covering at least the happy path (e.g., a simple ETH transfer returns {} since there are no internal calls) would close the coverage gap.

Prompt To Fix With AI
This is a comment left during a code review.
Path: test/tests/rpc/debug_mux_tracer_tests.rs
Line: 1-10

Comment:
**No integration test for the `4byteTracer` sub-tracer within muxTracer**

The integration test suite validates `callTracer`, `prestateTracer`, and `noopTracer` as mux sub-tracers, but not `4byteTracer`. Given that `4byteTracer` has its own new implementation (`collect_four_byte_selectors`, `collect_four_byte_recursive`, `is_precompile_address`) rather than delegating to an existing path, an end-to-end test covering at least the happy path (e.g., a simple ETH transfer returns `{}` since there are no internal calls) would close the coverage gap.

How can I resolve this? If you propose a fix, please make it concise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

L1 Ethereum client

Projects

Status: In Review

Development

Successfully merging this pull request may close these issues.

1 participant