reth_trie_sparse/traits.rs
1//! Traits for sparse trie implementations.
2
3use core::fmt::Debug;
4
5use alloc::{borrow::Cow, vec, vec::Vec};
6use alloy_primitives::{
7 map::{HashMap, HashSet},
8 B256,
9};
10use alloy_trie::{BranchNodeCompact, TrieMask};
11use reth_execution_errors::SparseTrieResult;
12use reth_trie_common::{Nibbles, TrieNode};
13
14use crate::provider::TrieNodeProvider;
15
16/// Trait defining common operations for revealed sparse trie implementations.
17///
18/// This trait abstracts over different sparse trie implementations (serial vs parallel)
19/// while providing a unified interface for the core trie operations needed by the
20/// [`crate::SparseTrie`] enum.
21pub trait SparseTrieInterface: Sized + Debug + Send + Sync {
22 /// Configures the trie to have the given root node revealed.
23 ///
24 /// # Arguments
25 ///
26 /// * `root` - The root node to reveal
27 /// * `masks` - Trie masks for root branch node
28 /// * `retain_updates` - Whether to track updates
29 ///
30 /// # Returns
31 ///
32 /// Self if successful, or an error if revealing fails.
33 ///
34 /// # Panics
35 ///
36 /// May panic if the trie is not new/cleared, and has already revealed nodes.
37 fn with_root(
38 self,
39 root: TrieNode,
40 masks: TrieMasks,
41 retain_updates: bool,
42 ) -> SparseTrieResult<Self>;
43
44 /// Configures the trie to retain information about updates.
45 ///
46 /// If `retain_updates` is true, the trie will record branch node updates
47 /// and deletions. This information can be used to efficiently update
48 /// an external database.
49 ///
50 /// # Arguments
51 ///
52 /// * `retain_updates` - Whether to track updates
53 ///
54 /// # Returns
55 ///
56 /// Self for method chaining.
57 fn with_updates(self, retain_updates: bool) -> Self;
58
59 /// Reserves capacity for additional trie nodes.
60 ///
61 /// # Arguments
62 ///
63 /// * `additional` - The number of additional trie nodes to reserve capacity for.
64 fn reserve_nodes(&mut self, _additional: usize) {}
65
66 /// The single-node version of `reveal_nodes`.
67 ///
68 /// # Returns
69 ///
70 /// `Ok(())` if successful, or an error if the node was not revealed.
71 fn reveal_node(
72 &mut self,
73 path: Nibbles,
74 node: TrieNode,
75 masks: TrieMasks,
76 ) -> SparseTrieResult<()> {
77 self.reveal_nodes(vec![RevealedSparseNode { path, node, masks }])
78 }
79
80 /// Reveals one or more trie nodes if they have not been revealed before.
81 ///
82 /// This function decodes trie nodes and inserts them into the trie structure. It handles
83 /// different node types (leaf, extension, branch) by appropriately adding them to the trie and
84 /// recursively revealing their children.
85 ///
86 /// # Arguments
87 ///
88 /// * `nodes` - The nodes to be revealed, each having a path and optional set of branch node
89 /// masks. The nodes will be unsorted.
90 ///
91 /// # Returns
92 ///
93 /// `Ok(())` if successful, or an error if any of the nodes was not revealed.
94 fn reveal_nodes(&mut self, nodes: Vec<RevealedSparseNode>) -> SparseTrieResult<()>;
95
96 /// Updates the value of a leaf node at the specified path.
97 ///
98 /// If the leaf doesn't exist, it will be created.
99 /// If it does exist, its value will be updated.
100 ///
101 /// # Arguments
102 ///
103 /// * `full_path` - The full path to the leaf
104 /// * `value` - The new value for the leaf
105 /// * `provider` - The trie provider for resolving missing nodes
106 ///
107 /// # Returns
108 ///
109 /// `Ok(())` if successful, or an error if the update failed.
110 fn update_leaf<P: TrieNodeProvider>(
111 &mut self,
112 full_path: Nibbles,
113 value: Vec<u8>,
114 provider: P,
115 ) -> SparseTrieResult<()>;
116
117 /// Removes a leaf node at the specified path.
118 ///
119 /// This will also handle collapsing the trie structure as needed
120 /// (e.g., removing branch nodes that become unnecessary).
121 ///
122 /// # Arguments
123 ///
124 /// * `full_path` - The full path to the leaf to remove
125 /// * `provider` - The trie node provider for resolving missing nodes
126 ///
127 /// # Returns
128 ///
129 /// `Ok(())` if successful, or an error if the removal failed.
130 fn remove_leaf<P: TrieNodeProvider>(
131 &mut self,
132 full_path: &Nibbles,
133 provider: P,
134 ) -> SparseTrieResult<()>;
135
136 /// Calculates and returns the root hash of the trie.
137 ///
138 /// This processes any dirty nodes by updating their RLP encodings
139 /// and returns the root hash.
140 ///
141 /// # Returns
142 ///
143 /// The root hash of the trie.
144 fn root(&mut self) -> B256;
145
146 /// Recalculates and updates the RLP hashes of subtries deeper than a certain level. The level
147 /// is defined in the implementation.
148 ///
149 /// The root node is considered to be at level 0. This method is useful for optimizing
150 /// hash recalculations after localized changes to the trie structure.
151 fn update_subtrie_hashes(&mut self);
152
153 /// Retrieves a reference to the leaf value at the specified path.
154 ///
155 /// # Arguments
156 ///
157 /// * `full_path` - The full path to the leaf value
158 ///
159 /// # Returns
160 ///
161 /// A reference to the leaf value stored at the given full path, if it is revealed.
162 ///
163 /// Note: a value can exist in the full trie and this function still returns `None`
164 /// because the value has not been revealed.
165 ///
166 /// Hence a `None` indicates two possibilities:
167 /// - The value does not exists in the trie, so it cannot be revealed
168 /// - The value has not yet been revealed. In order to determine which is true, one would need
169 /// an exclusion proof.
170 fn get_leaf_value(&self, full_path: &Nibbles) -> Option<&Vec<u8>>;
171
172 /// Attempts to find a leaf node at the specified path.
173 ///
174 /// This method traverses the trie from the root down to the given path, checking
175 /// if a leaf exists at that path. It can be used to verify the existence of a leaf
176 /// or to generate an exclusion proof (proof that a leaf does not exist).
177 ///
178 /// # Parameters
179 ///
180 /// - `full_path`: The path to search for.
181 /// - `expected_value`: Optional expected value. If provided, will verify the leaf value
182 /// matches.
183 ///
184 /// # Returns
185 ///
186 /// - `Ok(LeafLookup::Exists)` if the leaf exists with the expected value.
187 /// - `Ok(LeafLookup::NonExistent)` if the leaf definitely does not exist (exclusion proof).
188 /// - `Err(LeafLookupError)` if the search encountered a blinded node or found a different
189 /// value.
190 fn find_leaf(
191 &self,
192 full_path: &Nibbles,
193 expected_value: Option<&Vec<u8>>,
194 ) -> Result<LeafLookup, LeafLookupError>;
195
196 /// Returns a reference to the current sparse trie updates.
197 ///
198 /// If no updates have been made/recorded, returns an empty update set.
199 fn updates_ref(&self) -> Cow<'_, SparseTrieUpdates>;
200
201 /// Consumes and returns the currently accumulated trie updates.
202 ///
203 /// This is useful when you want to apply the updates to an external database
204 /// and then start tracking a new set of updates.
205 ///
206 /// # Returns
207 ///
208 /// The accumulated updates, or an empty set if updates weren't being tracked.
209 fn take_updates(&mut self) -> SparseTrieUpdates;
210
211 /// Removes all nodes and values from the trie, resetting it to a blank state
212 /// with only an empty root node. This is used when a storage root is deleted.
213 ///
214 /// This should not be used when intending to reuse the trie for a fresh account/storage root;
215 /// use `clear` for that.
216 ///
217 /// Note: All previously tracked changes to the trie are also removed.
218 fn wipe(&mut self);
219
220 /// This clears all data structures in the sparse trie, keeping the backing data structures
221 /// allocated. A [`crate::SparseNode::Empty`] is inserted at the root.
222 ///
223 /// This is useful for reusing the trie without needing to reallocate memory.
224 fn clear(&mut self);
225}
226
227/// Struct for passing around branch node mask information.
228///
229/// Branch nodes can have up to 16 children (one for each nibble).
230/// The masks represent which children are stored in different ways:
231/// - `hash_mask`: Indicates which children are stored as hashes in the database
232/// - `tree_mask`: Indicates which children are complete subtrees stored in the database
233///
234/// These masks are essential for efficient trie traversal and serialization, as they
235/// determine how nodes should be encoded and stored on disk.
236#[derive(Debug, PartialEq, Eq, Clone, Copy)]
237pub struct TrieMasks {
238 /// Branch node hash mask, if any.
239 ///
240 /// When a bit is set, the corresponding child node's hash is stored in the trie.
241 ///
242 /// This mask enables selective hashing of child nodes.
243 pub hash_mask: Option<TrieMask>,
244 /// Branch node tree mask, if any.
245 ///
246 /// When a bit is set, the corresponding child subtree is stored in the database.
247 pub tree_mask: Option<TrieMask>,
248}
249
250impl TrieMasks {
251 /// Helper function, returns both fields `hash_mask` and `tree_mask` as [`None`]
252 pub const fn none() -> Self {
253 Self { hash_mask: None, tree_mask: None }
254 }
255}
256
257/// Tracks modifications to the sparse trie structure.
258///
259/// Maintains references to both modified and pruned/removed branches, enabling
260/// one to make batch updates to a persistent database.
261#[derive(Debug, Clone, Default, PartialEq, Eq)]
262pub struct SparseTrieUpdates {
263 /// Collection of updated intermediate nodes indexed by full path.
264 pub updated_nodes: HashMap<Nibbles, BranchNodeCompact>,
265 /// Collection of removed intermediate nodes indexed by full path.
266 pub removed_nodes: HashSet<Nibbles>,
267 /// Flag indicating whether the trie was wiped.
268 pub wiped: bool,
269}
270
271/// Error type for a leaf lookup operation
272#[derive(Debug, Clone, PartialEq, Eq)]
273pub enum LeafLookupError {
274 /// The path leads to a blinded node, cannot determine if leaf exists.
275 /// This means the witness is not complete.
276 BlindedNode {
277 /// Path to the blinded node.
278 path: Nibbles,
279 /// Hash of the blinded node.
280 hash: B256,
281 },
282 /// The path leads to a leaf with a different value than expected.
283 /// This means the witness is malformed.
284 ValueMismatch {
285 /// Path to the leaf.
286 path: Nibbles,
287 /// Expected value.
288 expected: Option<Vec<u8>>,
289 /// Actual value found.
290 actual: Vec<u8>,
291 },
292}
293
294/// Success value for a leaf lookup operation
295#[derive(Debug, Clone, PartialEq, Eq)]
296pub enum LeafLookup {
297 /// Leaf exists with expected value.
298 Exists,
299 /// Leaf does not exist (exclusion proof found).
300 NonExistent,
301}
302
303/// Carries all information needed by a sparse trie to reveal a particular node.
304#[derive(Debug, PartialEq, Eq)]
305pub struct RevealedSparseNode {
306 /// Path of the node.
307 pub path: Nibbles,
308 /// The node itself.
309 pub node: TrieNode,
310 /// Tree and hash masks for the node, if known.
311 pub masks: TrieMasks,
312}