Skip to content

Conversation

@tskoyo
Copy link
Contributor

@tskoyo tskoyo commented Nov 23, 2025

Motivation

Closes #12446

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added for cast run as well. I noticed we use traces on cast call as well. Shall we add prune trace depth over there as well?

https://github.com/foundry-rs/foundry/blob/master/crates/cast/src/cmd/call.rs

Copy link
Collaborator

Choose a reason for hiding this comment

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

cast run should be fine for now, will extend if needed for other

}

#[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]

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added another test in the same file. Use the same contract RecursiveCall that was used in that file.

@tskoyo tskoyo requested a review from grandizzy November 26, 2025 21:35
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.

lgtm, thank you!

@grandizzy grandizzy added this pull request to the merge queue Nov 27, 2025
Merged via the queue into foundry-rs:master with commit 445f340 Nov 27, 2025
27 of 29 checks passed
@github-project-automation github-project-automation bot moved this to Done in Foundry Nov 27, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

feat(traces): add a -d | --depth flag for verbose traces, like tree

2 participants