miden_crypto/merkle/smt/large/mod.rs
1//! Large-scale Sparse Merkle Tree backed by pluggable storage.
2//!
3//! `LargeSmt` stores the top of the tree (depths 0–23) in memory and persists the lower
4//! depths (24–64) in storage as fixed-size subtrees. This hybrid layout scales beyond RAM
5//! while keeping common operations fast. With the `rocksdb` feature enabled, the lower
6//! subtrees and leaves are stored in RocksDB. On reopen, the in-memory top is reconstructed
7//! from cached depth-24 subtree roots.
8//!
9//! Examples below require the `rocksdb` feature.
10//!
11//! Open an existing RocksDB-backed tree:
12//! ```no_run
13//! use miden_crypto::merkle::{LargeSmt, RocksDbConfig, RocksDbStorage};
14//!
15//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
16//! let storage = RocksDbStorage::open(RocksDbConfig::new("/path/to/db"))?;
17//! let smt = LargeSmt::new(storage)?; // reconstructs in-memory top if data exists
18//! let _root = smt.root()?;
19//! # Ok(())
20//! # }
21//! ```
22//!
23//! Initialize an empty RocksDB-backed tree and bulk-load entries using mutations:
24//! ```no_run
25//! use miden_crypto::{
26//! Felt, Word,
27//! merkle::{LargeSmt, RocksDbConfig, RocksDbStorage},
28//! };
29//!
30//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
31//! let path = "/path/to/new-db";
32//! if std::path::Path::new(path).exists() {
33//! std::fs::remove_dir_all(path)?;
34//! }
35//! std::fs::create_dir_all(path)?;
36//!
37//! let storage = RocksDbStorage::open(RocksDbConfig::new(path))?;
38//! let mut smt = LargeSmt::new(storage)?; // empty tree
39//!
40//! // Prepare initial entries
41//! let entries = vec![
42//! (
43//! Word::new([Felt::new(1), Felt::new(0), Felt::new(0), Felt::new(0)]),
44//! Word::new([Felt::new(10), Felt::new(20), Felt::new(30), Felt::new(40)]),
45//! ),
46//! (
47//! Word::new([Felt::new(2), Felt::new(0), Felt::new(0), Felt::new(0)]),
48//! Word::new([Felt::new(11), Felt::new(22), Felt::new(33), Felt::new(44)]),
49//! ),
50//! ];
51//!
52//! // Compute and atomically apply the initial bulk load
53//! let mutations = smt.compute_mutations(entries)?;
54//! smt.apply_mutations(mutations)?;
55//! # Ok(())
56//! # }
57//! ```
58//!
59//! Compute and apply a batch of updates atomically:
60//! ```no_run
61//! use miden_crypto::{
62//! EMPTY_WORD, Felt, Word,
63//! merkle::{LargeSmt, RocksDbConfig, RocksDbStorage},
64//! };
65//!
66//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
67//! let storage = RocksDbStorage::open(RocksDbConfig::new("/path/to/db"))?;
68//! let mut smt = LargeSmt::new(storage)?;
69//!
70//! let k1 = Word::new([Felt::new(101), Felt::new(0), Felt::new(0), Felt::new(0)]);
71//! let v1 = Word::new([Felt::new(1), Felt::new(2), Felt::new(3), Felt::new(4)]);
72//! let k2 = Word::new([Felt::new(202), Felt::new(0), Felt::new(0), Felt::new(0)]);
73//! let k3 = Word::new([Felt::new(303), Felt::new(0), Felt::new(0), Felt::new(0)]);
74//! let v3 = Word::new([Felt::new(7), Felt::new(7), Felt::new(7), Felt::new(7)]);
75//!
76//! // EMPTY_WORD marks deletions.
77//! let updates = vec![(k1, v1), (k2, EMPTY_WORD), (k3, v3)];
78//! let mutations = smt.compute_mutations(updates)?;
79//! smt.apply_mutations(mutations)?;
80//! # Ok(())
81//! # }
82//! ```
83//!
84//! Quick initialization with `with_entries` (best for modest datasets/tests):
85//! ```no_run
86//! use miden_crypto::{
87//! Felt, Word,
88//! merkle::{LargeSmt, RocksDbConfig, RocksDbStorage},
89//! };
90//!
91//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
92//! // Note: `with_entries` expects an EMPTY storage and performs an all-at-once build.
93//! // Prefer `compute_mutations` + `apply_mutations` for very large/bulk loads.
94//! let path = "/path/to/new-db";
95//! if std::path::Path::new(path).exists() {
96//! std::fs::remove_dir_all(path)?;
97//! }
98//! std::fs::create_dir_all(path)?;
99//!
100//! let storage = RocksDbStorage::open(RocksDbConfig::new(path))?;
101//! let entries = vec![
102//! (
103//! Word::new([Felt::new(1), Felt::new(0), Felt::new(0), Felt::new(0)]),
104//! Word::new([Felt::new(10), Felt::new(20), Felt::new(30), Felt::new(40)]),
105//! ),
106//! (
107//! Word::new([Felt::new(2), Felt::new(0), Felt::new(0), Felt::new(0)]),
108//! Word::new([Felt::new(11), Felt::new(22), Felt::new(33), Felt::new(44)]),
109//! ),
110//! ];
111//! let _smt = LargeSmt::with_entries(storage, entries)?;
112//! # Ok(())
113//! # }
114//! ```
115use alloc::{boxed::Box, vec::Vec};
116use core::mem;
117
118use num::Integer;
119use rayon::prelude::*;
120
121use super::{
122 EMPTY_WORD, EmptySubtreeRoots, InnerNode, InnerNodeInfo, InnerNodes, LeafIndex, MerkleError,
123 MutationSet, NodeIndex, Rpo256, SMT_DEPTH, Smt, SmtLeaf, SmtLeafError, SmtProof,
124 SparseMerklePath, SparseMerkleTree, Word,
125};
126use crate::merkle::smt::{
127 Map, NodeMutation, NodeMutations,
128 full::concurrent::{
129 MutatedSubtreeLeaves, PairComputations, SUBTREE_DEPTH, SubtreeLeaf, SubtreeLeavesIter,
130 build_subtree, fetch_sibling_pair, process_sorted_pairs_to_leaves,
131 },
132};
133
134mod error;
135pub use error::LargeSmtError;
136
137#[cfg(test)]
138mod tests;
139
140mod subtree;
141pub use subtree::{Subtree, SubtreeError};
142
143mod storage;
144pub use storage::{MemoryStorage, SmtStorage, StorageError, StorageUpdateParts, StorageUpdates};
145#[cfg(feature = "rocksdb")]
146pub use storage::{RocksDbConfig, RocksDbStorage};
147
148// CONSTANTS
149// ================================================================================================
150
151/// Number of levels of the tree that are stored in memory
152const IN_MEMORY_DEPTH: u8 = 24;
153
154/// Number of nodes that are stored in memory (including the unused index 0)
155const NUM_IN_MEMORY_NODES: usize = 1 << (IN_MEMORY_DEPTH + 1);
156
157/// Number of subtree levels below in-memory depth (24-64 in steps of 8)
158const NUM_SUBTREE_LEVELS: usize = 5;
159
160/// How many subtrees we buffer before flushing them to storage **during the
161/// SMT construction phase**.
162///
163/// * This constant is **only** used while building a fresh tree; incremental updates use their own
164/// per-batch sizing.
165/// * Construction is all-or-nothing: if the write fails we abort and rebuild from scratch, so we
166/// allow larger batches that maximise I/O throughput instead of fine-grained rollback safety.
167const CONSTRUCTION_SUBTREE_BATCH_SIZE: usize = 10_000;
168
169// TYPES
170// ================================================================================================
171
172type Leaves = super::Leaves<SmtLeaf>;
173// LargeSmt
174// ================================================================================================
175
176/// A large-scale Sparse Merkle tree mapping 256-bit keys to 256-bit values, backed by pluggable
177/// storage. Both keys and values are represented by 4 field elements.
178///
179/// Unlike the regular `Smt`, this implementation is designed for very large trees by using external
180/// storage (such as RocksDB) for the bulk of the tree data, while keeping only the upper levels (up
181/// to depth 24) in memory. This hybrid approach allows the tree to scale beyond memory limitations
182/// while maintaining good performance for common operations.
183///
184/// All leaves sit at depth 64. The most significant element of the key is used to identify the leaf
185/// to which the key maps.
186///
187/// A leaf is either empty, or holds one or more key-value pairs. An empty leaf hashes to the empty
188/// word. Otherwise, a leaf hashes to the hash of its key-value pairs, ordered by key first, value
189/// second.
190///
191/// The tree structure:
192/// - Depths 0-23: Stored in memory as a flat array for fast access
193/// - Depths 24-64: Stored in external storage organized as subtrees for efficient batch operations
194#[derive(Debug)]
195pub struct LargeSmt<S: SmtStorage> {
196 storage: S,
197 /// Flat vector representation of in-memory nodes.
198 /// Index 0 is unused; index 1 is root.
199 /// For node at index i: left child at 2*i, right child at 2*i+1.
200 in_memory_nodes: Vec<Word>,
201}
202
203impl<S: SmtStorage> LargeSmt<S> {
204 // CONSTANTS
205 // --------------------------------------------------------------------------------------------
206 /// The default value used to compute the hash of empty leaves.
207 pub const EMPTY_VALUE: Word = <Self as SparseMerkleTree<SMT_DEPTH>>::EMPTY_VALUE;
208
209 /// Subtree depths for the subtrees stored in storage.
210 pub const SUBTREE_DEPTHS: [u8; 5] = [56, 48, 40, 32, 24];
211
212 // CONSTRUCTORS
213 // --------------------------------------------------------------------------------------------
214
215 /// Returns a new [LargeSmt] backed by the provided storage.
216 ///
217 /// The SMT's root is fetched from the storage backend. If the storage is empty the SMT is
218 /// initialized with the root of an empty tree. Otherwise, materializes in-memory nodes from
219 /// the top subtrees.
220 ///
221 /// # Errors
222 /// Returns an error if fetching the root or initial in-memory nodes from the storage fails.
223 pub fn new(storage: S) -> Result<Self, LargeSmtError> {
224 let root = storage.get_root()?.unwrap_or(*EmptySubtreeRoots::entry(SMT_DEPTH, 0));
225
226 let is_empty = !storage.has_leaves()?;
227
228 // Initialize in-memory nodes
229 let mut in_memory_nodes: Vec<Word> = vec![EMPTY_WORD; NUM_IN_MEMORY_NODES];
230
231 for depth in 0..IN_MEMORY_DEPTH {
232 let child_empty_hash = *EmptySubtreeRoots::entry(SMT_DEPTH, depth + 1);
233 let start = 2 * (1 << depth);
234 let end = 2 * (1 << (depth + 1));
235 in_memory_nodes[start..end].fill(child_empty_hash);
236 }
237
238 // No leaves, return empty tree
239 if is_empty {
240 return Ok(Self { storage, in_memory_nodes });
241 }
242
243 let subtree_roots = storage.get_depth24()?;
244
245 // convert subtree roots to SubtreeLeaf
246 let mut leaf_subtrees: Vec<SubtreeLeaf> = subtree_roots
247 .into_iter()
248 .map(|(index, hash)| SubtreeLeaf { col: index, hash })
249 .collect();
250 leaf_subtrees.sort_by_key(|leaf| leaf.col);
251
252 let mut subtree_leaves: Vec<Vec<SubtreeLeaf>> =
253 SubtreeLeavesIter::from_leaves(&mut leaf_subtrees).collect();
254
255 // build in-memory top of the tree
256 for current_depth in (SUBTREE_DEPTH..=IN_MEMORY_DEPTH).step_by(SUBTREE_DEPTH as usize).rev()
257 {
258 let (nodes, mut subtree_roots): (Vec<Map<_, _>>, Vec<SubtreeLeaf>) = subtree_leaves
259 .into_par_iter()
260 .map(|subtree| {
261 debug_assert!(subtree.is_sorted());
262 debug_assert!(!subtree.is_empty());
263 let (nodes, subtree_root) = build_subtree(subtree, SMT_DEPTH, current_depth);
264 (nodes, subtree_root)
265 })
266 .unzip();
267 subtree_leaves = SubtreeLeavesIter::from_leaves(&mut subtree_roots).collect();
268 debug_assert!(!subtree_leaves.is_empty());
269
270 for subtree_nodes in nodes {
271 for (index, node) in subtree_nodes {
272 let memory_index = to_memory_index(&index);
273 // Store left and right children in flat layout
274 in_memory_nodes[memory_index * 2] = node.left;
275 in_memory_nodes[memory_index * 2 + 1] = node.right;
276 }
277 }
278 }
279
280 // Check that the calculated root matches the root in storage
281 // Root is at index 1, with children at indices 2 and 3
282 let calculated_root = Rpo256::merge(&[in_memory_nodes[2], in_memory_nodes[3]]);
283 assert_eq!(calculated_root, root, "Tree reconstruction failed - root mismatch");
284
285 Ok(Self { storage, in_memory_nodes })
286 }
287
288 /// Returns a new [Smt] instantiated with leaves set as specified by the provided entries.
289 ///
290 /// If the `concurrent` feature is enabled, this function uses a parallel implementation to
291 /// process the entries efficiently, otherwise it defaults to the sequential implementation.
292 ///
293 /// All leaves omitted from the entries list are set to [Self::EMPTY_VALUE].
294 ///
295 /// # Errors
296 /// Returns an error if the provided entries contain multiple values for the same key.
297 pub fn with_entries(
298 storage: S,
299 entries: impl IntoIterator<Item = (Word, Word)>,
300 ) -> Result<Self, LargeSmtError> {
301 let entries: Vec<(Word, Word)> = entries.into_iter().collect();
302
303 if storage.has_leaves()? {
304 return Err(StorageError::Unsupported(
305 "Cannot create SMT with non-empty storage".into(),
306 )
307 .into());
308 }
309 let mut tree = LargeSmt::new(storage)?;
310 if entries.is_empty() {
311 return Ok(tree);
312 }
313 tree.build_subtrees(entries)?;
314 Ok(tree)
315 }
316
317 // PUBLIC ACCESSORS
318 // --------------------------------------------------------------------------------------------
319
320 /// Returns the depth of the tree
321 pub const fn depth(&self) -> u8 {
322 SMT_DEPTH
323 }
324
325 /// Returns the root of the tree
326 pub fn root(&self) -> Result<Word, LargeSmtError> {
327 Ok(self.storage.get_root()?.unwrap_or(Self::EMPTY_ROOT))
328 }
329
330 /// Returns the number of non-empty leaves in this tree.
331 ///
332 /// Note that this may return a different value from [Self::num_entries()] as a single leaf may
333 /// contain more than one key-value pair.
334 ///
335 /// # Errors
336 /// Returns an error if there is a storage error when retrieving the leaf count.
337 pub fn num_leaves(&self) -> Result<usize, LargeSmtError> {
338 Ok(self.storage.leaf_count()?)
339 }
340
341 /// Returns the number of key-value pairs with non-default values in this tree.
342 ///
343 /// Note that this may return a different value from [Self::num_leaves()] as a single leaf may
344 /// contain more than one key-value pair.
345 ///
346 /// Also note that this is currently an expensive operation is counting the number of entries
347 /// requires iterating over all leaves of the tree.
348 ///
349 /// # Errors
350 /// Returns an error if there is a storage error when retrieving the entry count.
351 pub fn num_entries(&self) -> Result<usize, LargeSmtError> {
352 Ok(self.storage.entry_count()?)
353 }
354
355 /// Returns the leaf to which `key` maps
356 pub fn get_leaf(&self, key: &Word) -> SmtLeaf {
357 <Self as SparseMerkleTree<SMT_DEPTH>>::get_leaf(self, key)
358 }
359
360 /// Returns the value associated with `key`
361 pub fn get_value(&self, key: &Word) -> Word {
362 <Self as SparseMerkleTree<SMT_DEPTH>>::get_value(self, key)
363 }
364
365 /// Returns an opening of the leaf associated with `key`. Conceptually, an opening is a Merkle
366 /// path to the leaf, as well as the leaf itself.
367 pub fn open(&self, key: &Word) -> SmtProof {
368 <Self as SparseMerkleTree<SMT_DEPTH>>::open(self, key)
369 }
370
371 /// Returns a boolean value indicating whether the SMT is empty.
372 ///
373 /// # Errors
374 /// Returns an error if there is a storage error when retrieving the root or leaf count.
375 pub fn is_empty(&self) -> Result<bool, LargeSmtError> {
376 let root = self.storage.get_root()?.unwrap_or(Self::EMPTY_ROOT);
377 debug_assert_eq!(self.num_leaves()? == 0, root == Self::EMPTY_ROOT);
378 Ok(root == Self::EMPTY_ROOT)
379 }
380
381 // ITERATORS
382 // --------------------------------------------------------------------------------------------
383
384 /// Returns an iterator over the leaves of this [Smt].
385 /// Note: This iterator returns owned SmtLeaf values.
386 ///
387 /// # Errors
388 /// Returns an error if the storage backend fails to create the iterator.
389 pub fn leaves(
390 &self,
391 ) -> Result<impl Iterator<Item = (LeafIndex<SMT_DEPTH>, SmtLeaf)>, LargeSmtError> {
392 let iter = self.storage.iter_leaves()?;
393 Ok(iter.map(|(idx, leaf)| (LeafIndex::new_max_depth(idx), leaf)))
394 }
395
396 /// Returns an iterator over the key-value pairs of this [Smt].
397 /// Note: This iterator returns owned (Word, Word) tuples.
398 ///
399 /// # Errors
400 /// Returns an error if the storage backend fails to create the iterator.
401 pub fn entries(&self) -> Result<impl Iterator<Item = (Word, Word)>, LargeSmtError> {
402 let leaves_iter = self.leaves()?;
403 Ok(leaves_iter.flat_map(|(_, leaf)| {
404 // Collect the (Word, Word) tuples into an owned Vec
405 // This ensures they outlive the 'leaf' from which they are derived.
406 let owned_entries: Vec<(Word, Word)> = leaf.entries().to_vec();
407 // Return an iterator over this owned Vec
408 owned_entries.into_iter()
409 }))
410 }
411
412 /// Returns an iterator over the inner nodes of this [Smt].
413 ///
414 /// # Errors
415 /// Returns an error if the storage backend fails during iteration setup.
416 pub fn inner_nodes(&self) -> Result<impl Iterator<Item = InnerNodeInfo> + '_, LargeSmtError> {
417 // Pre-validate that storage is accessible
418 let _ = self.storage.iter_subtrees()?;
419 Ok(LargeSmtInnerNodeIterator::new(self))
420 }
421
422 // STATE MUTATORS
423 // --------------------------------------------------------------------------------------------
424
425 /// Inserts a value at the specified key, returning the previous value associated with that key.
426 /// Recall that by definition, any key that hasn't been updated is associated with
427 /// [`Self::EMPTY_VALUE`].
428 ///
429 /// This also recomputes all hashes between the leaf (associated with the key) and the root,
430 /// updating the root itself.
431 ///
432 /// # Errors
433 /// Returns an error if inserting the key-value pair would exceed
434 /// [`MAX_LEAF_ENTRIES`](super::MAX_LEAF_ENTRIES) (1024 entries) in the leaf.
435 pub fn insert(&mut self, key: Word, value: Word) -> Result<Word, MerkleError> {
436 <Self as SparseMerkleTree<SMT_DEPTH>>::insert(self, key, value)
437 }
438
439 /// Computes what changes are necessary to insert the specified key-value pairs into this Merkle
440 /// tree, allowing for validation before applying those changes.
441 ///
442 /// This method returns a [`MutationSet`], which contains all the information for inserting
443 /// `kv_pairs` into this Merkle tree already calculated, including the new root hash, which can
444 /// be queried with [`MutationSet::root()`]. Once a mutation set is returned,
445 /// [`Smt::apply_mutations()`] can be called in order to commit these changes to the Merkle
446 /// tree, or [`drop()`] to discard them.
447 ///
448 /// # Example
449 /// ```
450 /// # use miden_crypto::{Felt, Word};
451 /// # use miden_crypto::merkle::{Smt, EmptySubtreeRoots, SMT_DEPTH};
452 /// let mut smt = Smt::new();
453 /// let pair = (Word::default(), Word::default());
454 /// let mutations = smt.compute_mutations(vec![pair]).expect("compute_mutations ok");
455 /// assert_eq!(mutations.root(), *EmptySubtreeRoots::entry(SMT_DEPTH, 0));
456 /// smt.apply_mutations(mutations);
457 /// assert_eq!(smt.root(), *EmptySubtreeRoots::entry(SMT_DEPTH, 0));
458 /// ```
459 pub fn compute_mutations(
460 &self,
461 kv_pairs: impl IntoIterator<Item = (Word, Word)>,
462 ) -> Result<MutationSet<SMT_DEPTH, Word, Word>, LargeSmtError>
463 where
464 Self: Sized + Sync,
465 {
466 // Collect and sort key-value pairs by their corresponding leaf index
467 let mut sorted_kv_pairs: Vec<_> = kv_pairs.into_iter().collect();
468 sorted_kv_pairs.par_sort_unstable_by_key(|(key, _)| Self::key_to_leaf_index(key).value());
469
470 // Collect the unique leaf indices
471 let mut leaf_indices: Vec<u64> = sorted_kv_pairs
472 .iter()
473 .map(|(key, _)| Self::key_to_leaf_index(key).value())
474 .collect();
475 leaf_indices.dedup();
476 leaf_indices.sort_unstable();
477
478 // Get leaves from storage
479 let leaves_from_storage = self.storage.get_leaves(&leaf_indices)?;
480
481 // Map leaf indices to their corresponding leaves
482 let leaf_map: Map<u64, SmtLeaf> = leaf_indices
483 .into_iter()
484 .zip(leaves_from_storage)
485 .filter_map(|(index, maybe_leaf)| maybe_leaf.map(|leaf| (index, leaf)))
486 .collect();
487
488 // Convert sorted pairs into mutated leaves and capture any new pairs
489 let (mut leaves, new_pairs) =
490 self.sorted_pairs_to_mutated_leaves_with_preloaded_leaves(sorted_kv_pairs, leaf_map);
491
492 // If no mutations, return an empty mutation set
493 let old_root = self.root()?;
494 if leaves.is_empty() {
495 return Ok(MutationSet {
496 old_root,
497 new_root: old_root,
498 node_mutations: NodeMutations::default(),
499 new_pairs,
500 });
501 }
502
503 let mut node_mutations = NodeMutations::default();
504
505 // Process each depth level in reverse, stepping by the subtree depth
506 for subtree_root_depth in
507 (0..=SMT_DEPTH - SUBTREE_DEPTH).step_by(SUBTREE_DEPTH as usize).rev()
508 {
509 // Parallel processing of each subtree to generate mutations and roots
510 let (mutations_per_subtree, mut subtree_roots): (Vec<_>, Vec<_>) = leaves
511 .into_par_iter()
512 .map(|subtree_leaves| {
513 let subtree: Option<Subtree> = if subtree_root_depth < IN_MEMORY_DEPTH {
514 None
515 } else {
516 // Compute subtree root index
517 let subtree_root_index = NodeIndex::new_unchecked(
518 subtree_root_depth,
519 subtree_leaves[0].col >> SUBTREE_DEPTH,
520 );
521 self.storage
522 .get_subtree(subtree_root_index)
523 .expect("Storage error getting subtree in compute_mutations")
524 };
525 debug_assert!(subtree_leaves.is_sorted() && !subtree_leaves.is_empty());
526 self.build_subtree_mutations(
527 subtree_leaves,
528 SMT_DEPTH,
529 subtree_root_depth,
530 subtree,
531 )
532 })
533 .unzip();
534
535 // Prepare leaves for the next depth level
536 leaves = SubtreeLeavesIter::from_leaves(&mut subtree_roots).collect();
537
538 // Aggregate all node mutations
539 node_mutations.extend(mutations_per_subtree.into_iter().flatten());
540
541 debug_assert!(!leaves.is_empty());
542 }
543
544 let new_root = leaves[0][0].hash;
545
546 // Create mutation set
547 let mutation_set = MutationSet {
548 old_root: self.root()?,
549 new_root,
550 node_mutations,
551 new_pairs,
552 };
553
554 // There should be mutations and new pairs at this point
555 debug_assert!(
556 !mutation_set.node_mutations().is_empty() && !mutation_set.new_pairs().is_empty()
557 );
558
559 Ok(mutation_set)
560 }
561
562 /// Applies the prospective mutations computed with [`Smt::compute_mutations()`] to this tree.
563 ///
564 /// # Errors
565 /// If `mutations` was computed on a tree with a different root than this one, returns
566 /// [`MerkleError::ConflictingRoots`] with a two-item [`Vec`]. The first item is the root hash
567 /// the `mutations` were computed against, and the second item is the actual current root of
568 /// this tree.
569 pub fn apply_mutations(
570 &mut self,
571 mutations: MutationSet<SMT_DEPTH, Word, Word>,
572 ) -> Result<(), LargeSmtError> {
573 use NodeMutation::*;
574 use rayon::prelude::*;
575 let MutationSet {
576 old_root,
577 node_mutations,
578 new_pairs,
579 new_root,
580 } = mutations;
581
582 // Guard against accidentally trying to apply mutations that were computed against a
583 // different tree, including a stale version of this tree.
584 let expected_root = self.root()?;
585 if old_root != expected_root {
586 return Err(LargeSmtError::Merkle(MerkleError::ConflictingRoots {
587 expected_root,
588 actual_root: old_root,
589 }));
590 }
591
592 // Sort mutations
593 let mut sorted_mutations: Vec<_> = Vec::from_iter(node_mutations);
594 sorted_mutations.par_sort_unstable_by_key(|(index, _)| Subtree::find_subtree_root(*index));
595
596 // Collect all unique subtree root indexes needed
597 let mut subtree_roots_indices: Vec<NodeIndex> = sorted_mutations
598 .iter()
599 .filter_map(|(index, _)| {
600 if index.depth() < IN_MEMORY_DEPTH {
601 None
602 } else {
603 Some(Subtree::find_subtree_root(*index))
604 }
605 })
606 .collect();
607 subtree_roots_indices.dedup();
608
609 // Read all subtrees at once
610 let subtrees_from_storage = self.storage.get_subtrees(&subtree_roots_indices)?;
611
612 // Map the subtrees
613 let mut loaded_subtrees: Map<NodeIndex, Option<Subtree>> = subtree_roots_indices
614 .into_iter()
615 .zip(subtrees_from_storage)
616 .map(|(root_index, subtree_opt)| {
617 (root_index, Some(subtree_opt.unwrap_or_else(|| Subtree::new(root_index))))
618 })
619 .collect();
620
621 // Process mutations
622 for (index, mutation) in sorted_mutations {
623 if index.depth() < IN_MEMORY_DEPTH {
624 match mutation {
625 Removal => self.remove_inner_node(index),
626 Addition(node) => self.insert_inner_node(index, node),
627 };
628 } else {
629 let subtree_root_index = Subtree::find_subtree_root(index);
630 let subtree = loaded_subtrees
631 .get_mut(&subtree_root_index)
632 .expect("Subtree map entry must exist")
633 .as_mut()
634 .expect("Subtree must exist as it was either fetched or created");
635
636 match mutation {
637 Removal => subtree.remove_inner_node(index),
638 Addition(node) => subtree.insert_inner_node(index, node),
639 };
640 }
641 }
642
643 // Go through subtrees, see if any are empty, and if so remove them
644 for (_index, subtree) in loaded_subtrees.iter_mut() {
645 if subtree.as_ref().is_some_and(|s| s.is_empty()) {
646 *subtree = None;
647 }
648 }
649
650 // Collect and sort key-value pairs by their corresponding leaf index
651 let mut sorted_kv_pairs: Vec<_> = new_pairs.iter().map(|(k, v)| (*k, *v)).collect();
652 sorted_kv_pairs.par_sort_by_key(|(key, _)| Self::key_to_leaf_index(key).value());
653
654 // Collect the unique leaf indices
655 let mut leaf_indices: Vec<u64> = sorted_kv_pairs
656 .iter()
657 .map(|(key, _)| Self::key_to_leaf_index(key).value())
658 .collect();
659 leaf_indices.par_sort_unstable();
660 leaf_indices.dedup();
661
662 // Get leaves from storage
663 let leaves = self.storage.get_leaves(&leaf_indices)?;
664
665 // Map leaf indices to their corresponding leaves
666 let mut leaf_map: Map<u64, Option<SmtLeaf>> =
667 leaf_indices.into_iter().zip(leaves).collect();
668
669 let mut leaf_count_delta = 0isize;
670 let mut entry_count_delta = 0isize;
671
672 for (key, value) in new_pairs {
673 let idx = Self::key_to_leaf_index(&key).value();
674 // Get leaf
675 let entry = leaf_map.entry(idx).or_insert(None);
676
677 // New values is empty, handle deletion
678 if value == Self::EMPTY_VALUE {
679 if let Some(leaf) = entry {
680 // Leaf exists, handle deletion
681 if leaf.remove(key).1 {
682 // Key had previous value, decrement entry count
683 entry_count_delta -= 1;
684 if leaf.is_empty() {
685 // Leaf is now empty, remove it and decrement leaf count
686 *entry = None;
687 leaf_count_delta -= 1;
688 }
689 }
690 }
691 } else {
692 // New value is not empty, handle update or create
693 match entry {
694 Some(leaf) => {
695 // Leaf exists, handle update
696 if leaf.insert(key, value).expect("Failed to insert value").is_none() {
697 // Key had no previous value, increment entry count
698 entry_count_delta += 1;
699 }
700 },
701 None => {
702 // Leaf does not exist, create it
703 *entry = Some(SmtLeaf::Single((key, value)));
704 // Increment both entry and leaf count
705 entry_count_delta += 1;
706 leaf_count_delta += 1;
707 },
708 }
709 }
710 }
711
712 let updates = StorageUpdates::from_parts(
713 leaf_map,
714 loaded_subtrees,
715 new_root,
716 leaf_count_delta,
717 entry_count_delta,
718 );
719 self.storage.apply(updates)?;
720 Ok(())
721 }
722
723 /// Applies the prospective mutations computed with [`Smt::compute_mutations()`] to this tree
724 /// and returns the reverse mutation set.
725 ///
726 /// Applying the reverse mutation sets to the updated tree will revert the changes.
727 ///
728 /// # Errors
729 /// If `mutations` was computed on a tree with a different root than this one, returns
730 /// [`MerkleError::ConflictingRoots`] with a two-item [`Vec`]. The first item is the root hash
731 /// the `mutations` were computed against, and the second item is the actual current root of
732 /// this tree.
733 pub fn apply_mutations_with_reversion(
734 &mut self,
735 mutations: MutationSet<SMT_DEPTH, Word, Word>,
736 ) -> Result<MutationSet<SMT_DEPTH, Word, Word>, LargeSmtError>
737 where
738 Self: Sized,
739 {
740 use NodeMutation::*;
741 let MutationSet {
742 old_root,
743 node_mutations,
744 new_pairs,
745 new_root,
746 } = mutations;
747
748 let mut reverse_mutations = NodeMutations::new();
749 for (index, mutation) in node_mutations {
750 match mutation {
751 Removal => {
752 if let Some(node) = self.remove_inner_node(index) {
753 reverse_mutations.insert(index, Addition(node));
754 }
755 },
756 Addition(node) => {
757 if let Some(old_node) = self.insert_inner_node(index, node) {
758 reverse_mutations.insert(index, Addition(old_node));
759 } else {
760 reverse_mutations.insert(index, Removal);
761 }
762 },
763 }
764 }
765
766 let mut reverse_pairs = Map::new();
767 for (key, value) in new_pairs {
768 if let Some(old_value) = self.insert_value(key, value)? {
769 reverse_pairs.insert(key, old_value);
770 } else {
771 reverse_pairs.insert(key, Self::EMPTY_VALUE);
772 }
773 }
774
775 self.set_root(new_root);
776
777 Ok(MutationSet {
778 old_root: new_root,
779 node_mutations: reverse_mutations,
780 new_pairs: reverse_pairs,
781 new_root: old_root,
782 })
783 }
784
785 // HELPERS
786 // --------------------------------------------------------------------------------------------
787
788 fn build_subtrees(&mut self, mut entries: Vec<(Word, Word)>) -> Result<(), MerkleError> {
789 entries.par_sort_unstable_by_key(|item| {
790 let index = Self::key_to_leaf_index(&item.0);
791 index.value()
792 });
793 self.build_subtrees_from_sorted_entries(entries)?;
794 Ok(())
795 }
796
797 fn build_subtrees_from_sorted_entries(
798 &mut self,
799 entries: Vec<(Word, Word)>,
800 ) -> Result<(), MerkleError> {
801 let PairComputations {
802 leaves: mut leaf_subtrees,
803 nodes: initial_leaves,
804 } = Smt::sorted_pairs_to_leaves(entries)?;
805
806 if initial_leaves.is_empty() {
807 return Ok(());
808 }
809
810 // Store the initial leaves
811 self.storage.set_leaves(initial_leaves).expect("Failed to store initial leaves");
812
813 // build deep (disk-backed) subtrees
814 leaf_subtrees = std::thread::scope(|scope| {
815 let (sender, receiver) = flume::bounded(CONSTRUCTION_SUBTREE_BATCH_SIZE);
816 let storage: &S = &self.storage;
817
818 scope.spawn(move || -> Result<(), MerkleError> {
819 let mut subtrees: Vec<Subtree> =
820 Vec::with_capacity(CONSTRUCTION_SUBTREE_BATCH_SIZE);
821 for subtree in receiver.iter() {
822 subtrees.push(subtree);
823 if subtrees.len() == CONSTRUCTION_SUBTREE_BATCH_SIZE {
824 let subtrees_clone = mem::take(&mut subtrees);
825 storage
826 .set_subtrees(subtrees_clone)
827 .expect("Writer thread failed to set subtrees");
828 }
829 }
830 storage.set_subtrees(subtrees).expect("Writer thread failed to set subtrees");
831 Ok(())
832 });
833
834 for bottom_depth in (IN_MEMORY_DEPTH + SUBTREE_DEPTH..=SMT_DEPTH)
835 .step_by(SUBTREE_DEPTH as usize)
836 .rev()
837 {
838 let mut subtree_roots: Vec<SubtreeLeaf> = leaf_subtrees
839 .into_par_iter()
840 .map(|subtree_leaves| {
841 debug_assert!(subtree_leaves.is_sorted());
842 debug_assert!(!subtree_leaves.is_empty());
843 let (nodes, subtree_root) =
844 build_subtree(subtree_leaves, SMT_DEPTH, bottom_depth);
845
846 let subtree_root_index =
847 NodeIndex::new(bottom_depth - SUBTREE_DEPTH, subtree_root.col).unwrap();
848 let mut subtree = Subtree::new(subtree_root_index);
849 for (index, node) in nodes {
850 subtree.insert_inner_node(index, node);
851 }
852 sender.send(subtree).expect("Flume channel disconnected unexpectedly");
853 subtree_root
854 })
855 .collect();
856 leaf_subtrees = SubtreeLeavesIter::from_leaves(&mut subtree_roots).collect();
857 debug_assert!(!leaf_subtrees.is_empty());
858 }
859
860 drop(sender);
861 leaf_subtrees
862 });
863
864 // build top of the tree (in-memory only, normal insert)
865 for bottom_depth in (SUBTREE_DEPTH..=IN_MEMORY_DEPTH).step_by(SUBTREE_DEPTH as usize).rev()
866 {
867 let (nodes, mut subtree_roots): (Vec<Map<_, _>>, Vec<SubtreeLeaf>) = leaf_subtrees
868 .into_par_iter()
869 .map(|subtree| {
870 debug_assert!(subtree.is_sorted());
871 debug_assert!(!subtree.is_empty());
872 let (nodes, subtree_root) = build_subtree(subtree, SMT_DEPTH, bottom_depth);
873 (nodes, subtree_root)
874 })
875 .unzip();
876 leaf_subtrees = SubtreeLeavesIter::from_leaves(&mut subtree_roots).collect();
877 debug_assert!(!leaf_subtrees.is_empty());
878
879 for subtree_nodes in nodes {
880 self.insert_inner_nodes_batch(subtree_nodes.into_iter());
881 }
882 }
883 self.set_root(self.get_inner_node(NodeIndex::root()).hash());
884 Ok(())
885 }
886
887 // MUTATIONS
888 // --------------------------------------------------------------------------------------------
889
890 /// Computes leaves from a set of key-value pairs and current leaf values.
891 /// Derived from `sorted_pairs_to_leaves`
892 fn sorted_pairs_to_mutated_leaves_with_preloaded_leaves(
893 &self,
894 pairs: Vec<(Word, Word)>,
895 leaf_map: Map<u64, SmtLeaf>,
896 ) -> (MutatedSubtreeLeaves, Map<Word, Word>) {
897 // Map to track new key-value pairs for mutated leaves
898 let mut new_pairs = Map::new();
899
900 let accumulator = process_sorted_pairs_to_leaves(pairs, |leaf_pairs| {
901 let leaf_index = LeafIndex::<SMT_DEPTH>::from(leaf_pairs[0].0);
902 let mut leaf = leaf_map
903 .get(&leaf_index.value())
904 .cloned()
905 .unwrap_or_else(|| SmtLeaf::new_empty(leaf_pairs[0].0.into()));
906
907 let mut leaf_changed = false;
908 for (key, value) in leaf_pairs {
909 // Check if the value has changed
910 let old_value = new_pairs.get(&key).cloned().unwrap_or_else(|| {
911 // Safe to unwrap: `leaf_pairs` contains keys all belonging to this leaf.
912 // `SmtLeaf::get_value()` only returns `None` if the key does not belong to the
913 // leaf, which cannot happen due to the sorting/grouping
914 // logic in `process_sorted_pairs_to_leaves()`.
915 leaf.get_value(&key).unwrap()
916 });
917
918 if value != old_value {
919 // Update the leaf and track the new key-value pair
920 leaf = self
921 .construct_prospective_leaf(leaf, &key, &value)
922 .expect("Failed to construct prospective leaf");
923 new_pairs.insert(key, value);
924 leaf_changed = true;
925 }
926 }
927
928 if leaf_changed {
929 // Only return the leaf if it actually changed
930 Ok(Some(leaf))
931 } else {
932 // Return None if leaf hasn't changed
933 Ok(None)
934 }
935 });
936 // The closure is the only possible source of errors.
937 // Since it never returns an error - only `Ok(Some(_))` or `Ok(None)` - we can safely assume
938 // `accumulator` is always `Ok(_)`.
939 (
940 accumulator.expect("process_sorted_pairs_to_leaves never fails").leaves,
941 new_pairs,
942 )
943 }
944
945 /// Computes the node mutations and the root of a subtree
946 fn build_subtree_mutations(
947 &self,
948 mut leaves: Vec<SubtreeLeaf>,
949 tree_depth: u8,
950 subtree_root_depth: u8,
951 subtree: Option<Subtree>,
952 ) -> (NodeMutations, SubtreeLeaf)
953 where
954 Self: Sized,
955 {
956 let bottom_depth = subtree_root_depth + SUBTREE_DEPTH;
957
958 debug_assert!(bottom_depth <= tree_depth);
959 debug_assert!(Integer::is_multiple_of(&bottom_depth, &SUBTREE_DEPTH));
960 debug_assert!(leaves.len() <= usize::pow(2, SUBTREE_DEPTH as u32));
961
962 let mut node_mutations: NodeMutations = Default::default();
963 let mut next_leaves: Vec<SubtreeLeaf> = Vec::with_capacity(leaves.len() / 2);
964
965 for current_depth in (subtree_root_depth..bottom_depth).rev() {
966 debug_assert!(current_depth <= bottom_depth);
967
968 let next_depth = current_depth + 1;
969 let mut iter = leaves.drain(..).peekable();
970
971 while let Some(first_leaf) = iter.next() {
972 // This constructs a valid index because next_depth will never exceed the depth of
973 // the tree.
974 let parent_index = NodeIndex::new_unchecked(next_depth, first_leaf.col).parent();
975 let parent_node = if let Some(ref sub) = subtree {
976 sub.get_inner_node(parent_index).unwrap_or_else(|| {
977 EmptySubtreeRoots::get_inner_node(SMT_DEPTH, parent_index.depth())
978 })
979 } else if subtree_root_depth >= IN_MEMORY_DEPTH {
980 EmptySubtreeRoots::get_inner_node(SMT_DEPTH, parent_index.depth())
981 } else {
982 self.get_inner_node(parent_index)
983 };
984 let combined_node = fetch_sibling_pair(&mut iter, first_leaf, parent_node);
985 let combined_hash = combined_node.hash();
986
987 let &empty_hash = EmptySubtreeRoots::entry(tree_depth, current_depth);
988
989 // Add the parent node even if it is empty for proper upward updates
990 next_leaves.push(SubtreeLeaf {
991 col: parent_index.value(),
992 hash: combined_hash,
993 });
994
995 node_mutations.insert(
996 parent_index,
997 if combined_hash != empty_hash {
998 NodeMutation::Addition(combined_node)
999 } else {
1000 NodeMutation::Removal
1001 },
1002 );
1003 }
1004 drop(iter);
1005 leaves = mem::take(&mut next_leaves);
1006 }
1007
1008 debug_assert_eq!(leaves.len(), 1);
1009 let root_leaf = leaves.pop().unwrap();
1010 (node_mutations, root_leaf)
1011 }
1012
1013 // STORAGE
1014 // --------------------------------------------------------------------------------------------
1015
1016 // Inserts batch of upper inner nodes
1017 fn insert_inner_nodes_batch(
1018 &mut self,
1019 nodes: impl IntoIterator<Item = (NodeIndex, InnerNode)>,
1020 ) {
1021 for (index, node) in nodes {
1022 if index.depth() < IN_MEMORY_DEPTH {
1023 let memory_index = to_memory_index(&index);
1024 // Store in flat layout: left at 2*i, right at 2*i+1
1025 self.in_memory_nodes[memory_index * 2] = node.left;
1026 self.in_memory_nodes[memory_index * 2 + 1] = node.right;
1027 }
1028 }
1029 }
1030
1031 // TEST HELPERS
1032 // --------------------------------------------------------------------------------------------
1033
1034 #[cfg(test)]
1035 pub(crate) fn in_memory_nodes(&self) -> &Vec<Word> {
1036 &self.in_memory_nodes
1037 }
1038}
1039
1040impl<S: SmtStorage> SparseMerkleTree<SMT_DEPTH> for LargeSmt<S> {
1041 type Key = Word;
1042 type Value = Word;
1043 type Leaf = SmtLeaf;
1044 type Opening = SmtProof;
1045
1046 const EMPTY_VALUE: Self::Value = EMPTY_WORD;
1047 const EMPTY_ROOT: Word = *EmptySubtreeRoots::entry(SMT_DEPTH, 0);
1048
1049 fn from_raw_parts(
1050 _inner_nodes: InnerNodes,
1051 _leaves: Leaves,
1052 _root: Word,
1053 ) -> Result<Self, MerkleError> {
1054 // This method is not supported
1055 panic!("LargeSmt::from_raw_parts is not supported");
1056 }
1057
1058 fn root(&self) -> Word {
1059 self.storage.get_root().ok().flatten().unwrap_or(Self::EMPTY_ROOT)
1060 }
1061
1062 fn set_root(&mut self, root: Word) {
1063 self.storage.set_root(root).expect("Failed to set root");
1064 }
1065
1066 fn get_inner_node(&self, index: NodeIndex) -> InnerNode {
1067 if index.depth() < IN_MEMORY_DEPTH {
1068 let memory_index = to_memory_index(&index);
1069 // Reconstruct InnerNode from flat layout: left at 2*i, right at 2*i+1
1070 return InnerNode {
1071 left: self.in_memory_nodes[memory_index * 2],
1072 right: self.in_memory_nodes[memory_index * 2 + 1],
1073 };
1074 }
1075
1076 self.storage
1077 .get_inner_node(index)
1078 .expect("Failed to get inner node")
1079 .unwrap_or_else(|| EmptySubtreeRoots::get_inner_node(SMT_DEPTH, index.depth()))
1080 }
1081
1082 fn insert_inner_node(&mut self, index: NodeIndex, inner_node: InnerNode) -> Option<InnerNode> {
1083 if index.depth() < IN_MEMORY_DEPTH {
1084 let i = to_memory_index(&index);
1085 // Get the old node before replacing
1086 let old_left = self.in_memory_nodes[i * 2];
1087 let old_right = self.in_memory_nodes[i * 2 + 1];
1088
1089 // Store new node in flat layout
1090 self.in_memory_nodes[i * 2] = inner_node.left;
1091 self.in_memory_nodes[i * 2 + 1] = inner_node.right;
1092
1093 // Check if the old node was empty
1094 if is_empty_parent(old_left, old_right, index.depth() + 1) {
1095 return None;
1096 }
1097
1098 return Some(InnerNode { left: old_left, right: old_right });
1099 }
1100 self.storage
1101 .set_inner_node(index, inner_node)
1102 .expect("Failed to store inner node")
1103 }
1104
1105 fn remove_inner_node(&mut self, index: NodeIndex) -> Option<InnerNode> {
1106 if index.depth() < IN_MEMORY_DEPTH {
1107 let memory_index = to_memory_index(&index);
1108 // Get the old node before replacing with empty hashes
1109 let old_left = self.in_memory_nodes[memory_index * 2];
1110 let old_right = self.in_memory_nodes[memory_index * 2 + 1];
1111
1112 // Replace with empty hashes
1113 let child_depth = index.depth() + 1;
1114 let empty_hash = *EmptySubtreeRoots::entry(SMT_DEPTH, child_depth);
1115 self.in_memory_nodes[memory_index * 2] = empty_hash;
1116 self.in_memory_nodes[memory_index * 2 + 1] = empty_hash;
1117
1118 // Return the old node if it wasn't already empty
1119 if is_empty_parent(old_left, old_right, child_depth) {
1120 return None;
1121 }
1122
1123 return Some(InnerNode { left: old_left, right: old_right });
1124 }
1125 self.storage.remove_inner_node(index).expect("Failed to remove inner node")
1126 }
1127
1128 fn insert(&mut self, key: Self::Key, value: Self::Value) -> Result<Self::Value, MerkleError> {
1129 let old_value = self.get_value(&key);
1130 // if the old value and new value are the same, there is nothing to update
1131 if value == old_value {
1132 return Ok(value);
1133 }
1134
1135 let mutations = self
1136 .compute_mutations([(key, value)])
1137 .expect("Failed to compute mutations in insert");
1138 self.apply_mutations(mutations).expect("Failed to apply mutations in insert");
1139
1140 Ok(old_value)
1141 }
1142
1143 fn insert_value(
1144 &mut self,
1145 key: Self::Key,
1146 value: Self::Value,
1147 ) -> Result<Option<Self::Value>, MerkleError> {
1148 // inserting an `EMPTY_VALUE` is equivalent to removing any value associated with `key`
1149 let index = Self::key_to_leaf_index(&key).value();
1150 if value != Self::EMPTY_VALUE {
1151 match self.storage.insert_value(index, key, value) {
1152 Ok(prev) => Ok(prev),
1153 Err(StorageError::Leaf(SmtLeafError::TooManyLeafEntries { actual })) => {
1154 Err(MerkleError::TooManyLeafEntries { actual })
1155 },
1156 Err(_) => {
1157 panic!("Storage error during insert_value");
1158 },
1159 }
1160 } else {
1161 Ok(self.storage.remove_value(index, key).expect("Failed to remove value"))
1162 }
1163 }
1164
1165 fn get_value(&self, key: &Self::Key) -> Self::Value {
1166 let leaf_pos = LeafIndex::<SMT_DEPTH>::from(*key);
1167 match self.storage.get_leaf(leaf_pos.value()) {
1168 Ok(Some(leaf)) => leaf.get_value(key).unwrap_or_default(),
1169 Ok(None) => EMPTY_WORD,
1170 Err(_) => {
1171 panic!("Storage error during get_leaf in get_value");
1172 },
1173 }
1174 }
1175
1176 fn get_leaf(&self, key: &Word) -> Self::Leaf {
1177 let leaf_pos = LeafIndex::<SMT_DEPTH>::from(*key).value();
1178 match self.storage.get_leaf(leaf_pos) {
1179 Ok(Some(leaf)) => leaf,
1180 Ok(None) => SmtLeaf::new_empty((*key).into()),
1181 Err(_) => {
1182 panic!("Storage error during get_leaf in get_leaf");
1183 },
1184 }
1185 }
1186
1187 fn hash_leaf(leaf: &Self::Leaf) -> Word {
1188 leaf.hash()
1189 }
1190
1191 fn construct_prospective_leaf(
1192 &self,
1193 mut existing_leaf: SmtLeaf,
1194 key: &Word,
1195 value: &Word,
1196 ) -> Result<SmtLeaf, SmtLeafError> {
1197 debug_assert_eq!(existing_leaf.index(), Self::key_to_leaf_index(key));
1198
1199 match existing_leaf {
1200 SmtLeaf::Empty(_) => Ok(SmtLeaf::new_single(*key, *value)),
1201 _ => {
1202 if *value != EMPTY_WORD {
1203 existing_leaf.insert(*key, *value)?;
1204 } else {
1205 existing_leaf.remove(*key);
1206 }
1207
1208 Ok(existing_leaf)
1209 },
1210 }
1211 }
1212
1213 fn open(&self, key: &Self::Key) -> Self::Opening {
1214 let leaf = self.get_leaf(key);
1215
1216 let mut idx: NodeIndex = LeafIndex::from(*key).into();
1217
1218 let subtree_roots: Vec<NodeIndex> = (0..NUM_SUBTREE_LEVELS)
1219 .scan(idx.parent(), |cursor, _| {
1220 let subtree_root = Subtree::find_subtree_root(*cursor);
1221 *cursor = subtree_root.parent();
1222 Some(subtree_root)
1223 })
1224 .collect();
1225 // cache subtrees in memory
1226 let mut cache = Map::<NodeIndex, Subtree>::new();
1227 for &root in &subtree_roots {
1228 let subtree =
1229 match self.storage.get_subtree(root).expect("storage error fetching subtree") {
1230 Some(st) => st,
1231 None => Subtree::new(root),
1232 };
1233 cache.insert(root, subtree);
1234 }
1235 let mut path = Vec::with_capacity(idx.depth() as usize);
1236 while idx.depth() > 0 {
1237 let is_right = idx.is_value_odd();
1238 idx = idx.parent();
1239
1240 let sibling_hash = if idx.depth() < IN_MEMORY_DEPTH {
1241 // top levels in memory
1242 let InnerNode { left, right } = self.get_inner_node(idx);
1243 if is_right { left } else { right }
1244 } else {
1245 // deep levels come from our 5 preloaded subtrees
1246 let root = Subtree::find_subtree_root(idx);
1247 let subtree = &cache[&root];
1248 let InnerNode { left, right } = subtree
1249 .get_inner_node(idx)
1250 .unwrap_or_else(|| EmptySubtreeRoots::get_inner_node(SMT_DEPTH, idx.depth()));
1251 if is_right { left } else { right }
1252 };
1253
1254 path.push(sibling_hash);
1255 }
1256
1257 let merkle_path =
1258 SparseMerklePath::from_sized_iter(path).expect("failed to convert to SparseMerklePath");
1259 Self::path_and_leaf_to_opening(merkle_path, leaf)
1260 }
1261
1262 fn key_to_leaf_index(key: &Word) -> LeafIndex<SMT_DEPTH> {
1263 let most_significant_felt = key[3];
1264 LeafIndex::new_max_depth(most_significant_felt.as_int())
1265 }
1266
1267 fn path_and_leaf_to_opening(path: SparseMerklePath, leaf: SmtLeaf) -> SmtProof {
1268 SmtProof::new_unchecked(path, leaf)
1269 }
1270}
1271
1272impl<S: SmtStorage> PartialEq for LargeSmt<S> {
1273 /// Compares two LargeSmt instances based on their root hash and metadata.
1274 ///
1275 /// Note: This comparison only checks the root hash and counts, not the underlying
1276 /// storage contents. Two SMTs with the same root should be cryptographically
1277 /// equivalent, but this doesn't verify the storage backends are identical.
1278 fn eq(&self, other: &Self) -> bool {
1279 self.root().unwrap() == other.root().unwrap()
1280 && self.num_leaves().unwrap() == other.num_leaves().unwrap()
1281 && self.num_entries().unwrap() == other.num_entries().unwrap()
1282 }
1283}
1284
1285impl<S: SmtStorage> Eq for LargeSmt<S> {}
1286
1287// Note: Clone is intentionally not implemented for LargeSmt because:
1288// 1. Cloning would only clone the in-memory portion and share storage via Arc
1289// 2. This doesn't actually clone the underlying disk data, which is misleading
1290// 3. Users should be explicit about sharing LargeSmt instances via Arc if needed
1291
1292/// Converts a NodeIndex to a flat vector index using 1-indexed layout.
1293/// Index 0 is unused, index 1 is root.
1294/// For a node at index i: left child at 2*i, right child at 2*i+1.
1295fn to_memory_index(index: &NodeIndex) -> usize {
1296 debug_assert!(index.depth() < IN_MEMORY_DEPTH);
1297 debug_assert!(index.value() < (1 << index.depth()));
1298 (1usize << index.depth()) + index.value() as usize
1299}
1300
1301/// Checks if a node with the given children is empty.
1302/// A node is considered empty if both children equal the empty hash for that depth.
1303fn is_empty_parent(left: Word, right: Word, child_depth: u8) -> bool {
1304 let empty_hash = *EmptySubtreeRoots::entry(SMT_DEPTH, child_depth);
1305 left == empty_hash && right == empty_hash
1306}
1307
1308// ITERATORS
1309// ================================================================================================
1310
1311enum InnerNodeIteratorState<'a> {
1312 InMemory {
1313 current_index: usize,
1314 large_smt_in_memory_nodes: &'a Vec<Word>,
1315 },
1316 Subtree {
1317 subtree_iter: Box<dyn Iterator<Item = Subtree> + 'a>,
1318 current_subtree_node_iter: Option<Box<dyn Iterator<Item = InnerNodeInfo> + 'a>>,
1319 },
1320 Done,
1321}
1322
1323pub struct LargeSmtInnerNodeIterator<'a, S: SmtStorage> {
1324 large_smt: &'a LargeSmt<S>,
1325 state: InnerNodeIteratorState<'a>,
1326}
1327
1328impl<'a, S: SmtStorage> LargeSmtInnerNodeIterator<'a, S> {
1329 fn new(large_smt: &'a LargeSmt<S>) -> Self {
1330 // in-memory nodes should never be empty
1331 Self {
1332 large_smt,
1333 state: InnerNodeIteratorState::InMemory {
1334 current_index: 0,
1335 large_smt_in_memory_nodes: &large_smt.in_memory_nodes,
1336 },
1337 }
1338 }
1339}
1340
1341impl<S: SmtStorage> Iterator for LargeSmtInnerNodeIterator<'_, S> {
1342 type Item = InnerNodeInfo;
1343
1344 /// Returns the next inner node info in the tree.
1345 ///
1346 /// The iterator operates in three phases:
1347 /// 1. InMemory: Iterates through the in-memory nodes (depths 0-IN_MEMORY_DEPTH-1)
1348 /// 2. Subtree: Iterates through nodes in storage subtrees (depths IN_MEMORY_DEPTH-SMT_DEPTH)
1349 /// 3. Done: No more nodes to iterate
1350 fn next(&mut self) -> Option<Self::Item> {
1351 loop {
1352 match &mut self.state {
1353 // Phase 1: Process in-memory nodes (depths 0-23)
1354 InnerNodeIteratorState::InMemory { current_index, large_smt_in_memory_nodes } => {
1355 // Iterate through nodes at depths 0 to IN_MEMORY_DEPTH-1
1356 // Start at index 1 (root), max node index is (1 << IN_MEMORY_DEPTH) - 1
1357 if *current_index == 0 {
1358 *current_index = 1;
1359 }
1360
1361 let max_node_idx = (1 << IN_MEMORY_DEPTH) - 1;
1362
1363 while *current_index <= max_node_idx {
1364 let node_idx = *current_index;
1365 *current_index += 1;
1366
1367 // Get children from flat layout: left at 2*i, right at 2*i+1
1368 let left = large_smt_in_memory_nodes[node_idx * 2];
1369 let right = large_smt_in_memory_nodes[node_idx * 2 + 1];
1370
1371 // Skip empty nodes
1372 let depth = node_idx.ilog2() as u8;
1373 let child_depth = depth + 1;
1374
1375 if !is_empty_parent(left, right, child_depth) {
1376 return Some(InnerNodeInfo {
1377 value: Rpo256::merge(&[left, right]),
1378 left,
1379 right,
1380 });
1381 }
1382 }
1383
1384 // All in-memory nodes processed. Transition to Phase 2: Subtree iteration
1385 match self.large_smt.storage.iter_subtrees() {
1386 Ok(subtree_iter) => {
1387 self.state = InnerNodeIteratorState::Subtree {
1388 subtree_iter,
1389 current_subtree_node_iter: None,
1390 };
1391 continue; // Start processing subtrees immediately
1392 },
1393 Err(_e) => {
1394 // Storage error occurred - we should propagate this properly
1395 // For now, transition to Done state to avoid infinite loops
1396 self.state = InnerNodeIteratorState::Done;
1397 return None;
1398 },
1399 }
1400 },
1401 // Phase 2: Process storage subtrees (depths 25-64)
1402 InnerNodeIteratorState::Subtree { subtree_iter, current_subtree_node_iter } => {
1403 loop {
1404 // First, try to get the next node from current subtree
1405 if let Some(node_iter) = current_subtree_node_iter
1406 && let Some(info) = node_iter.as_mut().next()
1407 {
1408 return Some(info);
1409 }
1410
1411 // Current subtree exhausted, move to next subtree
1412 match subtree_iter.next() {
1413 Some(next_subtree) => {
1414 let infos: Vec<InnerNodeInfo> =
1415 next_subtree.iter_inner_node_info().collect();
1416 *current_subtree_node_iter = Some(Box::new(infos.into_iter()));
1417 },
1418 None => {
1419 self.state = InnerNodeIteratorState::Done;
1420 return None; // All subtrees processed
1421 },
1422 }
1423 }
1424 },
1425 InnerNodeIteratorState::Done => {
1426 return None; // Iteration finished.
1427 },
1428 }
1429 }
1430 }
1431}