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 gas_limit: u64,
19 pub steps: Vec<CallTraceStep>,
21}
22
23impl DebugNode {
24 pub fn new(
26 address: Address,
27 kind: CallKind,
28 steps: Vec<CallTraceStep>,
29 calldata: Bytes,
30 gas_limit: u64,
31 ) -> Self {
32 Self { address, kind, steps, calldata, gas_limit }
33 }
34}
35
36pub fn flatten_call_trace(arena: CallTraceArena, out: &mut Vec<DebugNode>) {
41 #[derive(Debug, Clone, Copy)]
42 struct PendingNode {
43 node_idx: usize,
44 steps_count: usize,
45 }
46
47 fn inner(arena: &CallTraceArena, node_idx: usize, out: &mut Vec<PendingNode>) {
48 let mut pending = PendingNode { node_idx, steps_count: 0 };
49 let node = &arena.nodes()[node_idx];
50 for order in &node.ordering {
51 match order {
52 TraceMemberOrder::Call(idx) => {
53 out.push(pending);
54 pending.steps_count = 0;
55 inner(arena, node.children[*idx], out);
56 }
57 TraceMemberOrder::Step(_) => {
58 pending.steps_count += 1;
59 }
60 _ => {}
61 }
62 }
63 out.push(pending);
64 }
65 let mut nodes = Vec::new();
66 inner(&arena, 0, &mut nodes);
67
68 let mut arena_nodes = arena.into_nodes();
69
70 for pending in nodes {
71 let steps = {
72 let other_steps =
73 arena_nodes[pending.node_idx].trace.steps.split_off(pending.steps_count);
74 std::mem::replace(&mut arena_nodes[pending.node_idx].trace.steps, other_steps)
75 };
76
77 if steps.is_empty() {
79 continue;
80 }
81
82 let call = &arena_nodes[pending.node_idx].trace;
83 let calldata = if call.kind.is_any_create() { Bytes::new() } else { call.data.clone() };
84 let node = DebugNode::new(call.address, call.kind, steps, calldata, call.gas_limit);
85
86 out.push(node);
87 }
88}