diff --git a/src/hash_tree.rs b/src/hash_tree.rs index 177c03a..5a7620f 100644 --- a/src/hash_tree.rs +++ b/src/hash_tree.rs @@ -149,4 +149,11 @@ impl HashTree { ) -> BinaryMerkleTreeResult> { self.tree.insert_one(previous_root, key, value) } + + #[inline] + #[must_use] + /// Decomposes the tree into the its DB and size + pub fn decompose(self) -> (HashTreeDB, usize) { + self.tree.decompose() + } } diff --git a/src/merkle_bit.rs b/src/merkle_bit.rs index eac5add..dca2bd1 100644 --- a/src/merkle_bit.rs +++ b/src/merkle_bit.rs @@ -1,3 +1,5 @@ +#![allow(unused_qualifications)] + #[cfg(not(any(feature = "hashbrown")))] use std::collections::HashMap; use std::collections::VecDeque; @@ -900,6 +902,12 @@ impl, const N: usize> MerkleBIT { let new_root = self.create_tree(tree_refs)?; Ok(new_root) } + + /// Decomposes the tree into its underlying data structures + #[inline] + pub fn decompose(self) -> (M::Database, usize) { + (self.db, self.depth) + } } /// Enum used for splitting nodes into either the left or right path during tree traversal diff --git a/src/rocks_tree.rs b/src/rocks_tree.rs index f10eae9..a0c73f8 100644 --- a/src/rocks_tree.rs +++ b/src/rocks_tree.rs @@ -110,4 +110,10 @@ impl RocksTree { ) -> BinaryMerkleTreeResult<()> { Tree::verify_inclusion_proof(root, key, value, proof) } + + #[inline] + #[must_use] + pub fn decompose(self) -> (RocksDB, usize) { + self.tree.decompose() + } } diff --git a/src/tree_db/hashbrown.rs b/src/tree_db/hashbrown.rs index 442dbf3..8dd8e98 100644 --- a/src/tree_db/hashbrown.rs +++ b/src/tree_db/hashbrown.rs @@ -15,6 +15,11 @@ impl HashDB { pub fn new(map: HashMap, TreeNode>) -> Self { Self { map } } + #[inline] + #[must_use] + pub fn decompose(self) -> HashMap, TreeNode> { + self.map + } } impl Database> for HashDB { diff --git a/src/tree_db/hashmap.rs b/src/tree_db/hashmap.rs index e7a3ceb..6770c75 100644 --- a/src/tree_db/hashmap.rs +++ b/src/tree_db/hashmap.rs @@ -18,6 +18,13 @@ impl HashDB { pub const fn new(map: HashMap, TreeNode>) -> Self { Self { map } } + + #[inline] + #[must_use] + /// Decomposes the `HashDB` into its underlying `HashMap`. + pub fn decompose(self) -> HashMap, TreeNode> { + self.map + } } impl Database> for HashDB { diff --git a/src/tree_db/rocksdb.rs b/src/tree_db/rocksdb.rs index 0704d0c..4766fda 100644 --- a/src/tree_db/rocksdb.rs +++ b/src/tree_db/rocksdb.rs @@ -27,6 +27,11 @@ impl RocksDB { pending_inserts: Some(WriteBatch::default()), } } + + #[inline] + pub fn decompose(self) -> DB { + self.db + } } impl Database> for RocksDB { diff --git a/tests/merkle_bit.rs b/tests/merkle_bit.rs index 0baba89..b0bc56d 100644 --- a/tests/merkle_bit.rs +++ b/tests/merkle_bit.rs @@ -1386,6 +1386,34 @@ pub mod integration_tests { Ok(()) } + #[test] + fn it_actually_removes_things_from_the_db() -> BinaryMerkleTreeResult<()> { + let seed = [0x51u8; KEY_LEN]; + let path = generate_path(seed); + let mut rng: StdRng = SeedableRng::from_seed(seed); + + #[cfg(not(feature = "groestl"))] + let num_entries = 4096; + #[cfg(feature = "groestl")] + let num_entries = 512; + + let (mut keys, values) = prepare_inserts(num_entries, &mut rng); + + let mut bmt = Tree::open(&path, 160)?; + + let root = bmt.insert(None, &mut keys, &values)?; + + bmt.remove(&root)?; + + let (db, _) = bmt.decompose(); + let map = db.decompose(); + #[cfg(not(any(feature = "rocksdb")))] + assert_eq!(map.keys().len(), 0); + + tear_down(&path); + Ok(()) + } + test_key_size!(it_handles_key_size_of_two, 2, [0x94u8; 32], 16, 16); test_key_size!(it_handles_key_size_of_three, 3, [0x95u8; 32], 32, 32); test_key_size!(it_handles_key_size_of_four, 4, [0x96u8; 32], 64, 64);