1use alloc::{string::String, vec::Vec};
8use alloy_primitives::{hex, Bytes, B256};
9use alloy_trie::nodes::TrieNode;
10use reth_trie_common::Nibbles;
11use serde::Serialize;
12
13#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize)]
15pub struct TrieDebugRecorder {
16 ops: Vec<RecordedOp>,
17}
18
19impl TrieDebugRecorder {
20 pub fn new() -> Self {
22 Self::default()
23 }
24
25 pub fn reset(&mut self) {
27 self.ops.clear();
28 }
29
30 pub fn record(&mut self, op: RecordedOp) {
32 self.ops.push(op);
33 }
34
35 pub fn ops(&self) -> &[RecordedOp] {
37 &self.ops
38 }
39
40 pub fn take_ops(&mut self) -> Vec<RecordedOp> {
42 core::mem::take(&mut self.ops)
43 }
44
45 pub const fn is_empty(&self) -> bool {
47 self.ops.is_empty()
48 }
49}
50
51#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
53pub enum RecordedOp {
54 RevealNodes {
56 nodes: Vec<ProofTrieNodeRecord>,
58 },
59 UpdateLeaves {
61 updates: Vec<(B256, LeafUpdateRecord)>,
63 proof_targets: Vec<(B256, u8)>,
65 },
66 UpdateSubtrieHashes,
68 Root,
70 SetRoot {
72 node: ProofTrieNodeRecord,
74 },
75 Prune,
78}
79
80#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
82pub struct ProofTrieNodeRecord {
83 pub path: Nibbles,
85 pub node: TrieNodeRecord,
87 pub masks: Option<(u16, u16)>,
89 #[serde(skip_serializing_if = "Option::is_none")]
93 pub short_key: Option<Nibbles>,
94 #[serde(skip_serializing_if = "Option::is_none")]
96 pub state: Option<NodeStateRecord>,
97}
98
99#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
101pub enum NodeStateRecord {
102 Revealed,
104 Cached {
106 rlp_node: String,
108 },
109 Dirty,
111}
112
113impl ProofTrieNodeRecord {
114 pub fn from_proof_trie_node(node: &reth_trie_common::ProofTrieNode) -> Self {
116 Self {
117 path: node.path,
118 node: TrieNodeRecord(node.node.clone()),
119 masks: node.masks.map(|masks| (masks.hash_mask.get(), masks.tree_mask.get())),
120 short_key: None,
121 state: None,
122 }
123 }
124
125 pub fn from_proof_trie_node_v2(node: &reth_trie_common::ProofTrieNodeV2) -> Self {
127 use reth_trie_common::TrieNodeV2;
128 let (trie_node, short_key) = match &node.node {
129 TrieNodeV2::EmptyRoot => (TrieNode::EmptyRoot, None),
130 TrieNodeV2::Leaf(leaf) => (TrieNode::Leaf(leaf.clone()), None),
131 TrieNodeV2::Extension(ext) => (TrieNode::Extension(ext.clone()), None),
132 TrieNodeV2::Branch(branch) => (
133 TrieNode::Branch(alloy_trie::nodes::BranchNode::new(
134 branch.stack.clone(),
135 branch.state_mask,
136 )),
137 (!branch.key.is_empty()).then_some(branch.key),
138 ),
139 };
140 Self {
141 path: node.path,
142 node: TrieNodeRecord(trie_node),
143 masks: node.masks.map(|masks| (masks.hash_mask.get(), masks.tree_mask.get())),
144 short_key,
145 state: None,
146 }
147 }
148}
149
150#[derive(Debug, Clone, PartialEq, Eq)]
154pub struct TrieNodeRecord(pub TrieNode);
155
156impl From<TrieNode> for TrieNodeRecord {
157 fn from(node: TrieNode) -> Self {
158 Self(node)
159 }
160}
161
162impl Serialize for TrieNodeRecord {
163 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
164 use serde::ser::SerializeStructVariant;
165 match &self.0 {
166 TrieNode::EmptyRoot => serializer.serialize_unit_variant("TrieNode", 0, "EmptyRoot"),
167 TrieNode::Branch(branch) => {
168 let stack_hex: Vec<String> =
169 branch.stack.iter().map(|n| hex::encode(n.as_ref())).collect();
170 let mut sv = serializer.serialize_struct_variant("TrieNode", 1, "Branch", 2)?;
171 sv.serialize_field("stack", &stack_hex)?;
172 sv.serialize_field("state_mask", &branch.state_mask.get())?;
173 sv.end()
174 }
175 TrieNode::Extension(ext) => {
176 let mut sv = serializer.serialize_struct_variant("TrieNode", 2, "Extension", 2)?;
177 sv.serialize_field("key", &ext.key)?;
178 sv.serialize_field("child", &hex::encode(ext.child.as_ref()))?;
179 sv.end()
180 }
181 TrieNode::Leaf(leaf) => {
182 let mut sv = serializer.serialize_struct_variant("TrieNode", 3, "Leaf", 2)?;
183 sv.serialize_field("key", &leaf.key)?;
184 sv.serialize_field("value", &hex::encode(&leaf.value))?;
185 sv.end()
186 }
187 }
188 }
189}
190
191#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
193pub enum LeafUpdateRecord {
194 Changed(Bytes),
196 Touched,
198}
199
200impl From<&crate::LeafUpdate> for LeafUpdateRecord {
201 fn from(update: &crate::LeafUpdate) -> Self {
202 match update {
203 crate::LeafUpdate::Changed(value) => Self::Changed(value.clone().into()),
204 crate::LeafUpdate::Touched => Self::Touched,
205 }
206 }
207}