foundry_debugger/
node.rs
1use alloy_primitives::{Address, Bytes};
2use foundry_evm_traces::{CallKind, CallTraceArena};
3use revm_inspectors::tracing::types::{CallTraceStep, TraceMemberOrder};
4use serde::{Deserialize, Serialize};
5
6#[derive(Clone, Debug, Default, Serialize, Deserialize)]
8pub struct DebugNode {
9 pub address: Address,
13 pub kind: CallKind,
15 pub calldata: Bytes,
17 pub steps: Vec<CallTraceStep>,
19}
20
21impl DebugNode {
22 pub fn new(
24 address: Address,
25 kind: CallKind,
26 steps: Vec<CallTraceStep>,
27 calldata: Bytes,
28 ) -> Self {
29 Self { address, kind, steps, calldata }
30 }
31}
32
33pub fn flatten_call_trace(arena: CallTraceArena, out: &mut Vec<DebugNode>) {
38 #[derive(Debug, Clone, Copy)]
39 struct PendingNode {
40 node_idx: usize,
41 steps_count: usize,
42 }
43
44 fn inner(arena: &CallTraceArena, node_idx: usize, out: &mut Vec<PendingNode>) {
45 let mut pending = PendingNode { node_idx, steps_count: 0 };
46 let node = &arena.nodes()[node_idx];
47 for order in &node.ordering {
48 match order {
49 TraceMemberOrder::Call(idx) => {
50 out.push(pending);
51 pending.steps_count = 0;
52 inner(arena, node.children[*idx], out);
53 }
54 TraceMemberOrder::Step(_) => {
55 pending.steps_count += 1;
56 }
57 _ => {}
58 }
59 }
60 out.push(pending);
61 }
62 let mut nodes = Vec::new();
63 inner(&arena, 0, &mut nodes);
64
65 let mut arena_nodes = arena.into_nodes();
66
67 for pending in nodes {
68 let steps = {
69 let other_steps =
70 arena_nodes[pending.node_idx].trace.steps.split_off(pending.steps_count);
71 std::mem::replace(&mut arena_nodes[pending.node_idx].trace.steps, other_steps)
72 };
73
74 if steps.is_empty() {
76 continue
77 }
78
79 let call = &arena_nodes[pending.node_idx].trace;
80 let calldata = if call.kind.is_any_create() { Bytes::new() } else { call.data.clone() };
81 let node = DebugNode::new(call.address, call.kind, steps, calldata);
82
83 out.push(node);
84 }
85}