diff --git a/grovedb/Cargo.toml b/grovedb/Cargo.toml index 78ba365e5..1cf5b1c4b 100644 --- a/grovedb/Cargo.toml +++ b/grovedb/Cargo.toml @@ -12,6 +12,7 @@ bincode = "1.3.3" serde = { version = "1.0.130", features = ["derive"] } storage = { path = "../storage" } hex = "0.4.3" +blake3 = "1.3.0" [dev-dependencies] rand = "0.8.4" diff --git a/grovedb/src/lib.rs b/grovedb/src/lib.rs index 38a14a0b8..69cc55ab3 100644 --- a/grovedb/src/lib.rs +++ b/grovedb/src/lib.rs @@ -1,10 +1,11 @@ mod operations; mod subtree; +mod subtrees; #[cfg(test)] mod tests; mod transaction; -use std::{collections::HashMap, path::Path, rc::Rc}; +use std::{cell::RefCell, collections::HashMap, path::Path, rc::Rc}; pub use merk::proofs::{query::QueryItem, Query}; use merk::{self, Merk}; @@ -16,6 +17,8 @@ use storage::{ Transaction, }; pub use subtree::Element; +use subtrees::Subtrees; +use blake3; // use crate::transaction::GroveDbTransaction; // pub use transaction::GroveDbTransaction; @@ -106,7 +109,6 @@ pub struct Proof { pub struct GroveDb { root_tree: MerkleTree, root_leaf_keys: HashMap, usize>, - subtrees: HashMap, Merk>, meta_storage: PrefixedRocksDbStorage, db: Rc, // Locks the database for writes during the transaction @@ -114,26 +116,24 @@ pub struct GroveDb { // Temp trees used for writes during transaction temp_root_tree: MerkleTree, temp_root_leaf_keys: HashMap, usize>, - temp_subtrees: HashMap, Merk>, + temp_subtrees: RefCell, Merk>>, } impl GroveDb { pub fn new( root_tree: MerkleTree, root_leaf_keys: HashMap, usize>, - subtrees: HashMap, Merk>, meta_storage: PrefixedRocksDbStorage, db: Rc, ) -> Self { Self { root_tree, root_leaf_keys, - subtrees, meta_storage, db, temp_root_tree: MerkleTree::new(), temp_root_leaf_keys: HashMap::new(), - temp_subtrees: HashMap::new(), + temp_subtrees: RefCell::new(HashMap::new()), is_readonly: false, } } @@ -149,21 +149,6 @@ impl GroveDb { ); let meta_storage = PrefixedRocksDbStorage::new(db.clone(), Vec::new())?; - let mut subtrees = HashMap::new(); - // TODO: owned `get` is not required for deserialization - if let Some(prefixes_serialized) = meta_storage.get_meta(SUBTREES_SERIALIZED_KEY)? { - let subtrees_prefixes: Vec> = bincode::deserialize(&prefixes_serialized) - .map_err(|_| { - Error::CorruptedData(String::from("unable to deserialize prefixes")) - })?; - for prefix in subtrees_prefixes { - let subtree_merk = - Merk::open(PrefixedRocksDbStorage::new(db.clone(), prefix.to_vec())?) - .map_err(|e| Error::CorruptedData(e.to_string()))?; - subtrees.insert(prefix.to_vec(), subtree_merk); - } - } - // TODO: owned `get` is not required for deserialization let root_leaf_keys: HashMap, usize> = if let Some(root_leaf_keys_serialized) = meta_storage.get_meta(ROOT_LEAFS_SERIALIZED_KEY)? @@ -175,10 +160,17 @@ impl GroveDb { HashMap::new() }; + let temp_subtrees: RefCell, Merk>> = + RefCell::new(HashMap::new()); + let subtrees_view = Subtrees { + root_leaf_keys: &root_leaf_keys, + temp_subtrees: &temp_subtrees, + storage: db.clone(), + }; + Ok(GroveDb::new( - Self::build_root_tree(&subtrees, &root_leaf_keys), + Self::build_root_tree(&subtrees_view, &root_leaf_keys, None), root_leaf_keys, - subtrees, meta_storage, db, )) @@ -207,83 +199,48 @@ impl GroveDb { } } - fn store_subtrees_keys_data( - &self, - db_transaction: Option<&OptimisticTransactionDBTransaction>, - ) -> Result<(), Error> { - let subtrees = match db_transaction { - None => &self.subtrees, - Some(_) => &self.temp_subtrees, - }; - - let prefixes: Vec> = subtrees.keys().cloned().collect(); - - // TODO: make StorageOrTransaction which will has the access to either storage - // or transaction - match db_transaction { - None => { - self.meta_storage.put_meta( - SUBTREES_SERIALIZED_KEY, - &bincode::serialize(&prefixes).map_err(|_| { - Error::CorruptedData(String::from("unable to serialize prefixes")) - })?, - )?; - self.meta_storage.put_meta( - ROOT_LEAFS_SERIALIZED_KEY, - &bincode::serialize(&self.temp_root_leaf_keys).map_err(|_| { - Error::CorruptedData(String::from("unable to serialize root leafs")) - })?, - )?; - } - Some(tx) => { - let transaction = self.meta_storage.transaction(tx); - transaction.put_meta( - SUBTREES_SERIALIZED_KEY, - &bincode::serialize(&prefixes).map_err(|_| { - Error::CorruptedData(String::from("unable to serialize prefixes")) - })?, - )?; - transaction.put_meta( - ROOT_LEAFS_SERIALIZED_KEY, - &bincode::serialize(&self.root_leaf_keys).map_err(|_| { - Error::CorruptedData(String::from("unable to serialize root leafs")) - })?, - )?; - } - } - - Ok(()) - } - fn build_root_tree( - subtrees: &HashMap, Merk>, + subtrees: &Subtrees, root_leaf_keys: &HashMap, usize>, + transaction: Option<&OptimisticTransactionDBTransaction>, ) -> MerkleTree { let mut leaf_hashes: Vec<[u8; 32]> = vec![[0; 32]; root_leaf_keys.len()]; for (subtree_path, root_leaf_idx) in root_leaf_keys { - let subtree_merk = subtrees - .get(subtree_path) + let (subtree_merk, prefix) = subtrees + .get(&[subtree_path.as_slice()], transaction) .expect("`root_leaf_keys` must be in sync with `subtrees`"); leaf_hashes[*root_leaf_idx] = subtree_merk.root_hash(); + if let Some(prefix) = prefix { + subtrees.insert_temp_tree_with_prefix(prefix, subtree_merk, transaction); + } else { + subtrees.insert_temp_tree(&[subtree_path.as_slice()], subtree_merk, transaction); + } } MerkleTree::::from_leaves(&leaf_hashes) } - pub fn elements_iterator( - &self, - path: &[&[u8]], - transaction: Option<&OptimisticTransactionDBTransaction>, - ) -> Result { - let subtrees = match transaction { - None => &self.subtrees, - Some(_) => &self.temp_subtrees, - }; - - let merk = subtrees - .get(&Self::compress_subtree_key(path, None)) - .ok_or(Error::InvalidPath("no subtree found under that path"))?; - Ok(Element::iterator(merk.raw_iter())) - } + // pub fn elements_iterator( + // &self, + // path: &[&[u8]], + // transaction: Option<&OptimisticTransactionDBTransaction>, + // ) -> Result { + // // Get the correct subtrees instance + // // let subtrees = match transaction { + // // None => &self.subtrees, + // // Some(_) => &self.temp_subtrees, + // // }; + // todo!() + // // Get the merk at the current path + // // let merk = self.get_subtrees() + // // .get(path, transaction) + // // .ok_or(Error::InvalidPath("no subtree found under that path"))?; + // // // let merk = self + // // // .get_subtrees() + // // // .get(path, transaction) + // // // .map_err(|_| Error::InvalidPath("no subtree found under that + // // path"))?; Return the raw iter of the merk + // // Ok(Element::iterator(merk.raw_iter())) + // } /// Method to propagate updated subtree root hashes up to GroveDB root fn propagate_changes<'a: 'b, 'b>( @@ -291,45 +248,60 @@ impl GroveDb { path: &[&[u8]], transaction: Option<&'b ::DBTransaction<'b>>, ) -> Result<(), Error> { - let subtrees = match transaction { - None => &mut self.subtrees, - Some(_) => &mut self.temp_subtrees, - }; + let subtrees = self.get_subtrees(); - let root_leaf_keys = match transaction { - None => &mut self.root_leaf_keys, - Some(_) => &mut self.temp_root_leaf_keys, - }; + let mut path = path; - let mut split_path = path.split_last(); // Go up until only one element in path, which means a key of a root tree - while let Some((key, path_slice)) = split_path { - if path_slice.is_empty() { - // Hit the root tree - match transaction { - None => self.root_tree = Self::build_root_tree(subtrees, root_leaf_keys), - Some(_) => { - self.temp_root_tree = Self::build_root_tree(subtrees, root_leaf_keys) - } - }; - break; + while path.len() > 1 { + // non root leaf node + let (subtree, prefix) = subtrees.get(path, transaction)?; + let element = Element::Tree(subtree.root_hash()); + if let Some(prefix) = prefix { + self.get_subtrees() + .insert_temp_tree_with_prefix(prefix, subtree, transaction); + } else { + self.get_subtrees() + .insert_temp_tree(path, subtree, transaction); + } + + let (key, parent_path) = path.split_last().ok_or(Error::InvalidPath("empty path"))?; + let (mut upper_tree, prefix) = subtrees.get(parent_path, transaction)?; + element.insert(&mut upper_tree, key.to_vec(), transaction); + if let Some(prefix) = prefix { + self.get_subtrees() + .insert_temp_tree(parent_path, upper_tree, transaction); } else { - let compressed_path_upper_tree = Self::compress_subtree_key(path_slice, None); - let compressed_path_subtree = Self::compress_subtree_key(path_slice, Some(key)); - let subtree = subtrees - .get(&compressed_path_subtree) - .ok_or(Error::InvalidPath("no subtree found under that path"))?; - let element = Element::Tree(subtree.root_hash()); - let upper_tree = subtrees - .get_mut(&compressed_path_upper_tree) - .ok_or(Error::InvalidPath("no subtree found under that path"))?; - element.insert(upper_tree, key.to_vec(), transaction)?; - split_path = path_slice.split_last(); + self.get_subtrees().insert_temp_tree(path, upper_tree, transaction); } + + path = parent_path; } + + // root leaf nodes + if path.len() <= 1 { + let root_leaf_keys = match transaction { + None => &self.root_leaf_keys, + Some(_) => &self.temp_root_leaf_keys, + }; + let root_tree = GroveDb::build_root_tree(&subtrees, root_leaf_keys, transaction); + match transaction { + None => self.root_tree = root_tree, + Some(_) => self.temp_root_tree = root_tree, + } + } + Ok(()) } + fn get_subtrees(&self) -> Subtrees { + Subtrees { + root_leaf_keys: &self.root_leaf_keys, + temp_subtrees: &self.temp_subtrees, + storage: self.storage(), + } + } + /// A helper method to build a prefix to rocksdb keys or identify a subtree /// in `subtrees` map by tree path; fn compress_subtree_key(path: &[&[u8]], key: Option<&[u8]>) -> Vec { @@ -351,7 +323,7 @@ impl GroveDb { acc.extend(p.len().to_ne_bytes()); acc }); - res = Sha256::hash(&res).to_vec(); + res = blake3::hash(&res).as_bytes().to_vec(); res } @@ -421,7 +393,6 @@ impl GroveDb { // Cloning all the trees to maintain original state before the transaction self.temp_root_tree = self.root_tree.clone(); self.temp_root_leaf_keys = self.root_leaf_keys.clone(); - self.temp_subtrees = self.subtrees.clone(); Ok(()) } @@ -444,7 +415,6 @@ impl GroveDb { // code can be reworked to account for that self.root_tree = self.temp_root_tree.clone(); self.root_leaf_keys = self.temp_root_leaf_keys.drain().collect(); - self.subtrees = self.temp_subtrees.drain().collect(); self.cleanup_transactional_data(); @@ -453,16 +423,6 @@ impl GroveDb { .map_err(PrefixedRocksDbStorageError::RocksDbError)?) } - pub fn get_subtrees_for_transaction( - &mut self, - transaction: Option<&OptimisticTransactionDBTransaction>, - ) -> &HashMap, Merk> { - match transaction { - None => &self.subtrees, - Some(_) => &self.temp_subtrees, - } - } - /// Rollbacks previously started db transaction to initial state. /// For more details on the transaction usage, please check /// [`GroveDb::start_transaction`] @@ -473,7 +433,7 @@ impl GroveDb { // Cloning all the trees to maintain to rollback transactional changes self.temp_root_tree = self.root_tree.clone(); self.temp_root_leaf_keys = self.root_leaf_keys.clone(); - self.temp_subtrees = self.subtrees.clone(); + self.temp_subtrees = RefCell::new(HashMap::new()); Ok(db_transaction .rollback() @@ -501,6 +461,6 @@ impl GroveDb { // Free transactional data self.temp_root_tree = MerkleTree::new(); self.temp_root_leaf_keys = HashMap::new(); - self.temp_subtrees = HashMap::new(); + self.temp_subtrees = RefCell::new(HashMap::new()); } } diff --git a/grovedb/src/operations/delete.rs b/grovedb/src/operations/delete.rs index b4c1f97d8..6f80f8eee 100644 --- a/grovedb/src/operations/delete.rs +++ b/grovedb/src/operations/delete.rs @@ -22,15 +22,17 @@ impl GroveDb { } else { let element = self.get_raw(path, &key, transaction)?; { - let subtrees = match transaction { - None => &mut self.subtrees, - Some(_) => &mut self.temp_subtrees, - }; + let (mut merk, prefix) = self.get_subtrees().get(path, transaction)?; + Element::delete(&mut merk, key.clone(), transaction)?; - let mut merk = subtrees - .get_mut(&Self::compress_subtree_key(path, None)) - .ok_or(Error::InvalidPath("no subtree found under that path"))?; - Element::delete(merk, key.clone(), transaction)?; + // after deletion, if there is a transaction, add the merk back into the hashmap + if let Some(prefix) = prefix { + self.get_subtrees() + .insert_temp_tree_with_prefix(prefix, merk, transaction); + } else { + self.get_subtrees() + .insert_temp_tree(path, merk, transaction); + } } if let Element::Tree(_) = element { @@ -38,24 +40,17 @@ impl GroveDb { let mut concat_path: Vec> = path.iter().map(|x| x.to_vec()).collect(); concat_path.push(key); let subtrees_paths = self.find_subtrees(concat_path, transaction)?; - let subtrees = match transaction { - None => &mut self.subtrees, - Some(_) => &mut self.temp_subtrees, - }; for subtree_path in subtrees_paths { // TODO: eventually we need to do something about this nested slices let subtree_path_ref: Vec<&[u8]> = subtree_path.iter().map(|x| x.as_slice()).collect(); - let prefix = Self::compress_subtree_key(&subtree_path_ref, None); - if let Some(mut subtree) = subtrees.remove(&prefix) { - subtree.clear(transaction).map_err(|e| { - Error::CorruptedData(format!( - "unable to cleanup tree from storage: {}", - e - )) - })?; - } + let mut subtree = self + .get_subtrees() + .get_subtree_without_transaction(subtree_path_ref.as_slice())?; + subtree.clear(transaction).map_err(|e| { + Error::CorruptedData(format!("unable to cleanup tree from storage: {}", e)) + })?; } } self.propagate_changes(path, transaction)?; @@ -78,7 +73,10 @@ impl GroveDb { while let Some(q) = queue.pop() { // TODO: eventually we need to do something about this nested slices let q_ref: Vec<&[u8]> = q.iter().map(|x| x.as_slice()).collect(); - let mut iter = self.elements_iterator(&q_ref, transaction)?; + // Get the correct subtree with q_ref as path + let (merk, _) = self.get_subtrees().get(&q_ref, transaction)?; + let mut iter = Element::iterator(merk.raw_iter()); + // let mut iter = self.elements_iterator(&q_ref, transaction)?; while let Some((key, value)) = iter.next()? { match value { Element::Tree(_) => { diff --git a/grovedb/src/operations/get.rs b/grovedb/src/operations/get.rs index 0a39b45a0..84248dac1 100644 --- a/grovedb/src/operations/get.rs +++ b/grovedb/src/operations/get.rs @@ -1,9 +1,16 @@ -use std::collections::{HashMap, HashSet}; +use std::{ + collections::{HashMap, HashSet}, + ops::Range, + rc::Rc, +}; use merk::Merk; -use storage::rocksdb_storage::{OptimisticTransactionDBTransaction, PrefixedRocksDbStorage}; +use storage::{ + rocksdb_storage::{OptimisticTransactionDBTransaction, PrefixedRocksDbStorage}, + RawIterator, +}; -use crate::{Element, Error, GroveDb, PathQuery}; +use crate::{Element, Error, GroveDb, PathQuery, Subtrees}; /// Limit of possible indirections pub(crate) const MAX_REFERENCE_HOPS: usize = 10; @@ -66,15 +73,33 @@ impl GroveDb { key: &[u8], transaction: Option<&OptimisticTransactionDBTransaction>, ) -> Result { - let subtrees = match transaction { - None => &self.subtrees, - Some(_) => &self.temp_subtrees, - }; - - let merk = subtrees - .get(&Self::compress_subtree_key(path, None)) - .ok_or(Error::InvalidPath("no subtree found under that path"))?; - Element::get(merk, key) + // If path is empty, then we need to combine the provided key and path + // then use this to get merk. + let merk_result; + if path.is_empty() { + merk_result = self.get_subtrees().get(&[key], transaction)?; + } else { + merk_result = self.get_subtrees().get(path, transaction)?; + } + + let (merk, prefix) = merk_result; + + let elem; + if path.is_empty(){ + elem = Ok(Element::Tree(merk.root_hash())); + } else { + elem = Element::get(&merk, key); + } + + if let Some(prefix) = prefix { + self.get_subtrees() + .insert_temp_tree_with_prefix(prefix, merk, transaction); + } else { + self.get_subtrees() + .insert_temp_tree(path, merk, transaction); + } + + elem } pub fn get_path_queries( @@ -146,22 +171,28 @@ impl GroveDb { path_query: &PathQuery, transaction: Option<&OptimisticTransactionDBTransaction>, ) -> Result<(Vec, u16), Error> { - let subtrees = match transaction { - None => &self.subtrees, - Some(_) => &self.temp_subtrees, - }; - self.get_path_query_on_trees_raw(path_query, subtrees) + let subtrees = self.get_subtrees(); + self.get_path_query_on_trees_raw(path_query, subtrees, transaction) } fn get_path_query_on_trees_raw( &self, path_query: &PathQuery, - subtrees: &HashMap, Merk>, + subtrees: Subtrees, + transaction: Option<&OptimisticTransactionDBTransaction>, + // subtrees: &HashMap, Merk>, ) -> Result<(Vec, u16), Error> { let path = path_query.path; - let merk = subtrees - .get(&Self::compress_subtree_key(path, None)) - .ok_or(Error::InvalidPath("no subtree found under that path"))?; - Element::get_path_query(merk, path_query, Some(subtrees)) + let (merk, prefix) = subtrees.get(path, transaction)?; + + let elem = Element::get_path_query(&merk, path_query, Some(&subtrees)); + + if let Some(prefix) = prefix{ + subtrees.insert_temp_tree_with_prefix(prefix, merk, transaction); + } else { + subtrees.insert_temp_tree(path, merk, transaction); + } + + elem } } diff --git a/grovedb/src/operations/insert.rs b/grovedb/src/operations/insert.rs index d58d2c379..67c5bee97 100644 --- a/grovedb/src/operations/insert.rs +++ b/grovedb/src/operations/insert.rs @@ -33,11 +33,6 @@ impl GroveDb { } } - let subtrees = match transaction { - None => &mut self.subtrees, - Some(_) => &mut self.temp_subtrees, - }; - match element { Element::Tree(_) => { if path.is_empty() { @@ -45,7 +40,6 @@ impl GroveDb { } else { self.add_non_root_subtree(path, key, transaction)?; } - self.store_subtrees_keys_data(transaction)?; } _ => { // If path is empty that means there is an attempt to insert something into a @@ -55,11 +49,19 @@ impl GroveDb { "only subtrees are allowed as root tree's leafs", )); } - // Get a Merk by a path - let mut merk = subtrees - .get_mut(&Self::compress_subtree_key(path, None)) - .ok_or(Error::InvalidPath("no subtree found under that path"))?; + + let (mut merk, prefix) = self + .get_subtrees() + .get(path, transaction) + .map_err(|_| Error::InvalidPath("no subtree found under that path"))?; element.insert(&mut merk, key, transaction)?; + if let Some(prefix) = prefix{ + self.get_subtrees() + .insert_temp_tree_with_prefix(prefix, merk, transaction); + } else { + self.get_subtrees() + .insert_temp_tree(path, merk, transaction); + } self.propagate_changes(path, transaction)?; } } @@ -78,10 +80,12 @@ impl GroveDb { } } - let subtrees = match transaction { - None => &mut self.subtrees, - Some(_) => &mut self.temp_subtrees, - }; + + // Open Merk and put handle into `subtrees` dictionary accessible by its + // compressed path + let (subtree_prefix, subtree_merk) = create_merk_with_prefix(self.db.clone(), &[], key)?; + self.get_subtrees() + .insert_temp_tree_with_prefix(subtree_prefix, subtree_merk, transaction); let root_leaf_keys = match transaction { None => &mut self.root_leaf_keys, @@ -92,20 +96,20 @@ impl GroveDb { None => &mut self.root_tree, Some(_) => &mut self.temp_root_tree, }; - // Open Merk and put handle into `subtrees` dictionary accessible by its - // compressed path - let (subtree_prefix, subtree_merk) = create_merk_with_prefix(self.db.clone(), &[], key)?; - subtrees.insert(subtree_prefix.clone(), subtree_merk); - // Update root leafs index to persist rs-merkle structure later - if root_leaf_keys.get(&subtree_prefix).is_none() { - root_leaf_keys.insert(subtree_prefix, root_tree.leaves_len()); + if root_leaf_keys.get(&key.to_vec()).is_none() { + root_leaf_keys.insert(key.to_vec(), root_tree.leaves_len()); } self.propagate_changes(&[key], transaction)?; Ok(()) } // Add subtree to another subtree. + // We want to add a new empty merk to another merk at a key + // first make sure other merk exist + // if it exists, then create merk to be inserted, and get root hash + // we only care about root hash of merk to be inserted + // fn add_non_root_subtree<'a: 'b, 'b>( &'a mut self, path: &[&[u8]], @@ -118,27 +122,41 @@ impl GroveDb { } } - let subtrees = match transaction { - None => &mut self.subtrees, - Some(_) => &mut self.temp_subtrees, - }; - - let compressed_path = Self::compress_subtree_key(path, None); // First, check if a subtree exists to create a new subtree under it - subtrees - .get(&compressed_path) - .ok_or(Error::InvalidPath("no subtree found under that path"))?; + let (parent, prefix) = self.get_subtrees().get(path, transaction)?; + if let Some(prefix) = prefix { + self.get_subtrees() + .insert_temp_tree_with_prefix(prefix, parent, transaction); + } else { + self.get_subtrees() + .insert_temp_tree(path, parent, transaction); + } + let (subtree_prefix, subtree_merk) = create_merk_with_prefix(self.db.clone(), path, &key)?; + // Set tree value as a a subtree root hash let element = Element::Tree(subtree_merk.root_hash()); - subtrees.insert(subtree_prefix, subtree_merk); + self.get_subtrees() + .insert_temp_tree_with_prefix(subtree_prefix, subtree_merk, transaction); + // Had to take merk from `subtrees` once again to solve multiple &mut s - let mut merk = subtrees - .get_mut(&compressed_path) - .expect("merk object must exist in `subtrees`"); + let (mut merk, prefix) = self + .get_subtrees() + .get(path, transaction) + .expect("confirmed subtree exists above"); + // need to mark key as taken in the upper tree - element.insert(merk, key, transaction)?; + element.insert(&mut merk, key, transaction)?; + if let Some(prefix) = prefix{ + self.get_subtrees() + .insert_temp_tree_with_prefix(prefix, merk, transaction); + } else { + self.get_subtrees() + .insert_temp_tree(path, merk, transaction); + } + self.propagate_changes(path, transaction)?; + Ok(()) } diff --git a/grovedb/src/operations/is_empty_tree.rs b/grovedb/src/operations/is_empty_tree.rs index fa00f5057..3e771aac9 100644 --- a/grovedb/src/operations/is_empty_tree.rs +++ b/grovedb/src/operations/is_empty_tree.rs @@ -8,14 +8,7 @@ impl GroveDb { path: &[&[u8]], transaction: Option<&OptimisticTransactionDBTransaction>, ) -> Result { - let subtrees = match transaction { - None => &self.subtrees, - Some(_) => &self.temp_subtrees, - }; - - let merk = subtrees - .get(&Self::compress_subtree_key(path, None)) - .ok_or(Error::InvalidPath("no subtree found under that path"))?; + let (merk, _) = self.get_subtrees().get(path, transaction)?; let mut iter = merk.raw_iter(); iter.seek_to_first(); diff --git a/grovedb/src/operations/proof.rs b/grovedb/src/operations/proof.rs index e7d36a085..4a945a8ac 100644 --- a/grovedb/src/operations/proof.rs +++ b/grovedb/src/operations/proof.rs @@ -1,255 +1,255 @@ -use std::collections::HashMap; - -use merk::proofs::query::Map; -use rs_merkle::{algorithms::Sha256, MerkleProof}; - -use crate::{Element, Error, GroveDb, PathQuery, Proof, Query}; - -impl GroveDb { - pub fn proof(&mut self, proof_queries: Vec) -> Result, Error> { - // To prove a path we need to return a proof for each node on the path including - // the root. With multiple paths, nodes can overlap i.e two or more paths can - // share the same nodes. We should only have one proof for each node, - // if a node forks into multiple relevant paths then we should create a - // combined proof for that node with all the relevant keys - let mut query_paths = Vec::new(); - let mut intermediate_proof_spec: HashMap, Query> = HashMap::new(); - let mut root_keys: Vec> = Vec::new(); - let mut proofs: HashMap, Vec> = HashMap::new(); - - // For each unique node including the root - // determine what keys would need to be included in the proof - for proof_query in proof_queries.iter() { - query_paths.push( - proof_query - .path - .iter() - .map(|x| x.to_vec()) - .collect::>(), - ); - - let mut split_path = proof_query.path.split_last(); - while let Some((key, path_slice)) = split_path { - if path_slice.is_empty() { - // We have gotten to the root node - let compressed_path = GroveDb::compress_subtree_key(&[], Some(key)); - root_keys.push(compressed_path); - } else { - let compressed_path = GroveDb::compress_subtree_key(path_slice, None); - if let Some(path_query) = intermediate_proof_spec.get_mut(&compressed_path) { - path_query.insert_key(key.to_vec()); - } else { - let mut path_query = Query::new(); - path_query.insert_key(key.to_vec()); - intermediate_proof_spec.insert(compressed_path, path_query); - } - } - split_path = path_slice.split_last(); - } - } - - // Construct the path proofs - for (path, query) in intermediate_proof_spec { - let proof = self.prove_item(&path, query)?; - proofs.insert(path, proof); - } - - // Construct the leaf proofs - for proof_query in proof_queries { - let path = proof_query.path; - - // If there is a subquery with a limit it's possible that we only need a reduced - // proof for this leaf. - let reduced_proof_query = proof_query; - - // First we must get elements - - if let Some(subquery_key) = reduced_proof_query.query.query.subquery_key.clone() { - self.get_path_queries_raw(&[&reduced_proof_query], None)?; - - let mut path_vec = path.to_vec(); - path_vec.push(subquery_key.as_slice()); - let compressed_path = GroveDb::compress_subtree_key(path_vec.as_slice(), None); - } - - // Now we must insert the final proof for the sub leaves - let compressed_path = GroveDb::compress_subtree_key(path, None); - let proof = self.prove_path_item(&compressed_path, reduced_proof_query)?; - proofs.insert(compressed_path, proof); - } - - // Construct the root proof - let mut root_index: Vec = Vec::new(); - for key in root_keys { - let index = self - .root_leaf_keys - .get(&key) - .ok_or(Error::InvalidPath("root key not found"))?; - root_index.push(*index); - } - let root_proof = self.root_tree.proof(&root_index).to_bytes(); - - let proof = Proof { - query_paths, - proofs, - root_proof, - root_leaf_keys: self.root_leaf_keys.clone(), - }; - - let seralized_proof = bincode::serialize(&proof) - .map_err(|_| Error::CorruptedData(String::from("unable to serialize proof")))?; - - Ok(seralized_proof) - } - - fn prove_path_item( - &self, - compressed_path: &Vec, - path_query: PathQuery, - ) -> Result, Error> { - let merk = self - .subtrees - .get(compressed_path) - .ok_or(Error::InvalidPath("no subtree found under that path"))?; - - let sized_query = path_query.query; - - if sized_query.query.subquery.is_none() { - // then limit should be applied directly to the proof here - let proof_result = merk - .prove( - sized_query.query, - sized_query.limit, - sized_query.offset, - ) - .expect("should prove both inclusion and absence"); - Ok(proof_result) - } else { - let proof_result = merk - .prove(sized_query.query, None, None) - .expect("should prove both inclusion and absence"); - Ok(proof_result) - } - } - - fn prove_item(&self, path: &Vec, query: Query) -> Result, Error> { - let merk = self - .subtrees - .get(path) - .ok_or(Error::InvalidPath("no subtree found under that path"))?; - - // then limit should be applied directly to the proof here - let proof_result = merk - .prove(query, None, None) - .expect("should prove both inclusion and absence"); - Ok(proof_result) - } - - pub fn execute_proof(proof: Vec) -> Result<([u8; 32], HashMap, Map>), Error> { - // Deserialize the proof - let proof: Proof = bincode::deserialize(&proof) - .map_err(|_| Error::CorruptedData(String::from("unable to deserialize proof")))?; - - // Required to execute the root proof - let mut root_keys_index: Vec = Vec::new(); - let mut root_hashes: Vec<[u8; 32]> = Vec::new(); - - // Collects the result map for each query - let mut result_map: HashMap, Map> = HashMap::new(); - - for path in proof.query_paths { - let path = path.iter().map(|x| x.as_slice()).collect::>(); - // For each query path, get the result map after execution - // and store hash + index for later root proof execution - let root_key = &path[0]; - let (hash, proof_result_map) = GroveDb::execute_path(&path, &proof.proofs)?; - let compressed_root_key_path = GroveDb::compress_subtree_key(&[], Some(root_key)); - let compressed_query_path = GroveDb::compress_subtree_key(&path, None); - - let index = proof - .root_leaf_keys - .get(&compressed_root_key_path) - .ok_or(Error::InvalidPath("Bad path"))?; - if !root_keys_index.contains(index) { - root_keys_index.push(*index); - root_hashes.push(hash); - } - - result_map.insert(compressed_query_path, proof_result_map); - } - - let root_proof = match MerkleProof::::try_from(proof.root_proof) { - Ok(proof) => Ok(proof), - Err(_) => Err(Error::InvalidProof("Invalid proof element")), - }?; - - let root_hash = - match root_proof.root(&root_keys_index, &root_hashes, proof.root_leaf_keys.len()) { - Ok(hash) => Ok(hash), - Err(_) => Err(Error::InvalidProof("Invalid proof element")), - }?; - - Ok((root_hash, result_map)) - } - - // Given a query path and a set of proofs - // execute_path validates that the nodes represented by the paths - // are connected to one another i.e root hash of child node is in parent node - // at the correct key. - // If path is valid, it returns the root hash of topmost merk and result map of - // leaf merk. - fn execute_path( - path: &[&[u8]], - proofs: &HashMap, Vec>, - ) -> Result<([u8; 32], Map), Error> { - let compressed_path = GroveDb::compress_subtree_key(path, None); - let proof = proofs - .get(&compressed_path) - .ok_or(Error::InvalidPath("Bad path"))?; - - // Execute the leaf merk proof - let (mut last_root_hash, result_map) = match merk::execute_proof(&proof[..]) { - Ok(result) => Ok(result), - Err(_) => Err(Error::InvalidPath("Invalid proof element")), - }?; - - // Validate the path - let mut split_path = path.split_last(); - while let Some((key, path_slice)) = split_path { - if !path_slice.is_empty() { - let compressed_path = GroveDb::compress_subtree_key(path_slice, None); - let proof = proofs - .get(&compressed_path) - .ok_or(Error::InvalidPath("Bad path"))?; - - let proof_result = match merk::execute_proof(&proof[..]) { - Ok(result) => Ok(result), - Err(_) => Err(Error::InvalidPath("Invalid proof element")), - }?; - - let result_map = proof_result.1; - // TODO: Handle the error better here - let elem: Element = - bincode::deserialize(result_map.get(key).unwrap().unwrap()).unwrap(); - let merk_root_hash = match elem { - Element::Tree(hash) => Ok(hash), - _ => Err(Error::InvalidProof( - "Intermediate proofs should be for trees", - )), - }?; - - if merk_root_hash != last_root_hash { - return Err(Error::InvalidProof("Bad path")); - } - - last_root_hash = proof_result.0; - } else { - break; - } - - split_path = path_slice.split_last(); - } - - Ok((last_root_hash, result_map)) - } -} +// use std::collections::HashMap; +// +// use merk::proofs::query::Map; +// use rs_merkle::{algorithms::Sha256, MerkleProof}; +// +// use crate::{Element, Error, GroveDb, PathQuery, Proof, Query}; +// +// impl GroveDb { +// pub fn proof(&mut self, proof_queries: Vec) -> Result, Error> { +// // To prove a path we need to return a proof for each node on the path including +// // the root. With multiple paths, nodes can overlap i.e two or more paths can +// // share the same nodes. We should only have one proof for each node, +// // if a node forks into multiple relevant paths then we should create a +// // combined proof for that node with all the relevant keys +// let mut query_paths = Vec::new(); +// let mut intermediate_proof_spec: HashMap, Query> = HashMap::new(); +// let mut root_keys: Vec> = Vec::new(); +// let mut proofs: HashMap, Vec> = HashMap::new(); +// +// // For each unique node including the root +// // determine what keys would need to be included in the proof +// for proof_query in proof_queries.iter() { +// query_paths.push( +// proof_query +// .path +// .iter() +// .map(|x| x.to_vec()) +// .collect::>(), +// ); +// +// let mut split_path = proof_query.path.split_last(); +// while let Some((key, path_slice)) = split_path { +// if path_slice.is_empty() { +// // We have gotten to the root node +// let compressed_path = GroveDb::compress_subtree_key(&[], Some(key)); +// root_keys.push(compressed_path); +// } else { +// let compressed_path = GroveDb::compress_subtree_key(path_slice, None); +// if let Some(path_query) = intermediate_proof_spec.get_mut(&compressed_path) { +// path_query.insert_key(key.to_vec()); +// } else { +// let mut path_query = Query::new(); +// path_query.insert_key(key.to_vec()); +// intermediate_proof_spec.insert(compressed_path, path_query); +// } +// } +// split_path = path_slice.split_last(); +// } +// } +// +// // Construct the path proofs +// for (path, query) in intermediate_proof_spec { +// let proof = self.prove_item(&path, query)?; +// proofs.insert(path, proof); +// } +// +// // Construct the leaf proofs +// for proof_query in proof_queries { +// let path = proof_query.path; +// +// // If there is a subquery with a limit it's possible that we only need a reduced +// // proof for this leaf. +// let reduced_proof_query = proof_query; +// +// // First we must get elements +// +// if let Some(subquery_key) = reduced_proof_query.query.query.subquery_key.clone() { +// self.get_path_queries_raw(&[&reduced_proof_query], None)?; +// +// let mut path_vec = path.to_vec(); +// path_vec.push(subquery_key.as_slice()); +// let compressed_path = GroveDb::compress_subtree_key(path_vec.as_slice(), None); +// } +// +// // Now we must insert the final proof for the sub leaves +// let compressed_path = GroveDb::compress_subtree_key(path, None); +// let proof = self.prove_path_item(&compressed_path, reduced_proof_query)?; +// proofs.insert(compressed_path, proof); +// } +// +// // Construct the root proof +// let mut root_index: Vec = Vec::new(); +// for key in root_keys { +// let index = self +// .root_leaf_keys +// .get(&key) +// .ok_or(Error::InvalidPath("root key not found"))?; +// root_index.push(*index); +// } +// let root_proof = self.root_tree.proof(&root_index).to_bytes(); +// +// let proof = Proof { +// query_paths, +// proofs, +// root_proof, +// root_leaf_keys: self.root_leaf_keys.clone(), +// }; +// +// let seralized_proof = bincode::serialize(&proof) +// .map_err(|_| Error::CorruptedData(String::from("unable to serialize proof")))?; +// +// Ok(seralized_proof) +// } +// +// fn prove_path_item( +// &self, +// compressed_path: &Vec, +// path_query: PathQuery, +// ) -> Result, Error> { +// let merk = self +// .subtrees +// .get(compressed_path) +// .ok_or(Error::InvalidPath("no subtree found under that path"))?; +// +// let sized_query = path_query.query; +// +// if sized_query.query.subquery.is_none() { +// // then limit should be applied directly to the proof here +// let proof_result = merk +// .prove( +// sized_query.query, +// sized_query.limit, +// sized_query.offset, +// ) +// .expect("should prove both inclusion and absence"); +// Ok(proof_result) +// } else { +// let proof_result = merk +// .prove(sized_query.query, None, None) +// .expect("should prove both inclusion and absence"); +// Ok(proof_result) +// } +// } +// +// fn prove_item(&self, path: &Vec, query: Query) -> Result, Error> { +// let merk = self +// .subtrees +// .get(path) +// .ok_or(Error::InvalidPath("no subtree found under that path"))?; +// +// // then limit should be applied directly to the proof here +// let proof_result = merk +// .prove(query, None, None) +// .expect("should prove both inclusion and absence"); +// Ok(proof_result) +// } +// +// pub fn execute_proof(proof: Vec) -> Result<([u8; 32], HashMap, Map>), Error> { +// // Deserialize the proof +// let proof: Proof = bincode::deserialize(&proof) +// .map_err(|_| Error::CorruptedData(String::from("unable to deserialize proof")))?; +// +// // Required to execute the root proof +// let mut root_keys_index: Vec = Vec::new(); +// let mut root_hashes: Vec<[u8; 32]> = Vec::new(); +// +// // Collects the result map for each query +// let mut result_map: HashMap, Map> = HashMap::new(); +// +// for path in proof.query_paths { +// let path = path.iter().map(|x| x.as_slice()).collect::>(); +// // For each query path, get the result map after execution +// // and store hash + index for later root proof execution +// let root_key = &path[0]; +// let (hash, proof_result_map) = GroveDb::execute_path(&path, &proof.proofs)?; +// let compressed_root_key_path = GroveDb::compress_subtree_key(&[], Some(root_key)); +// let compressed_query_path = GroveDb::compress_subtree_key(&path, None); +// +// let index = proof +// .root_leaf_keys +// .get(&compressed_root_key_path) +// .ok_or(Error::InvalidPath("Bad path"))?; +// if !root_keys_index.contains(index) { +// root_keys_index.push(*index); +// root_hashes.push(hash); +// } +// +// result_map.insert(compressed_query_path, proof_result_map); +// } +// +// let root_proof = match MerkleProof::::try_from(proof.root_proof) { +// Ok(proof) => Ok(proof), +// Err(_) => Err(Error::InvalidProof("Invalid proof element")), +// }?; +// +// let root_hash = +// match root_proof.root(&root_keys_index, &root_hashes, proof.root_leaf_keys.len()) { +// Ok(hash) => Ok(hash), +// Err(_) => Err(Error::InvalidProof("Invalid proof element")), +// }?; +// +// Ok((root_hash, result_map)) +// } +// +// // Given a query path and a set of proofs +// // execute_path validates that the nodes represented by the paths +// // are connected to one another i.e root hash of child node is in parent node +// // at the correct key. +// // If path is valid, it returns the root hash of topmost merk and result map of +// // leaf merk. +// fn execute_path( +// path: &[&[u8]], +// proofs: &HashMap, Vec>, +// ) -> Result<([u8; 32], Map), Error> { +// let compressed_path = GroveDb::compress_subtree_key(path, None); +// let proof = proofs +// .get(&compressed_path) +// .ok_or(Error::InvalidPath("Bad path"))?; +// +// // Execute the leaf merk proof +// let (mut last_root_hash, result_map) = match merk::execute_proof(&proof[..]) { +// Ok(result) => Ok(result), +// Err(_) => Err(Error::InvalidPath("Invalid proof element")), +// }?; +// +// // Validate the path +// let mut split_path = path.split_last(); +// while let Some((key, path_slice)) = split_path { +// if !path_slice.is_empty() { +// let compressed_path = GroveDb::compress_subtree_key(path_slice, None); +// let proof = proofs +// .get(&compressed_path) +// .ok_or(Error::InvalidPath("Bad path"))?; +// +// let proof_result = match merk::execute_proof(&proof[..]) { +// Ok(result) => Ok(result), +// Err(_) => Err(Error::InvalidPath("Invalid proof element")), +// }?; +// +// let result_map = proof_result.1; +// // TODO: Handle the error better here +// let elem: Element = +// bincode::deserialize(result_map.get(key).unwrap().unwrap()).unwrap(); +// let merk_root_hash = match elem { +// Element::Tree(hash) => Ok(hash), +// _ => Err(Error::InvalidProof( +// "Intermediate proofs should be for trees", +// )), +// }?; +// +// if merk_root_hash != last_root_hash { +// return Err(Error::InvalidProof("Bad path")); +// } +// +// last_root_hash = proof_result.0; +// } else { +// break; +// } +// +// split_path = path_slice.split_last(); +// } +// +// Ok((last_root_hash, result_map)) +// } +// } diff --git a/grovedb/src/subtree.rs b/grovedb/src/subtree.rs index ba0f78883..9fb03ba4c 100644 --- a/grovedb/src/subtree.rs +++ b/grovedb/src/subtree.rs @@ -1,7 +1,7 @@ //! Module for subtrees handling. //! Subtrees handling is isolated so basically this module is about adapting //! Merk API to GroveDB needs. -use std::collections::HashMap; +use std::{collections::HashMap, ops::Sub}; use merk::{ proofs::{query::QueryItem, Query}, @@ -17,7 +17,7 @@ use storage::{ RawIterator, Storage, Store, }; -use crate::{Error, GroveDb, Merk, PathQuery, SizedQuery}; +use crate::{Error, GroveDb, Merk, PathQuery, SizedQuery, Subtrees}; /// Variants of GroveDB stored entities #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] @@ -68,7 +68,7 @@ impl Element { pub fn get_query( merk: &Merk, query: &Query, - subtrees_option: Option<&HashMap, Merk>>, + subtrees_option: Option<&Subtrees>, ) -> Result, Error> { let sized_query = SizedQuery::new(query.clone(), None, None); let (elements, _) = Element::get_sized_query(merk, &sized_query, subtrees_option)?; @@ -76,7 +76,8 @@ impl Element { } fn basic_push( - _subtrees: Option<&HashMap, Merk>>, + // _subtrees: Option<&HashMap, Merk>>, + _subtree: Option<&Subtrees>, _key: Option<&[u8]>, element: Element, _path: Option<&[&[u8]]>, @@ -99,7 +100,8 @@ impl Element { } fn path_query_push( - subtrees_option: Option<&HashMap, Merk>>, + // subtrees_option: Option<&HashMap, Merk>>, + subtrees_option: Option<&Subtrees>, key: Option<&[u8]>, element: Element, path: Option<&[&[u8]]>, @@ -135,13 +137,20 @@ impl Element { if let Some(subquery_key) = &subquery_key_option { path_vec.push(subquery_key.as_slice()); } - let inner_merk = subtrees - .get(&GroveDb::compress_subtree_key(path_vec.as_slice(), None)) - .ok_or(Error::InvalidPath("no subtree found under that path"))?; + let (inner_merk, prefix) = subtrees + .get(path_vec.as_slice(), None) + .map_err(|_| Error::InvalidPath("no subtree found under that path"))?; let inner_query = SizedQuery::new(subquery, *limit, *offset); let inner_path_query = PathQuery::new(path_vec.as_slice(), inner_query); let (mut sub_elements, skipped) = - Element::get_path_query(inner_merk, &inner_path_query, subtrees_option)?; + Element::get_path_query(&inner_merk, &inner_path_query, subtrees_option)?; + + if let Some(prefix) = prefix { + subtrees.insert_temp_tree_with_prefix(prefix, inner_merk, None); + } else { + subtrees.insert_temp_tree(path_vec.as_slice(), inner_merk, None); + } + if let Some(limit) = limit { *limit = *limit - sub_elements.len() as u16; } @@ -150,11 +159,11 @@ impl Element { } results.append(&mut sub_elements); } else if let Some(subquery_key) = subquery_key_option { - let inner_merk = subtrees - .get(&GroveDb::compress_subtree_key(path_vec.as_slice(), None)) - .ok_or(Error::InvalidPath("no subtree found under that path"))?; + let (inner_merk, prefix) = subtrees + .get(path_vec.as_slice(), None) + .map_err(|_| Error::InvalidPath("no subtree found under that path"))?; if offset.is_none() || offset.is_some() && offset.unwrap() == 0 { - results.push(Element::get(inner_merk, subquery_key.as_slice())?); + results.push(Element::get(&inner_merk, subquery_key.as_slice())?); if limit.is_some() { *limit = Some(limit.unwrap() - 1); } @@ -163,6 +172,11 @@ impl Element { *offset = Some(offset.unwrap() - 1); } } + if let Some(prefix) = prefix { + subtrees.insert_temp_tree_with_prefix(prefix, inner_merk, None); + } else { + subtrees.insert_temp_tree(path_vec.as_slice(), inner_merk, None); + } } else { return Err(Error::InvalidPath( "you must provide a subquery or a subquery_key when interacting with a \ @@ -188,9 +202,10 @@ impl Element { merk: &Merk, sized_query: &SizedQuery, path: Option<&[&[u8]]>, - subtrees: Option<&HashMap, Merk>>, + subtrees: Option<&Subtrees>, add_element_function: fn( - subtrees: Option<&HashMap, Merk>>, + // subtrees: Option<&HashMap, Merk>>, + subtrees: Option<&Subtrees>, key: Option<&[u8]>, element: Element, path: Option<&[&[u8]]>, @@ -278,7 +293,8 @@ impl Element { pub fn get_path_query( merk: &Merk, path_query: &PathQuery, - subtrees: Option<&HashMap, Merk>>, + // subtrees: Option<&HashMap, Merk>>, + subtrees: Option<&Subtrees>, ) -> Result<(Vec, u16), Error> { Element::get_query_apply_function( merk, @@ -293,7 +309,7 @@ impl Element { pub fn get_sized_query( merk: &Merk, sized_query: &SizedQuery, - subtrees: Option<&HashMap, Merk>>, + subtrees: Option<&Subtrees>, ) -> Result<(Vec, u16), Error> { Element::get_query_apply_function( merk, diff --git a/grovedb/src/subtrees.rs b/grovedb/src/subtrees.rs new file mode 100644 index 000000000..97a67587d --- /dev/null +++ b/grovedb/src/subtrees.rs @@ -0,0 +1,139 @@ +//! Module for retrieving subtrees +use std::{cell::RefCell, collections::HashMap, rc::Rc}; + +use merk::Merk; +use storage::{ + rocksdb_storage::{OptimisticTransactionDBTransaction, PrefixedRocksDbStorage}, + RawIterator, +}; + +use crate::{Element, Error, GroveDb}; + +// TODO: should take temp_root_leaf_keys also +pub struct Subtrees<'a> { + pub root_leaf_keys: &'a HashMap, usize>, + pub temp_subtrees: &'a RefCell, Merk>>, + pub storage: Rc, +} + +impl Subtrees<'_> { + pub fn insert_temp_tree( + &self, + path: &[&[u8]], + merk: Merk, + transaction: Option<&OptimisticTransactionDBTransaction>, + ) -> Option> { + match transaction { + None => None, + Some(_) => { + let prefix = GroveDb::compress_subtree_key(path, None); + self.temp_subtrees.borrow_mut().insert(prefix, merk) + } + } + } + + pub fn insert_temp_tree_with_prefix( + &self, + prefix: Vec, + merk: Merk, + transaction: Option<&OptimisticTransactionDBTransaction>, + ) -> Option> { + match transaction { + None => None, + Some(_) => self.temp_subtrees.borrow_mut().insert(prefix, merk), + } + } + + pub fn get( + &self, + path: &[&[u8]], + transaction: Option<&OptimisticTransactionDBTransaction>, + ) -> Result<(Merk, Option>), Error> { + let merk; + let mut prefix: Option> = None; + match transaction { + None => { + merk = self.get_subtree_without_transaction(path)?; + } + Some(_) => { + let tree_prefix = GroveDb::compress_subtree_key(path, None); + prefix = Some(tree_prefix.clone()); + if self.temp_subtrees.borrow().contains_key(&tree_prefix) { + // get the merk out + merk = self + .temp_subtrees + .borrow_mut() + .remove(&tree_prefix) + .expect("confirmed it's in the hashmap"); + } else { + // merk is not in the hash map get it without transaction + merk = self.get_subtree_without_transaction(path)?; + } + } + } + Ok((merk, prefix)) + } + + pub fn get_subtree_without_transaction( + &self, + path: &[&[u8]], + ) -> Result, Error> { + let (subtree, has_keys) = self.get_subtree_with_key_info(path, None)?; + if !has_keys { + // if the subtree has no keys, it's either empty or invalid + // we can confirm that it's an empty tree by checking if it was inserted into + // the parent tree + let (key, parent_path) = path.split_last().ok_or(Error::InvalidPath("empty path"))?; + + // if parent path is empty, we are dealing with root leaf node + // we can confirm validity of a root leaf node by checking root_leaf_keys + if parent_path.is_empty() { + let root_key = path[0].to_vec(); + return if self.root_leaf_keys.contains_key(&root_key) { + Ok(subtree) + } else { + Err(Error::InvalidPath("no subtree found under that path")) + }; + } + + // Non root leaf nodes, get parent tree and confirm child validity + let (parent_tree, has_keys) = self.get_subtree_with_key_info(parent_path, None)?; + if !has_keys { + // parent tree can't be empty, hence invalid path + Err(Error::InvalidPath("no subtree found under that path")) + } else { + // Check that it contains the child as an empty tree + let elem = Element::get(&parent_tree, key) + .map_err(|_| Error::InvalidPath("no subtree found under that path"))?; + match elem { + Element::Tree(_) => Ok(subtree), + _ => Err(Error::InvalidPath("no subtree found under that path")), + } + } + } else { + Ok(subtree) + } + } + + fn get_subtree_with_key_info( + &self, + path: &[&[u8]], + key: Option<&[u8]>, + ) -> Result<(Merk, bool), Error> { + let subtree_prefix = GroveDb::compress_subtree_key(path, key); + let merk = Merk::open(PrefixedRocksDbStorage::new( + self.storage.clone(), + subtree_prefix, + )?) + .map_err(|_| Error::InvalidPath("no subtree found under that path"))?; + let mut has_keys = false; + { + let mut iter = merk.raw_iter(); + iter.seek_to_first(); + if iter.valid() { + has_keys = true; + } + } + Ok((merk, has_keys)) + } +} diff --git a/grovedb/src/tests.rs b/grovedb/src/tests.rs index 71a0a404a..6fe8db714 100644 --- a/grovedb/src/tests.rs +++ b/grovedb/src/tests.rs @@ -3,7 +3,6 @@ use std::{ option::Option::None, }; -use merk::test_utils::TempMerk; use rand::Rng; use tempdir::TempDir; @@ -262,383 +261,383 @@ fn test_tree_structure_is_presistent() { fn test_root_tree_leafs_are_noted() { let db = make_grovedb(); let mut hm = HashMap::new(); - hm.insert(GroveDb::compress_subtree_key(&[TEST_LEAF], None), 0); - hm.insert(GroveDb::compress_subtree_key(&[ANOTHER_TEST_LEAF], None), 1); + hm.insert(TEST_LEAF.to_vec(), 0); + hm.insert(ANOTHER_TEST_LEAF.to_vec(), 1); assert_eq!(db.root_leaf_keys, hm); assert_eq!(db.root_tree.leaves_len(), 2); } -#[test] -fn test_proof_construction() { - // Tree Structure - // root - // test_leaf - // innertree - // k1,v1 - // k2,v2 - // another_test_leaf - // innertree2 - // k3,v3 - // innertree3 - // k4,v4 - - // Insert elements into grovedb instance - let mut temp_db = make_grovedb(); - // Insert level 1 nodes - temp_db - .insert( - &[TEST_LEAF], - b"innertree".to_vec(), - Element::empty_tree(), - None, - ) - .expect("successful subtree insert"); - temp_db - .insert( - &[ANOTHER_TEST_LEAF], - b"innertree2".to_vec(), - Element::empty_tree(), - None, - ) - .expect("successful subtree insert"); - temp_db - .insert( - &[ANOTHER_TEST_LEAF], - b"innertree3".to_vec(), - Element::empty_tree(), - None, - ) - .expect("successful subtree insert"); - // Insert level 2 nodes - temp_db - .insert( - &[TEST_LEAF, b"innertree"], - b"key1".to_vec(), - Element::Item(b"value1".to_vec()), - None, - ) - .expect("successful subtree insert"); - temp_db - .insert( - &[TEST_LEAF, b"innertree"], - b"key2".to_vec(), - Element::Item(b"value2".to_vec()), - None, - ) - .expect("successful subtree insert"); - temp_db - .insert( - &[ANOTHER_TEST_LEAF, b"innertree2"], - b"key3".to_vec(), - Element::Item(b"value3".to_vec()), - None, - ) - .expect("successful subtree insert"); - temp_db - .insert( - &[ANOTHER_TEST_LEAF, b"innertree3"], - b"key4".to_vec(), - Element::Item(b"value4".to_vec()), - None, - ) - .expect("successful subtree insert"); - - // Manually construct HADS bottom up - // Insert level 2 nodes - let mut inner_tree = TempMerk::new(); - let value_one = Element::Item(b"value1".to_vec()); - value_one - .insert(&mut inner_tree, b"key1".to_vec(), None) - .unwrap(); - let value_two = Element::Item(b"value2".to_vec()); - value_two - .insert(&mut inner_tree, b"key2".to_vec(), None) - .unwrap(); - - let mut inner_tree_2 = TempMerk::new(); - let value_three = Element::Item(b"value3".to_vec()); - value_three - .insert(&mut inner_tree_2, b"key3".to_vec(), None) - .unwrap(); - - let mut inner_tree_3 = TempMerk::new(); - let value_four = Element::Item(b"value4".to_vec()); - value_four - .insert(&mut inner_tree_3, b"key4".to_vec(), None) - .unwrap(); - // Insert level 1 nodes - let mut test_leaf = TempMerk::new(); - let inner_tree_root = Element::Tree(inner_tree.root_hash()); - inner_tree_root - .insert(&mut test_leaf, b"innertree".to_vec(), None) - .unwrap(); - let mut another_test_leaf = TempMerk::new(); - let inner_tree_2_root = Element::Tree(inner_tree_2.root_hash()); - inner_tree_2_root - .insert(&mut another_test_leaf, b"innertree2".to_vec(), None) - .unwrap(); - let inner_tree_3_root = Element::Tree(inner_tree_3.root_hash()); - inner_tree_3_root - .insert(&mut another_test_leaf, b"innertree3".to_vec(), None) - .unwrap(); - // Insert root nodes - let leaves = [test_leaf.root_hash(), another_test_leaf.root_hash()]; - let root_tree = MerkleTree::::from_leaves(&leaves); - - // Proof construction - // Generating a proof for two paths - // root -> test_leaf -> innertree (prove both k1 and k2) - // root -> another_test_leaf -> innertree3 (prove k4) - // root -> another_test_leaf -> innertree2 (prove k3) - - // Build reusable query objects - let mut path_one_query = Query::new(); - path_one_query.insert_key(b"key1".to_vec()); - path_one_query.insert_key(b"key2".to_vec()); - - let mut path_two_query = Query::new(); - path_two_query.insert_key(b"key4".to_vec()); - - let mut path_three_query = Query::new(); - path_three_query.insert_key(b"key3".to_vec()); - - // Get grovedb proof - let proof = temp_db - .proof(vec![ - PathQuery::new_unsized(&[TEST_LEAF, b"innertree"], path_one_query), - PathQuery::new_unsized(&[ANOTHER_TEST_LEAF, b"innertree3"], path_two_query), - PathQuery::new_unsized(&[ANOTHER_TEST_LEAF, b"innertree2"], path_three_query), - ]) - .unwrap(); - - // Deserialize the proof - let proof: Proof = bincode::deserialize(&proof).unwrap(); - - // Perform assertions - assert_eq!(proof.query_paths.len(), 3); - assert_eq!(proof.query_paths[0], &[TEST_LEAF, b"innertree"]); - assert_eq!(proof.query_paths[1], &[ANOTHER_TEST_LEAF, b"innertree3"]); - assert_eq!(proof.query_paths[2], &[ANOTHER_TEST_LEAF, b"innertree2"]); - - // For path 1 to path 3, there are 9 nodes - // root is repeated three times and another_test_leaf is repeated twice - // Accounting for duplication, there are 6 unique nodes - // root, test_leaf, another_test_leaf, innertree, innertree2, innertree3 - // proof.proofs contains all nodes except the root so we expect 5 sub proofs - assert_eq!(proof.proofs.len(), 5); - - // Check that all the subproofs were constructed correctly for each path and - // subpath - let path_one_as_vec = GroveDb::compress_subtree_key(&[TEST_LEAF, b"innertree"], None); - let path_two_as_vec = GroveDb::compress_subtree_key(&[ANOTHER_TEST_LEAF, b"innertree3"], None); - let path_three_as_vec = - GroveDb::compress_subtree_key(&[ANOTHER_TEST_LEAF, b"innertree2"], None); - let test_leaf_path_as_vec = GroveDb::compress_subtree_key(&[TEST_LEAF], None); - let another_test_leaf_path_as_vec = GroveDb::compress_subtree_key(&[ANOTHER_TEST_LEAF], None); - - let proof_for_path_one = proof.proofs.get(&path_one_as_vec).unwrap(); - let proof_for_path_two = proof.proofs.get(&path_two_as_vec).unwrap(); - let proof_for_path_three = proof.proofs.get(&path_three_as_vec).unwrap(); - let proof_for_test_leaf = proof.proofs.get(&test_leaf_path_as_vec).unwrap(); - let proof_for_another_test_leaf = proof.proofs.get(&another_test_leaf_path_as_vec).unwrap(); - - // Assert path 1 proof - let mut proof_query = Query::new(); - proof_query.insert_key(b"key1".to_vec()); - proof_query.insert_key(b"key2".to_vec()); - assert_eq!( - *proof_for_path_one, - inner_tree.prove(proof_query, None, None).unwrap() - ); - - // Assert path 2 proof - let mut proof_query = Query::new(); - proof_query.insert_key(b"key4".to_vec()); - assert_eq!( - *proof_for_path_two, - inner_tree_3.prove(proof_query, None, None).unwrap() - ); - - // Assert path 3 proof - let mut proof_query = Query::new(); - proof_query.insert_key(b"key3".to_vec()); - assert_eq!( - *proof_for_path_three, - inner_tree_2.prove(proof_query, None, None).unwrap() - ); - - // Assert test leaf proof - let mut proof_query = Query::new(); - proof_query.insert_key(b"innertree".to_vec()); - assert_eq!( - *proof_for_test_leaf, - test_leaf.prove(proof_query, None, None).unwrap() - ); - - // Assert another test leaf proof - // another test leaf appeared in two path, - // hence it should contain proofs for both keys - let mut proof_query = Query::new(); - proof_query.insert_key(b"innertree2".to_vec()); - proof_query.insert_key(b"innertree3".to_vec()); - assert_eq!( - *proof_for_another_test_leaf, - another_test_leaf - .prove(proof_query, None, None) - .unwrap() - ); - - // Check that the root proof is valid - // Root proof should contain proof for both test_leaf and another_test_leaf - let test_leaf_root_key = GroveDb::compress_subtree_key(&[], Some(TEST_LEAF)); - let another_test_leaf_root_key = GroveDb::compress_subtree_key(&[], Some(ANOTHER_TEST_LEAF)); - assert_eq!( - proof.root_proof, - root_tree - .proof(&[ - temp_db.root_leaf_keys[&test_leaf_root_key], - temp_db.root_leaf_keys[&another_test_leaf_root_key], - ]) - .to_bytes() - ); - - // Assert that we got the correct root leaf keys - assert_eq!(proof.root_leaf_keys.len(), 2); - assert_eq!(proof.root_leaf_keys[&test_leaf_root_key], 0); - assert_eq!(proof.root_leaf_keys[&another_test_leaf_root_key], 1); -} - -#[test] -fn test_successful_proof_verification() { - // Build a grovedb database - // Tree Structure - // root - // test_leaf - // innertree - // k1,v1 - // k2,v2 - // another_test_leaf - // innertree2 - // k3,v3 - // innertree3 - // k4,v4 - - // Insert elements into grovedb instance - let mut temp_db = make_grovedb(); - // Insert level 1 nodes - temp_db - .insert( - &[TEST_LEAF], - b"innertree".to_vec(), - Element::empty_tree(), - None, - ) - .expect("successful subtree insert"); - temp_db - .insert( - &[ANOTHER_TEST_LEAF], - b"innertree2".to_vec(), - Element::empty_tree(), - None, - ) - .expect("successful subtree insert"); - temp_db - .insert( - &[ANOTHER_TEST_LEAF], - b"innertree3".to_vec(), - Element::empty_tree(), - None, - ) - .expect("successful subtree insert"); - // Insert level 2 nodes - temp_db - .insert( - &[TEST_LEAF, b"innertree"], - b"key1".to_vec(), - Element::Item(b"value1".to_vec()), - None, - ) - .expect("successful subtree insert"); - temp_db - .insert( - &[TEST_LEAF, b"innertree"], - b"key2".to_vec(), - Element::Item(b"value2".to_vec()), - None, - ) - .expect("successful subtree insert"); - temp_db - .insert( - &[ANOTHER_TEST_LEAF, b"innertree2"], - b"key3".to_vec(), - Element::Item(b"value3".to_vec()), - None, - ) - .expect("successful subtree insert"); - temp_db - .insert( - &[ANOTHER_TEST_LEAF, b"innertree3"], - b"key4".to_vec(), - Element::Item(b"value4".to_vec()), - None, - ) - .expect("successful subtree insert"); - - // Single query proof verification - let mut path_one_query = Query::new(); - path_one_query.insert_key(b"key1".to_vec()); - path_one_query.insert_key(b"key2".to_vec()); - - let proof = temp_db - .proof(vec![PathQuery::new_unsized( - &[TEST_LEAF, b"innertree"], - path_one_query, - )]) - .unwrap(); - - // Assert correct root hash - let (root_hash, result_maps) = GroveDb::execute_proof(proof).unwrap(); - assert_eq!(temp_db.root_tree.root().unwrap(), root_hash); - - // Assert correct result object - // Proof query was for two keys key1 and key2 - let path_as_vec = GroveDb::compress_subtree_key(&[TEST_LEAF, b"innertree"], None); - let result_map = result_maps.get(&path_as_vec).unwrap(); - let elem_1: Element = bincode::deserialize(result_map.get(b"key1").unwrap().unwrap()).unwrap(); - let elem_2: Element = bincode::deserialize(result_map.get(b"key2").unwrap().unwrap()).unwrap(); - assert_eq!(elem_1, Element::Item(b"value1".to_vec())); - assert_eq!(elem_2, Element::Item(b"value2".to_vec())); - - // Multi query proof verification - let mut path_two_query = Query::new(); - path_two_query.insert_key(b"key4".to_vec()); - - let mut path_three_query = Query::new(); - path_three_query.insert_key(b"key3".to_vec()); - - // Get grovedb proof - let proof = temp_db - .proof(vec![ - PathQuery::new_unsized(&[ANOTHER_TEST_LEAF, b"innertree3"], path_two_query), - PathQuery::new_unsized(&[ANOTHER_TEST_LEAF, b"innertree2"], path_three_query), - ]) - .unwrap(); - - // Assert correct root hash - let (root_hash, result_maps) = GroveDb::execute_proof(proof).unwrap(); - assert_eq!(temp_db.root_tree.root().unwrap(), root_hash); - - // Assert correct result object - let path_one_as_vec = GroveDb::compress_subtree_key(&[ANOTHER_TEST_LEAF, b"innertree3"], None); - let result_map = result_maps.get(&path_one_as_vec).unwrap(); - let elem: Element = bincode::deserialize(result_map.get(b"key4").unwrap().unwrap()).unwrap(); - assert_eq!(elem, Element::Item(b"value4".to_vec())); +// #[test] +// fn test_proof_construction() { +// // Tree Structure +// // root +// // test_leaf +// // innertree +// // k1,v1 +// // k2,v2 +// // another_test_leaf +// // innertree2 +// // k3,v3 +// // innertree3 +// // k4,v4 +// +// // Insert elements into grovedb instance +// let mut temp_db = make_grovedb(); +// // Insert level 1 nodes +// temp_db +// .insert( +// &[TEST_LEAF], +// b"innertree".to_vec(), +// Element::empty_tree(), +// None, +// ) +// .expect("successful subtree insert"); +// temp_db +// .insert( +// &[ANOTHER_TEST_LEAF], +// b"innertree2".to_vec(), +// Element::empty_tree(), +// None, +// ) +// .expect("successful subtree insert"); +// temp_db +// .insert( +// &[ANOTHER_TEST_LEAF], +// b"innertree3".to_vec(), +// Element::empty_tree(), +// None, +// ) +// .expect("successful subtree insert"); +// // Insert level 2 nodes +// temp_db +// .insert( +// &[TEST_LEAF, b"innertree"], +// b"key1".to_vec(), +// Element::Item(b"value1".to_vec()), +// None, +// ) +// .expect("successful subtree insert"); +// temp_db +// .insert( +// &[TEST_LEAF, b"innertree"], +// b"key2".to_vec(), +// Element::Item(b"value2".to_vec()), +// None, +// ) +// .expect("successful subtree insert"); +// temp_db +// .insert( +// &[ANOTHER_TEST_LEAF, b"innertree2"], +// b"key3".to_vec(), +// Element::Item(b"value3".to_vec()), +// None, +// ) +// .expect("successful subtree insert"); +// temp_db +// .insert( +// &[ANOTHER_TEST_LEAF, b"innertree3"], +// b"key4".to_vec(), +// Element::Item(b"value4".to_vec()), +// None, +// ) +// .expect("successful subtree insert"); +// +// // Manually construct HADS bottom up +// // Insert level 2 nodes +// let mut inner_tree = TempMerk::new(); +// let value_one = Element::Item(b"value1".to_vec()); +// value_one +// .insert(&mut inner_tree, b"key1".to_vec(), None) +// .unwrap(); +// let value_two = Element::Item(b"value2".to_vec()); +// value_two +// .insert(&mut inner_tree, b"key2".to_vec(), None) +// .unwrap(); +// +// let mut inner_tree_2 = TempMerk::new(); +// let value_three = Element::Item(b"value3".to_vec()); +// value_three +// .insert(&mut inner_tree_2, b"key3".to_vec(), None) +// .unwrap(); +// +// let mut inner_tree_3 = TempMerk::new(); +// let value_four = Element::Item(b"value4".to_vec()); +// value_four +// .insert(&mut inner_tree_3, b"key4".to_vec(), None) +// .unwrap(); +// // Insert level 1 nodes +// let mut test_leaf = TempMerk::new(); +// let inner_tree_root = Element::Tree(inner_tree.root_hash()); +// inner_tree_root +// .insert(&mut test_leaf, b"innertree".to_vec(), None) +// .unwrap(); +// let mut another_test_leaf = TempMerk::new(); +// let inner_tree_2_root = Element::Tree(inner_tree_2.root_hash()); +// inner_tree_2_root +// .insert(&mut another_test_leaf, b"innertree2".to_vec(), None) +// .unwrap(); +// let inner_tree_3_root = Element::Tree(inner_tree_3.root_hash()); +// inner_tree_3_root +// .insert(&mut another_test_leaf, b"innertree3".to_vec(), None) +// .unwrap(); +// // Insert root nodes +// let leaves = [test_leaf.root_hash(), another_test_leaf.root_hash()]; +// let root_tree = MerkleTree::::from_leaves(&leaves); +// +// // Proof construction +// // Generating a proof for two paths +// // root -> test_leaf -> innertree (prove both k1 and k2) +// // root -> another_test_leaf -> innertree3 (prove k4) +// // root -> another_test_leaf -> innertree2 (prove k3) +// +// // Build reusable query objects +// let mut path_one_query = Query::new(); +// path_one_query.insert_key(b"key1".to_vec()); +// path_one_query.insert_key(b"key2".to_vec()); +// +// let mut path_two_query = Query::new(); +// path_two_query.insert_key(b"key4".to_vec()); +// +// let mut path_three_query = Query::new(); +// path_three_query.insert_key(b"key3".to_vec()); +// +// // Get grovedb proof +// let proof = temp_db +// .proof(vec![ +// PathQuery::new_unsized(&[TEST_LEAF, b"innertree"], path_one_query), +// PathQuery::new_unsized(&[ANOTHER_TEST_LEAF, b"innertree3"], path_two_query), +// PathQuery::new_unsized(&[ANOTHER_TEST_LEAF, b"innertree2"], path_three_query), +// ]) +// .unwrap(); +// +// // Deserialize the proof +// let proof: Proof = bincode::deserialize(&proof).unwrap(); +// +// // Perform assertions +// assert_eq!(proof.query_paths.len(), 3); +// assert_eq!(proof.query_paths[0], &[TEST_LEAF, b"innertree"]); +// assert_eq!(proof.query_paths[1], &[ANOTHER_TEST_LEAF, b"innertree3"]); +// assert_eq!(proof.query_paths[2], &[ANOTHER_TEST_LEAF, b"innertree2"]); +// +// // For path 1 to path 3, there are 9 nodes +// // root is repeated three times and another_test_leaf is repeated twice +// // Accounting for duplication, there are 6 unique nodes +// // root, test_leaf, another_test_leaf, innertree, innertree2, innertree3 +// // proof.proofs contains all nodes except the root so we expect 5 sub proofs +// assert_eq!(proof.proofs.len(), 5); +// +// // Check that all the subproofs were constructed correctly for each path and +// // subpath +// let path_one_as_vec = GroveDb::compress_subtree_key(&[TEST_LEAF, b"innertree"], None); +// let path_two_as_vec = GroveDb::compress_subtree_key(&[ANOTHER_TEST_LEAF, b"innertree3"], None); +// let path_three_as_vec = +// GroveDb::compress_subtree_key(&[ANOTHER_TEST_LEAF, b"innertree2"], None); +// let test_leaf_path_as_vec = GroveDb::compress_subtree_key(&[TEST_LEAF], None); +// let another_test_leaf_path_as_vec = GroveDb::compress_subtree_key(&[ANOTHER_TEST_LEAF], None); +// +// let proof_for_path_one = proof.proofs.get(&path_one_as_vec).unwrap(); +// let proof_for_path_two = proof.proofs.get(&path_two_as_vec).unwrap(); +// let proof_for_path_three = proof.proofs.get(&path_three_as_vec).unwrap(); +// let proof_for_test_leaf = proof.proofs.get(&test_leaf_path_as_vec).unwrap(); +// let proof_for_another_test_leaf = proof.proofs.get(&another_test_leaf_path_as_vec).unwrap(); +// +// // Assert path 1 proof +// let mut proof_query = Query::new(); +// proof_query.insert_key(b"key1".to_vec()); +// proof_query.insert_key(b"key2".to_vec()); +// assert_eq!( +// *proof_for_path_one, +// inner_tree.prove(proof_query, None, None).unwrap() +// ); +// +// // Assert path 2 proof +// let mut proof_query = Query::new(); +// proof_query.insert_key(b"key4".to_vec()); +// assert_eq!( +// *proof_for_path_two, +// inner_tree_3.prove(proof_query, None, None).unwrap() +// ); +// +// // Assert path 3 proof +// let mut proof_query = Query::new(); +// proof_query.insert_key(b"key3".to_vec()); +// assert_eq!( +// *proof_for_path_three, +// inner_tree_2.prove(proof_query, None, None).unwrap() +// ); +// +// // Assert test leaf proof +// let mut proof_query = Query::new(); +// proof_query.insert_key(b"innertree".to_vec()); +// assert_eq!( +// *proof_for_test_leaf, +// test_leaf.prove(proof_query, None, None).unwrap() +// ); +// +// // Assert another test leaf proof +// // another test leaf appeared in two path, +// // hence it should contain proofs for both keys +// let mut proof_query = Query::new(); +// proof_query.insert_key(b"innertree2".to_vec()); +// proof_query.insert_key(b"innertree3".to_vec()); +// assert_eq!( +// *proof_for_another_test_leaf, +// another_test_leaf +// .prove(proof_query, None, None) +// .unwrap() +// ); +// +// // Check that the root proof is valid +// // Root proof should contain proof for both test_leaf and another_test_leaf +// let test_leaf_root_key = GroveDb::compress_subtree_key(&[], Some(TEST_LEAF)); +// let another_test_leaf_root_key = GroveDb::compress_subtree_key(&[], Some(ANOTHER_TEST_LEAF)); +// assert_eq!( +// proof.root_proof, +// root_tree +// .proof(&[ +// temp_db.root_leaf_keys[&test_leaf_root_key], +// temp_db.root_leaf_keys[&another_test_leaf_root_key], +// ]) +// .to_bytes() +// ); +// +// // Assert that we got the correct root leaf keys +// assert_eq!(proof.root_leaf_keys.len(), 2); +// assert_eq!(proof.root_leaf_keys[&test_leaf_root_key], 0); +// assert_eq!(proof.root_leaf_keys[&another_test_leaf_root_key], 1); +// } - let path_two_as_vec = GroveDb::compress_subtree_key(&[ANOTHER_TEST_LEAF, b"innertree2"], None); - let result_map = result_maps.get(&path_two_as_vec).unwrap(); - let elem: Element = bincode::deserialize(result_map.get(b"key3").unwrap().unwrap()).unwrap(); - assert_eq!(elem, Element::Item(b"value3".to_vec())); -} +// #[test] +// fn test_successful_proof_verification() { +// // Build a grovedb database +// // Tree Structure +// // root +// // test_leaf +// // innertree +// // k1,v1 +// // k2,v2 +// // another_test_leaf +// // innertree2 +// // k3,v3 +// // innertree3 +// // k4,v4 +// +// // Insert elements into grovedb instance +// let mut temp_db = make_grovedb(); +// // Insert level 1 nodes +// temp_db +// .insert( +// &[TEST_LEAF], +// b"innertree".to_vec(), +// Element::empty_tree(), +// None, +// ) +// .expect("successful subtree insert"); +// temp_db +// .insert( +// &[ANOTHER_TEST_LEAF], +// b"innertree2".to_vec(), +// Element::empty_tree(), +// None, +// ) +// .expect("successful subtree insert"); +// temp_db +// .insert( +// &[ANOTHER_TEST_LEAF], +// b"innertree3".to_vec(), +// Element::empty_tree(), +// None, +// ) +// .expect("successful subtree insert"); +// // Insert level 2 nodes +// temp_db +// .insert( +// &[TEST_LEAF, b"innertree"], +// b"key1".to_vec(), +// Element::Item(b"value1".to_vec()), +// None, +// ) +// .expect("successful subtree insert"); +// temp_db +// .insert( +// &[TEST_LEAF, b"innertree"], +// b"key2".to_vec(), +// Element::Item(b"value2".to_vec()), +// None, +// ) +// .expect("successful subtree insert"); +// temp_db +// .insert( +// &[ANOTHER_TEST_LEAF, b"innertree2"], +// b"key3".to_vec(), +// Element::Item(b"value3".to_vec()), +// None, +// ) +// .expect("successful subtree insert"); +// temp_db +// .insert( +// &[ANOTHER_TEST_LEAF, b"innertree3"], +// b"key4".to_vec(), +// Element::Item(b"value4".to_vec()), +// None, +// ) +// .expect("successful subtree insert"); +// +// // Single query proof verification +// let mut path_one_query = Query::new(); +// path_one_query.insert_key(b"key1".to_vec()); +// path_one_query.insert_key(b"key2".to_vec()); +// +// let proof = temp_db +// .proof(vec![PathQuery::new_unsized( +// &[TEST_LEAF, b"innertree"], +// path_one_query, +// )]) +// .unwrap(); +// +// // Assert correct root hash +// let (root_hash, result_maps) = GroveDb::execute_proof(proof).unwrap(); +// assert_eq!(temp_db.root_tree.root().unwrap(), root_hash); +// +// // Assert correct result object +// // Proof query was for two keys key1 and key2 +// let path_as_vec = GroveDb::compress_subtree_key(&[TEST_LEAF, b"innertree"], None); +// let result_map = result_maps.get(&path_as_vec).unwrap(); +// let elem_1: Element = bincode::deserialize(result_map.get(b"key1").unwrap().unwrap()).unwrap(); +// let elem_2: Element = bincode::deserialize(result_map.get(b"key2").unwrap().unwrap()).unwrap(); +// assert_eq!(elem_1, Element::Item(b"value1".to_vec())); +// assert_eq!(elem_2, Element::Item(b"value2".to_vec())); +// +// // Multi query proof verification +// let mut path_two_query = Query::new(); +// path_two_query.insert_key(b"key4".to_vec()); +// +// let mut path_three_query = Query::new(); +// path_three_query.insert_key(b"key3".to_vec()); +// +// // Get grovedb proof +// let proof = temp_db +// .proof(vec![ +// PathQuery::new_unsized(&[ANOTHER_TEST_LEAF, b"innertree3"], path_two_query), +// PathQuery::new_unsized(&[ANOTHER_TEST_LEAF, b"innertree2"], path_three_query), +// ]) +// .unwrap(); +// +// // Assert correct root hash +// let (root_hash, result_maps) = GroveDb::execute_proof(proof).unwrap(); +// assert_eq!(temp_db.root_tree.root().unwrap(), root_hash); +// +// // Assert correct result object +// let path_one_as_vec = GroveDb::compress_subtree_key(&[ANOTHER_TEST_LEAF, b"innertree3"], None); +// let result_map = result_maps.get(&path_one_as_vec).unwrap(); +// let elem: Element = bincode::deserialize(result_map.get(b"key4").unwrap().unwrap()).unwrap(); +// assert_eq!(elem, Element::Item(b"value4".to_vec())); +// +// let path_two_as_vec = GroveDb::compress_subtree_key(&[ANOTHER_TEST_LEAF, b"innertree2"], None); +// let result_map = result_maps.get(&path_two_as_vec).unwrap(); +// let elem: Element = bincode::deserialize(result_map.get(b"key3").unwrap().unwrap()).unwrap(); +// assert_eq!(elem, Element::Item(b"value3".to_vec())); +// } // #[test] // fn test_checkpoint() { @@ -946,12 +945,12 @@ fn transaction_should_be_aborted() { assert!(db.is_readonly); assert!(db.temp_root_tree.leaves_len() > 0); assert!(!db.temp_root_leaf_keys.is_empty()); - assert!(!db.temp_subtrees.is_empty()); + assert!(!db.temp_subtrees.borrow().is_empty()); db.abort_transaction(transaction).unwrap(); assert!(!db.is_readonly); assert_eq!(db.temp_root_tree.leaves_len(), 0); assert!(db.temp_root_leaf_keys.is_empty()); - assert!(db.temp_subtrees.is_empty()); + assert!(db.temp_subtrees.borrow().is_empty()); // Transaction should be closed assert!(!db.is_transaction_started()); @@ -1025,9 +1024,14 @@ fn test_subtree_pairs_iterator() { .expect("succesful value insert"); // Iterate over subtree1 to see if keys of other subtrees messed up - let mut iter = db - .elements_iterator(&[TEST_LEAF, b"subtree1"], None) - .expect("cannot create iterator"); + // let mut iter = db + // .elements_iterator(&[TEST_LEAF, b"subtree1"], None) + // .expect("cannot create iterator"); + let (merk, _) = db + .get_subtrees() + .get(&[TEST_LEAF, b"subtree1"], None) + .unwrap(); + let mut iter = Element::iterator(merk.raw_iter()); assert_eq!(iter.next().unwrap(), Some((b"key1".to_vec(), element))); assert_eq!(iter.next().unwrap(), Some((b"key2".to_vec(), element2))); let subtree_element = iter.next().unwrap().unwrap(); @@ -1106,6 +1110,89 @@ fn test_find_subtrees() { ); } +#[test] +fn test_get_subtree() { + let mut db = make_grovedb(); + let element = Element::Item(b"ayy".to_vec()); + + // Returns error is subtree is not valid + let subtree = db.get_subtrees().get(&[TEST_LEAF, b"invalid_tree"], None); + assert_eq!(subtree.is_err(), true); + + // Doesn't return an error for subtree that exists but empty + let subtree = db.get_subtrees().get(&[TEST_LEAF], None); + assert_eq!(subtree.is_err(), false); + + // Insert some nested subtrees + db.insert(&[TEST_LEAF], b"key1".to_vec(), Element::empty_tree(), None) + .expect("successful subtree 1 insert"); + + db.insert( + &[TEST_LEAF, b"key1"], + b"key2".to_vec(), + Element::empty_tree(), + None, + ) + .expect("successful subtree 2 insert"); + + // Insert an element into subtree + db.insert( + &[TEST_LEAF, b"key1", b"key2"], + b"key3".to_vec(), + element.clone(), + None, + ) + .expect("successful value insert"); + db.insert(&[TEST_LEAF], b"key4".to_vec(), Element::empty_tree(), None) + .expect("successful subtree 3 insert"); + + // Retrieve subtree instance + // Check if it returns the same instance that was inserted + let (subtree, _) = db + .get_subtrees() + .get(&[TEST_LEAF, b"key1", b"key2"], None) + .unwrap(); + let result_element = Element::get(&subtree, b"key3").unwrap(); + assert_eq!(result_element, Element::Item(b"ayy".to_vec())); + + // Insert a new tree with transaction + db.start_transaction().unwrap(); + let storage = db.storage(); + let transaction = storage.transaction(); + + db.insert( + &[TEST_LEAF, b"key1"], + b"innertree".to_vec(), + Element::empty_tree(), + Some(&transaction), + ) + .expect("successful subtree insert"); + + db.insert( + &[TEST_LEAF, b"key1", b"innertree"], + b"key4".to_vec(), + element.clone(), + Some(&transaction), + ) + .expect("successful value insert"); + + // Retrieve subtree instance with transaction + let (subtree, _) = db + .get_subtrees() + .get(&[TEST_LEAF, b"key1", b"innertree"], Some(&transaction)) + .unwrap(); + let result_element = Element::get(&subtree, b"key4").unwrap(); + assert_eq!(result_element, Element::Item(b"ayy".to_vec())); + + // Should be able to retrieve instances created before transaction + let (subtree, _) = db + .get_subtrees() + .get(&[TEST_LEAF, b"key1", b"key2"], None) + .unwrap(); + let result_element = Element::get(&subtree, b"key3").unwrap(); + assert_eq!(result_element, Element::Item(b"ayy".to_vec())); +} + #[test] fn test_subtree_deletion() { let element = Element::Item(b"ayy".to_vec()); @@ -1138,7 +1225,10 @@ fn test_subtree_deletion() { db.get(&[TEST_LEAF, b"key1", b"key2"], b"key3", None), Err(Error::InvalidPath(_)) )); - assert_eq!(db.subtrees.len(), 3); // TEST_LEAF, ANOTHER_TEST_LEAF TEST_LEAF.key4 stay + // assert_eq!(db.subtrees.len(), 3); // TEST_LEAF, ANOTHER_TEST_LEAF + // TEST_LEAF.key4 stay + assert!(db.get(&[], TEST_LEAF, None).is_ok()); + assert!(db.get(&[], ANOTHER_TEST_LEAF, None).is_ok()); assert!(db.get(&[TEST_LEAF], b"key4", None).is_ok()); assert_ne!(root_hash, db.root_tree.root().unwrap()); }