Skip to content

Conversation

@tskoyo
Copy link

@tskoyo tskoyo commented Nov 23, 2025

Motivation

Solve this issue.

This PR introduces a new --depth (or -d) CLI option to forge test that allows users to limit how many levels of the call tree are displayed. This change makes traces easier to read.

Solution

Example:

Debugging passing tests

Trace output:
a) Command example: forge test --depth 3 -vvvv

[PASS] testResolveDispute_RevertToSeller() (gas: 70484)
Traces:
  [70484] EscrowTest::testResolveDispute_RevertToSeller()
    ├─ [0] VM::prank(buyer: [0x0fF93eDfa7FB7Ad5E962E4C0EdB9207C03a0fe02])
    │   └─ ← [Return]
    ├─ [7836] Escrow::raiseDispute(1)
    │   └─ ← [Stop]
    ├─ [0] VM::prank(arbitrator: [0xA2DE859fC0d8B01241993d48A78B4e0742B068c9])
    │   └─ ← [Return]
    ├─ [42518] Escrow::resolveDispute(1, false)
    │   ├─ [0] seller::fallback{value: 1000000000000000000}()
    │   │   └─ ← [Stop]
    │   └─ ← [Stop]
    ├─ [0] VM::assertEq(0, 0) [staticcall]
    │   └─ ← [Return]
    ├─ [0] VM::assertEq(1000000000000000000 [1e18], 1000000000000000000 [1e18]) [staticcall]
    │   └─ ← [Return]
    └─ ← [Stop]

Trace output:
b) Command example: forge test --depth 1 -vvvv

[PASS] testResolveDispute_RevertToSeller() (gas: 70484)
Traces:
  [70484] EscrowTest::testResolveDispute_RevertToSeller()
    ├─ [0] VM::prank(buyer: [0x0fF93eDfa7FB7Ad5E962E4C0EdB9207C03a0fe02])
    │   └─ ← [Return]
    ├─ [7836] Escrow::raiseDispute(1)
    │   └─ ← [Stop]
    ├─ [0] VM::prank(arbitrator: [0xA2DE859fC0d8B01241993d48A78B4e0742B068c9])
    │   └─ ← [Return]
    ├─ [42518] Escrow::resolveDispute(1, false)
    │   └─ ← [Stop]
    ├─ [0] VM::assertEq(0, 0) [staticcall]
    │   └─ ← [Return]
    ├─ [0] VM::assertEq(1000000000000000000 [1e18], 1000000000000000000 [1e18]) [staticcall]
    │   └─ ← [Return]
    └─ ← [Stop]

Debugging failing tests

Trace output:
a) Command example forge test --depth 1 -vvv

[FAIL: assertion failed: 0 != 5] testResolveDispute_RevertToBuyer() (gas: 38155)
Traces:
  [38155] EscrowTest::testResolveDispute_RevertToBuyer()
    ├─ [0] VM::prank(buyer: [0x0fF93eDfa7FB7Ad5E962E4C0EdB9207C03a0fe02])
    │   └─ ← [Return]
    ├─ [7836] Escrow::raiseDispute(1)
    │   └─ ← [Stop]
    ├─ [0] VM::prank(arbitrator: [0xA2DE859fC0d8B01241993d48A78B4e0742B068c9])
    │   └─ ← [Return]
    ├─ [13007] Escrow::resolveDispute(1, true)
    │   └─ ← [Stop]
    ├─ [0] VM::assertEq(0, 5) [staticcall]
    │   └─ ← [Revert] assertion failed: 0 != 5
    └─ ← [Revert] assertion failed: 0 != 5

Trace output:
b) Command example: forge test --depth 3 -vvv

[FAIL: assertion failed: 0 != 5] testResolveDispute_RevertToBuyer() (gas: 38155)
Traces:
  [38155] EscrowTest::testResolveDispute_RevertToBuyer()
    ├─ [0] VM::prank(buyer: [0x0fF93eDfa7FB7Ad5E962E4C0EdB9207C03a0fe02])
    │   └─ ← [Return]
    ├─ [7836] Escrow::raiseDispute(1)
    │   └─ ← [Stop]
    ├─ [0] VM::prank(arbitrator: [0xA2DE859fC0d8B01241993d48A78B4e0742B068c9])
    │   └─ ← [Return]
    ├─ [13007] Escrow::resolveDispute(1, true)
    │   ├─ [0] buyer::fallback{value: 1000000000000000000}()
    │   │   └─ ← [Stop]
    │   └─ ← [Stop]
    ├─ [0] VM::assertEq(0, 5) [staticcall]
    │   └─ ← [Revert] assertion failed: 0 != 5
    └─ ← [Revert] assertion failed: 0 != 5

PR Checklist

  • Added Tests
  • Added Documentation
  • Breaking changes

Copy link
Collaborator

@grandizzy grandizzy left a comment

Choose a reason for hiding this comment

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

thank you! left some comments, please check

pub fn prune_trace_depth(arena: &mut CallTraceArena, depth: usize) {
for node in arena.nodes_mut() {
if node.trace.depth >= depth {
Vec::clear(&mut node.ordering);
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: can be node.ordering.clear();


/// Defines the depth of a trace
#[arg(long, short)]
depth: Option<usize>,
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think trace_depth would be better naming
Also the ticket mentions cast as well, so let's extend the option to cast too.

}

#[test]
fn depth_trace() {
Copy link
Collaborator

Choose a reason for hiding this comment

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

please apply the new option in similar test as with test_trace test here

[..] TraceTest::testRecurseCall()
├─ [..] Node 0::recurseCall(8, 0)
│ ├─ [..] Node 0::recurseCall(8, 1)
│ │ ├─ [..] Node 0::recurseCall(8, 2)
│ │ │ ├─ [..] Node 0::recurseCall(8, 3)
│ │ │ │ ├─ [..] Node 0::recurseCall(8, 4)
│ │ │ │ │ ├─ [..] Node 0::recurseCall(8, 5)
│ │ │ │ │ │ ├─ [..] Node 0::recurseCall(8, 6)
│ │ │ │ │ │ │ ├─ [..] Node 0::recurseCall(8, 7)
│ │ │ │ │ │ │ │ ├─ [..] Node 0::recurseCall(8, 8)
│ │ │ │ │ │ │ │ │ ├─ [..] Node 0::negativeNum() [staticcall]
│ │ │ │ │ │ │ │ │ │ └─ ← [Return] -1000000000 [-1e9]

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

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

2 participants