From 05a4180ce98085aaee237e31054984fee9cdc4ba Mon Sep 17 00:00:00 2001 From: Wisdom Ogwu Date: Tue, 23 Nov 2021 08:36:36 +0100 Subject: [PATCH 01/20] Implemented single merk path + key proof --- .gitignore | 1 + grovedb/src/lib.rs | 19 ++++++++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 8ff0eb369..4b1aa93d0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target .idea Cargo.lock +grove.db \ No newline at end of file diff --git a/grovedb/src/lib.rs b/grovedb/src/lib.rs index 32a8c86f0..1b14b8234 100644 --- a/grovedb/src/lib.rs +++ b/grovedb/src/lib.rs @@ -5,7 +5,7 @@ use std::{ rc::Rc, }; -use merk::{self, rocksdb, Merk}; +use merk::{self, proofs::Query, rocksdb, Merk}; use rs_merkle::{algorithms::Sha256, MerkleTree}; use subtree::Element; mod subtree; @@ -203,8 +203,21 @@ impl GroveDb { Err(Error::ReferenceLimit) } - pub fn proof(&self) -> ! { - todo!() + pub fn proof(&self, path: &[&[u8]], key: &[u8]) -> Result, Error> { + let compressed_path = Self::compress_path(path, None); + let merk = self + .subtrees + .get(&Self::compress_path(path, None)) + .ok_or(Error::InvalidPath("no subtree found under that path"))?; + + // Generate a proof of this merk with the given key + let mut proof_query = Query::new(); + proof_query.insert_key(key.to_vec()); + + let proof_result = merk + .prove(proof_query) + .expect("should prove both inclusion and abscence"); + Ok(proof_result) } /// Method to propagate updated subtree root hashes up to GroveDB root From 08ce2d12c687dd1a381951cf547dbd9f8b0cb3cc Mon Sep 17 00:00:00 2001 From: Wisdom Ogwu Date: Wed, 24 Nov 2021 06:16:36 +0100 Subject: [PATCH 02/20] Recursive proofs wip --- grovedb/src/lib.rs | 50 +++++++++++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 14 deletions(-) diff --git a/grovedb/src/lib.rs b/grovedb/src/lib.rs index 1b14b8234..dd3210427 100644 --- a/grovedb/src/lib.rs +++ b/grovedb/src/lib.rs @@ -6,7 +6,7 @@ use std::{ }; use merk::{self, proofs::Query, rocksdb, Merk}; -use rs_merkle::{algorithms::Sha256, MerkleTree}; +use rs_merkle::{algorithms::Sha256, MerkleProof, MerkleTree}; use subtree::Element; mod subtree; @@ -203,21 +203,43 @@ impl GroveDb { Err(Error::ReferenceLimit) } - pub fn proof(&self, path: &[&[u8]], key: &[u8]) -> Result, Error> { - let compressed_path = Self::compress_path(path, None); - let merk = self - .subtrees - .get(&Self::compress_path(path, None)) - .ok_or(Error::InvalidPath("no subtree found under that path"))?; + pub fn proof( + &self, + path: &[&[u8]], + key: &[u8], + ) -> Result<(MerkleProof, Vec>), Error> { + // Grab the merk at a given path, create proof on merk for that key + // Continuously split path and generate proof + // if path is empty, then generate proof for root with given key + let mut split_path = path.split_last(); + let mut proofs: Vec> = Vec::new(); + let mut root_proof: MerkleProof; - // Generate a proof of this merk with the given key - let mut proof_query = Query::new(); - proof_query.insert_key(key.to_vec()); + while let Some((key, path_slice)) = split_path { + if path_slice.is_empty() { + // We have hit the root key + // Need to generate proof for this based on the index + // TODO: Use the correct index for the path name + root_proof = self.root_tree.proof(&vec![0]); + } + let merk = self + .subtrees + .get(&Self::compress_path(path, None)) + .ok_or(Error::InvalidPath("no subtree found under that path"))?; + + // Generate a proof of this merk with the given key + let mut proof_query = Query::new(); + proof_query.insert_key(key.to_vec()); + + let proof_result = merk + .prove(proof_query) + .expect("should prove both inclusion and absence"); + + proofs.push(proof_result); + split_path = path_slice.split_last(); + } - let proof_result = merk - .prove(proof_query) - .expect("should prove both inclusion and abscence"); - Ok(proof_result) + Ok((root_proof, proofs)) } /// Method to propagate updated subtree root hashes up to GroveDB root From 9901b94933846bab8dff8667240cb06fbe7961b0 Mon Sep 17 00:00:00 2001 From: Wisdom Ogwu Date: Fri, 26 Nov 2021 06:49:32 +0100 Subject: [PATCH 03/20] Returning the root proof as an option --- grovedb/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/grovedb/src/lib.rs b/grovedb/src/lib.rs index dd3210427..22617f4e5 100644 --- a/grovedb/src/lib.rs +++ b/grovedb/src/lib.rs @@ -207,20 +207,20 @@ impl GroveDb { &self, path: &[&[u8]], key: &[u8], - ) -> Result<(MerkleProof, Vec>), Error> { + ) -> Result<(Option>, Vec>), Error> { // Grab the merk at a given path, create proof on merk for that key // Continuously split path and generate proof // if path is empty, then generate proof for root with given key let mut split_path = path.split_last(); let mut proofs: Vec> = Vec::new(); - let mut root_proof: MerkleProof; + let mut root_proof: Option> = None; while let Some((key, path_slice)) = split_path { if path_slice.is_empty() { // We have hit the root key // Need to generate proof for this based on the index // TODO: Use the correct index for the path name - root_proof = self.root_tree.proof(&vec![0]); + root_proof = Some(self.root_tree.proof(&vec![0])); } let merk = self .subtrees From a69f57b9d959ae071708378b1bf91eb2d658708d Mon Sep 17 00:00:00 2001 From: Wisdom Ogwu Date: Fri, 26 Nov 2021 12:47:16 +0100 Subject: [PATCH 04/20] fmt --- grovedb/src/lib.rs | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/grovedb/src/lib.rs b/grovedb/src/lib.rs index 8b9620a11..f39cf3e73 100644 --- a/grovedb/src/lib.rs +++ b/grovedb/src/lib.rs @@ -15,7 +15,8 @@ use subtree::Element; /// Limit of possible indirections const MAX_REFERENCE_HOPS: usize = 10; -/// A key to store serialized data about subtree prefixes to restore HADS structure +/// A key to store serialized data about subtree prefixes to restore HADS +/// structure const SUBTRESS_SERIALIZED_KEY: &[u8] = b"subtreesSerialized"; /// A key to store serialized data about root tree leafs keys and order const ROOT_LEAFS_SERIALIZED_KEY: &[u8] = b"rootLeafsSerialized"; @@ -68,11 +69,12 @@ impl GroveDb { } // TODO: owned `get` is not required for deserialization - let root_leaf_keys: Vec> = if let Some(root_leaf_keys_serialized) = db.get(ROOT_LEAFS_SERIALIZED_KEY)? { - bincode::deserialize(&root_leaf_keys_serialized)? - } else { - Vec::new() - }; + let root_leaf_keys: Vec> = + if let Some(root_leaf_keys_serialized) = db.get(ROOT_LEAFS_SERIALIZED_KEY)? { + bincode::deserialize(&root_leaf_keys_serialized)? + } else { + Vec::new() + }; Ok(GroveDb { root_tree: Self::build_root_tree(&subtrees, &root_leaf_keys), @@ -90,7 +92,10 @@ impl GroveDb { Ok(db.put(SUBTRESS_SERIALIZED_KEY, bincode::serialize(&prefixes)?)?) } - fn build_root_tree(subtrees: &HashMap, Merk>, root_leaf_keys: &Vec>) -> MerkleTree { + fn build_root_tree( + subtrees: &HashMap, Merk>, + root_leaf_keys: &Vec>, + ) -> MerkleTree { let mut leaf_hashes = Vec::new(); for subtree_path in root_leaf_keys { let subtree_merk = subtrees @@ -121,7 +126,8 @@ impl GroveDb { if path.is_empty() { // Add subtree to the root tree let (compressed_path_subtree, subtree_merk) = create_subtree_merk()?; - self.subtrees.insert(compressed_path_subtree.clone(), subtree_merk); + self.subtrees + .insert(compressed_path_subtree.clone(), subtree_merk); // TODO: fine for now, not fine after if !self.root_leaf_keys.contains(&compressed_path_subtree) { self.root_leaf_keys.push(compressed_path_subtree); @@ -232,6 +238,12 @@ impl GroveDb { // We have hit the root key // Need to generate proof for this based on the index // TODO: Use the correct index for the path name + + // let root_key_index = self + // .root_leaf_keys + // .iter() + // .position(|&leaf| leaf.as_slice() == *key) + // .expect("Root key should exist"); root_proof = Some(self.root_tree.proof(&vec![0])); } let merk = self From ef331bc0d39dab99586edc044eeb2c9635c32ec1 Mon Sep 17 00:00:00 2001 From: Evgeny Fomin Date: Fri, 26 Nov 2021 15:45:54 +0300 Subject: [PATCH 05/20] restore a number of tests --- grovedb/src/lib.rs | 1 - grovedb/src/subtree.rs | 6 +- merk/src/merk/chunks.rs | 506 +++++++++++++++---------------- merk/src/merk/mod.rs | 181 +++++------ merk/src/proofs/chunk.rs | 114 +++---- merk/src/test_utils/mod.rs | 2 +- merk/src/test_utils/temp_merk.rs | 26 +- 7 files changed, 392 insertions(+), 444 deletions(-) diff --git a/grovedb/src/lib.rs b/grovedb/src/lib.rs index fbfb7da55..fdbefe868 100644 --- a/grovedb/src/lib.rs +++ b/grovedb/src/lib.rs @@ -99,7 +99,6 @@ impl GroveDb { subtrees: &HashMap, Merk>, root_leaf_keys: &HashMap, usize>, ) -> MerkleTree { - // let mut leaf_hashes = Vec::with_capacity(root_leaf_keys.len()); 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 diff --git a/grovedb/src/subtree.rs b/grovedb/src/subtree.rs index aacc1d769..6b3c5a36f 100644 --- a/grovedb/src/subtree.rs +++ b/grovedb/src/subtree.rs @@ -13,7 +13,9 @@ pub enum Element { Item(Vec), /// A reference to an object by its path Reference(Vec>), - /// A subtree, contains a root hash of the underlying Merk + /// A subtree, contains a root hash of the underlying Merk. + /// Hash is stored to make Merk become different when its subtrees have + /// changed, otherwise changes won't be reflected in parent trees. Tree([u8; 32]), } @@ -50,7 +52,7 @@ mod tests { #[test] fn test_success_insert() { - let mut merk = TempMerk::new().unwrap(); + let mut merk = TempMerk::new(); Element::empty_tree() .insert(&mut merk, b"mykey".to_vec()) .expect("expected successful insertion"); diff --git a/merk/src/merk/chunks.rs b/merk/src/merk/chunks.rs index 853865d20..6d6665c5e 100644 --- a/merk/src/merk/chunks.rs +++ b/merk/src/merk/chunks.rs @@ -149,266 +149,246 @@ impl Merk { } } -// #[cfg(test)] -// mod tests { -// use super::*; -// use crate::{ -// proofs::{ -// chunk::{verify_leaf, verify_trunk}, -// Decoder, -// }, -// test_utils::*, -// }; - -// #[test] -// fn len_small() { -// let mut merk = TempMerk::new().unwrap(); -// let batch = make_batch_seq(1..256); -// merk.apply(batch.as_slice(), &[]).unwrap(); - -// let chunks = merk.chunks().unwrap(); -// assert_eq!(chunks.len(), 1); -// assert_eq!(chunks.into_iter().size_hint().0, 1); -// } - -// #[test] -// fn len_big() { -// let mut merk = TempMerk::new().unwrap(); -// let batch = make_batch_seq(1..10_000); -// merk.apply(batch.as_slice(), &[]).unwrap(); - -// let chunks = merk.chunks().unwrap(); -// assert_eq!(chunks.len(), 129); -// assert_eq!(chunks.into_iter().size_hint().0, 129); -// } - -// #[test] -// fn generate_and_verify_chunks() { -// let mut merk = TempMerk::new().unwrap(); -// let batch = make_batch_seq(1..10_000); -// merk.apply(batch.as_slice(), &[]).unwrap(); - -// let mut chunks = -// merk.chunks().unwrap().into_iter().map(Result::unwrap); - -// let chunk = chunks.next().unwrap(); -// let ops = Decoder::new(chunk.as_slice()); -// let (trunk, height) = verify_trunk(ops).unwrap(); -// assert_eq!(height, 14); -// assert_eq!(trunk.hash(), merk.root_hash()); - -// assert_eq!(trunk.layer(7).count(), 128); - -// for (chunk, node) in chunks.zip(trunk.layer(height / 2)) { -// let ops = Decoder::new(chunk.as_slice()); -// verify_leaf(ops, node.hash()).unwrap(); -// } -// } - -// #[test] -// fn chunks_from_reopen() { -// let time = std::time::SystemTime::now() -// .duration_since(std::time::SystemTime::UNIX_EPOCH) -// .unwrap() -// .as_nanos(); -// let path = format!("chunks_from_reopen_{}.db", time); - -// let original_chunks = { -// let mut merk = Merk::open(&path).unwrap(); -// let batch = make_batch_seq(1..10); -// merk.apply(batch.as_slice(), &[]).unwrap(); - -// merk.chunks() -// .unwrap() -// .into_iter() -// .map(Result::unwrap) -// .collect::>() -// .into_iter() -// }; - -// let merk = TempMerk::open(path).unwrap(); -// let reopen_chunks = -// merk.chunks().unwrap().into_iter().map(Result::unwrap); - -// for (original, checkpoint) in original_chunks.zip(reopen_chunks) { -// assert_eq!(original.len(), checkpoint.len()); -// } -// } - -// #[test] -// fn chunks_from_checkpoint() { -// let mut merk = TempMerk::new().unwrap(); -// let batch = make_batch_seq(1..10); -// merk.apply(batch.as_slice(), &[]).unwrap(); - -// let path: std::path::PathBuf = -// "generate_and_verify_chunks_from_checkpoint.db".into(); if -// path.exists() { std::fs::remove_dir_all(&path).unwrap(); -// } -// let checkpoint = merk.checkpoint(&path).unwrap(); - -// let original_chunks = -// merk.chunks().unwrap().into_iter().map(Result::unwrap); let -// checkpoint_chunks = -// checkpoint.chunks().unwrap().into_iter().map(Result::unwrap); - -// for (original, checkpoint) in original_chunks.zip(checkpoint_chunks) -// { assert_eq!(original.len(), checkpoint.len()); -// } - -// std::fs::remove_dir_all(&path).unwrap(); -// } - -// #[test] -// fn random_access_chunks() { -// let mut merk = TempMerk::new().unwrap(); -// let batch = make_batch_seq(1..111); -// merk.apply(batch.as_slice(), &[]).unwrap(); - -// let chunks = merk -// .chunks() -// .unwrap() -// .into_iter() -// .map(Result::unwrap) -// .collect::>(); - -// let mut producer = merk.chunks().unwrap(); -// for i in 0..chunks.len() * 2 { -// let index = i % chunks.len(); -// assert_eq!(producer.chunk(index).unwrap(), chunks[index]); -// } -// } - -// #[test] -// #[should_panic(expected = "Attempted to fetch chunk on empty tree")] -// fn test_chunk_empty() { -// let merk = TempMerk::new().unwrap(); - -// let _chunks = merk -// .chunks() -// .unwrap() -// .into_iter() -// .map(Result::unwrap) -// .collect::>(); -// } - -// #[test] -// #[should_panic(expected = "Chunk index out-of-bounds")] -// fn test_chunk_index_oob() { -// let mut merk = TempMerk::new().unwrap(); -// let batch = make_batch_seq(1..42); -// merk.apply(batch.as_slice(), &[]).unwrap(); - -// let mut producer = merk.chunks().unwrap(); -// let _chunk = producer.chunk(50000).unwrap(); -// } - -// #[test] -// fn test_chunk_index_gt_1_access() { -// let mut merk = TempMerk::new().unwrap(); -// let batch = make_batch_seq(1..513); -// merk.apply(batch.as_slice(), &[]).unwrap(); - -// let mut producer = merk.chunks().unwrap(); -// println!("length: {}", producer.len()); -// let chunk = producer.chunk(2).unwrap(); -// assert_eq!( -// chunk, -// vec![ -// 3, 8, 0, 0, 0, 0, 0, 0, 0, 18, 0, 60, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 3, 8, 0, 0, 0, 0, 0, 0, 0, 19, 0, 60, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 16, 3, 8, -// 0, 0, 0, 0, 0, 0, 0, 20, 0, 60, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 17, 3, 8, 0, 0, 0, 0, 0, 0, 0, 21, 0, 60, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 16, 3, 8, 0, 0, 0, 0, 0, -// 0, 0, 22, 0, 60, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 3, 8, 0, 0, 0, 0, 0, 0, 0, 23, 0, 60, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 16, 3, 8, 0, 0, 0, 0, 0, 0, 0, 24, 0, 60, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 17, 17, 3, 8, 0, 0, 0, 0, 0, 0, 0, -// 25, 0, 60, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 16, 3, 8, 0, 0, 0, 0, 0, 0, 0, 26, 0, 60, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 3, 8, 0, 0, 0, 0, 0, 0, 0, 27, 0, -// 60, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 16, 3, -// 8, 0, 0, 0, 0, 0, 0, 0, 28, 0, 60, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 17, 3, 8, 0, 0, 0, 0, 0, 0, 0, 29, 0, 60, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 16, 3, 8, 0, 0, 0, 0, -// 0, 0, 0, 30, 0, 60, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 3, 8, 0, 0, 0, 0, 0, 0, 0, 31, 0, 60, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 16, 3, 8, 0, 0, 0, 0, 0, 0, 0, -// 32, 0, 60, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, -// 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 17, 17, 17 -// ] -// ); -// } - -// #[test] -// #[should_panic(expected = "Called next_chunk after end")] -// fn test_next_chunk_index_oob() { -// let mut merk = TempMerk::new().unwrap(); -// let batch = make_batch_seq(1..42); -// merk.apply(batch.as_slice(), &[]).unwrap(); - -// let mut producer = merk.chunks().unwrap(); -// let _chunk1 = producer.next_chunk(); -// let _chunk2 = producer.next_chunk(); -// } -// } +#[cfg(test)] +mod tests { + use tempdir::TempDir; + + use super::*; + use crate::{ + proofs::{ + chunk::{verify_leaf, verify_trunk}, + Decoder, + }, + test_utils::*, + }; + + #[test] + fn len_small() { + let mut merk = TempMerk::new(); + let batch = make_batch_seq(1..256); + merk.apply(batch.as_slice(), &[]).unwrap(); + + let chunks = merk.chunks().unwrap(); + assert_eq!(chunks.len(), 1); + assert_eq!(chunks.into_iter().size_hint().0, 1); + } + + #[test] + fn len_big() { + let mut merk = TempMerk::new(); + let batch = make_batch_seq(1..10_000); + merk.apply(batch.as_slice(), &[]).unwrap(); + + let chunks = merk.chunks().unwrap(); + assert_eq!(chunks.len(), 129); + assert_eq!(chunks.into_iter().size_hint().0, 129); + } + + #[test] + fn generate_and_verify_chunks() { + let mut merk = TempMerk::new(); + let batch = make_batch_seq(1..10_000); + merk.apply(batch.as_slice(), &[]).unwrap(); + + let mut chunks = merk.chunks().unwrap().into_iter().map(Result::unwrap); + + let chunk = chunks.next().unwrap(); + let ops = Decoder::new(chunk.as_slice()); + let (trunk, height) = verify_trunk(ops).unwrap(); + assert_eq!(height, 14); + assert_eq!(trunk.hash(), merk.root_hash()); + + assert_eq!(trunk.layer(7).count(), 128); + + for (chunk, node) in chunks.zip(trunk.layer(height / 2)) { + let ops = Decoder::new(chunk.as_slice()); + verify_leaf(ops, node.hash()).unwrap(); + } + } + + #[test] + fn chunks_from_reopen() { + let tmp_dir = TempDir::new("chunks_from_reopen").expect("cannot create tempdir"); + let original_chunks = { + let db = default_rocksdb(tmp_dir.path()); + let mut merk = Merk::open(db, Vec::new()).unwrap(); + let batch = make_batch_seq(1..10); + merk.apply(batch.as_slice(), &[]).unwrap(); + + merk.chunks() + .unwrap() + .into_iter() + .map(Result::unwrap) + .collect::>() + .into_iter() + }; + + let db = default_rocksdb(tmp_dir.path()); + let merk = Merk::open(db, Vec::new()).unwrap(); + let reopen_chunks = merk.chunks().unwrap().into_iter().map(Result::unwrap); + + for (original, checkpoint) in original_chunks.zip(reopen_chunks) { + assert_eq!(original.len(), checkpoint.len()); + } + } + + // #[test] + // fn chunks_from_checkpoint() { + // let mut merk = TempMerk::new(); + // let batch = make_batch_seq(1..10); + // merk.apply(batch.as_slice(), &[]).unwrap(); + + // let path: std::path::PathBuf = + // "generate_and_verify_chunks_from_checkpoint.db".into(); if path. + // exists() { std::fs::remove_dir_all(&path).unwrap(); + // } + // let checkpoint = merk.checkpoint(&path).unwrap(); + + // let original_chunks = + // merk.chunks().unwrap().into_iter().map(Result::unwrap); + // let checkpoint_chunks = + // checkpoint.chunks().unwrap().into_iter().map(Result::unwrap); + + // for (original, checkpoint) in original_chunks.zip(checkpoint_chunks) { + // assert_eq!(original.len(), checkpoint.len()); + // } + + // std::fs::remove_dir_all(&path).unwrap(); + // } + + #[test] + fn random_access_chunks() { + let mut merk = TempMerk::new(); + let batch = make_batch_seq(1..111); + merk.apply(batch.as_slice(), &[]).unwrap(); + + let chunks = merk + .chunks() + .unwrap() + .into_iter() + .map(Result::unwrap) + .collect::>(); + + let mut producer = merk.chunks().unwrap(); + for i in 0..chunks.len() * 2 { + let index = i % chunks.len(); + assert_eq!(producer.chunk(index).unwrap(), chunks[index]); + } + } + + #[test] + #[should_panic(expected = "Attempted to fetch chunk on empty tree")] + fn test_chunk_empty() { + let merk = TempMerk::new(); + + let _chunks = merk + .chunks() + .unwrap() + .into_iter() + .map(Result::unwrap) + .collect::>(); + } + + #[test] + #[should_panic(expected = "Chunk index out-of-bounds")] + fn test_chunk_index_oob() { + let mut merk = TempMerk::new(); + let batch = make_batch_seq(1..42); + merk.apply(batch.as_slice(), &[]).unwrap(); + + let mut producer = merk.chunks().unwrap(); + let _chunk = producer.chunk(50000).unwrap(); + } + + #[test] + fn test_chunk_index_gt_1_access() { + let mut merk = TempMerk::new(); + let batch = make_batch_seq(1..513); + merk.apply(batch.as_slice(), &[]).unwrap(); + + let mut producer = merk.chunks().unwrap(); + println!("length: {}", producer.len()); + let chunk = producer.chunk(2).unwrap(); + assert_eq!( + chunk, + vec![ + 3, 8, 0, 0, 0, 0, 0, 0, 0, 18, 0, 60, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 3, 8, 0, 0, 0, 0, 0, 0, 0, 19, 0, 60, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 16, 3, 8, 0, 0, 0, 0, 0, 0, 0, 20, 0, 60, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 17, 3, 8, 0, 0, 0, 0, 0, 0, 0, + 21, 0, 60, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 16, 3, 8, 0, + 0, 0, 0, 0, 0, 0, 22, 0, 60, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 3, 8, 0, 0, 0, 0, 0, 0, 0, 23, 0, 60, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 16, 3, 8, 0, 0, 0, 0, 0, 0, 0, 24, 0, 60, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 17, 17, 3, 8, 0, 0, 0, 0, 0, 0, 0, 25, 0, + 60, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 16, 3, 8, 0, 0, 0, 0, + 0, 0, 0, 26, 0, 60, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 3, + 8, 0, 0, 0, 0, 0, 0, 0, 27, 0, 60, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 16, 3, 8, 0, 0, 0, 0, 0, 0, 0, 28, 0, 60, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 17, 3, 8, 0, 0, 0, 0, 0, 0, 0, 29, 0, 60, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 16, 3, 8, 0, 0, 0, 0, 0, 0, + 0, 30, 0, 60, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 3, 8, 0, 0, + 0, 0, 0, 0, 0, 31, 0, 60, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 16, 3, 8, 0, 0, 0, 0, 0, 0, 0, 32, 0, 60, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 17, 17, 17 + ] + ); + } + + #[test] + #[should_panic(expected = "Called next_chunk after end")] + fn test_next_chunk_index_oob() { + let mut merk = TempMerk::new(); + let batch = make_batch_seq(1..42); + merk.apply(batch.as_slice(), &[]).unwrap(); + + let mut producer = merk.chunks().unwrap(); + let _chunk1 = producer.next_chunk(); + let _chunk2 = producer.next_chunk(); + } +} diff --git a/merk/src/merk/mod.rs b/merk/src/merk/mod.rs index 445a2087b..86c85d2ac 100644 --- a/merk/src/merk/mod.rs +++ b/merk/src/merk/mod.rs @@ -52,27 +52,6 @@ impl Merk { Ok(merk) } - // /// Opens a store with the specified file path and the given options. If no - // /// store exists at that path, one will be created. - // pub fn open_opt

(path: P, prefix: &[u8], db_opts: rocksdb::Options) -> - // Result where - // P: AsRef, - // { - // let mut path_buf = PathBuf::new(); - // path_buf.push(path); - // let db = rocksdb::DB::open_cf_descriptors(&db_opts, &path_buf, - // column_families())?; - - // let mut merk = Merk { - // tree: Cell::new(None), - // db, - // path: path_buf, - // }; - // merk.load_root()?; - - // Ok(merk) - // } - pub fn default_db_opts() -> rocksdb::Options { let mut opts = rocksdb::Options::default(); opts.create_if_missing(true); @@ -160,7 +139,7 @@ impl Merk { /// /// # Example /// ``` - /// # let mut store = merk::test_utils::TempMerk::new().unwrap(); + /// # let mut store = merk::test_utils::TempMerk::new(); /// # store.apply(&[(vec![4,5,6], Op::Put(vec![0]))], &[]).unwrap(); /// /// use merk::Op; @@ -198,7 +177,7 @@ impl Merk { /// /// # Example /// ``` - /// # let mut store = merk::test_utils::TempMerk::new().unwrap(); + /// # let mut store = merk::test_utils::TempMerk::new(); /// # store.apply(&[(vec![4,5,6], Op::Put(vec![0]))], &[]).unwrap(); /// /// use merk::Op; @@ -223,15 +202,6 @@ impl Merk { self.commit(deleted_keys, aux) } - // /// Closes the store and deletes all data from disk. - // pub fn destroy(self) -> Result<()> { - // let opts = Merk::default_db_opts(); - // let path = self.path.clone(); - // drop(self); - // rocksdb::DB::destroy(&opts, path)?; - // Ok(()) - // } - /// Creates a Merkle proof for the list of queried keys. For each key in the /// query, if the key is found in the store then the value will be proven to /// be in the tree. For each key in the query that does not exist in the @@ -293,22 +263,21 @@ impl Merk { let mut batch = rocksdb::WriteBatch::default(); let mut to_batch = self.use_tree_mut(|maybe_tree| -> UseTreeMutResult { // TODO: concurrent commit + // + let mut prefixed_root = self.prefix.clone(); + prefixed_root.extend_from_slice(ROOT_KEY_KEY); if let Some(tree) = maybe_tree { // TODO: configurable committer let mut committer = MerkCommitter::new(tree.height(), 100); tree.commit(&mut committer)?; - let mut prefixed_root = self.prefix.clone(); - prefixed_root.extend_from_slice(ROOT_KEY_KEY); // update pointer to root node batch.put_cf(internal_cf, prefixed_root, tree.key()); Ok(committer.batch) } else { // empty tree, delete pointer to root - // batch.delete_cf(internal_cf, ROOT_KEY_KEY); - todo!("deletion of root pointer"); - + batch.delete_cf(internal_cf, prefixed_root); Ok(vec![]) } })?; @@ -481,7 +450,7 @@ fn fetch_existing_node(db: &rocksdb::DB, prefix: &[u8], key: &[u8]) -> Result, nodes: &mut Vec>) - // { nodes.push(node.tree().encode()); - // node.walk(true).unwrap().map(|c| collect(c, nodes)); - // node.walk(false).unwrap().map(|c| collect(c, nodes)); - // } - - // let time = std::time::SystemTime::now() - // .duration_since(std::time::SystemTime::UNIX_EPOCH) - // .unwrap() - // .as_nanos(); - // let path = format!("merk_reopen_{}.db", time); - - // let original_nodes = { - // let mut merk = Merk::open(&path).unwrap(); - // let batch = make_batch_seq(1..10_000); - // merk.apply(batch.as_slice(), &[]).unwrap(); - // let mut tree = merk.tree.take().unwrap(); - // let walker = RefWalker::new(&mut tree, merk.source()); + #[test] + fn reopen() { + fn collect(mut node: RefWalker, nodes: &mut Vec>) { + nodes.push(node.tree().encode()); + node.walk(true).unwrap().map(|c| collect(c, nodes)); + node.walk(false).unwrap().map(|c| collect(c, nodes)); + } - // let mut nodes = vec![]; - // collect(walker, &mut nodes); - // nodes - // }; + let tmp_dir = TempDir::new("test_reopen").expect("cannot open tempdir"); - // let merk = TempMerk::open(&path).unwrap(); - // let mut tree = merk.tree.take().unwrap(); - // let walker = RefWalker::new(&mut tree, merk.source()); + let original_nodes = { + let db = default_rocksdb(tmp_dir.path()); + let mut merk = Merk::open(db, Vec::new()).unwrap(); + let batch = make_batch_seq(1..10_000); + merk.apply(batch.as_slice(), &[]).unwrap(); + let mut tree = merk.tree.take().unwrap(); + let walker = RefWalker::new(&mut tree, merk.source()); - // let mut reopen_nodes = vec![]; - // collect(walker, &mut reopen_nodes); + let mut nodes = vec![]; + collect(walker, &mut nodes); + nodes + }; - // assert_eq!(reopen_nodes, original_nodes); - // } + let db = default_rocksdb(tmp_dir.path()); + let merk = Merk::open(db, Vec::new()).unwrap(); + let mut tree = merk.tree.take().unwrap(); + let walker = RefWalker::new(&mut tree, merk.source()); - // #[test] - // fn reopen_iter() { - // fn collect(iter: &mut rocksdb::DBRawIterator, nodes: &mut - // Vec<(Vec, Vec)>) { while iter.valid() { - // nodes.push((iter.key().unwrap().to_vec(), - // iter.value().unwrap().to_vec())); iter.next(); - // } - // } + let mut reopen_nodes = vec![]; + collect(walker, &mut reopen_nodes); - // let time = std::time::SystemTime::now() - // .duration_since(std::time::SystemTime::UNIX_EPOCH) - // .unwrap() - // .as_nanos(); - // let path = format!("merk_reopen_{}.db", time); + assert_eq!(reopen_nodes, original_nodes); + } - // let original_nodes = { - // let mut merk = Merk::open(&path).unwrap(); - // let batch = make_batch_seq(1..10_000); - // merk.apply(batch.as_slice(), &[]).unwrap(); + #[test] + fn reopen_iter() { + fn collect(iter: &mut rocksdb::DBRawIterator, nodes: &mut Vec<(Vec, Vec)>) { + while iter.valid() { + nodes.push((iter.key().unwrap().to_vec(), iter.value().unwrap().to_vec())); + iter.next(); + } + } + let tmp_dir = TempDir::new("reopen_iter_test").expect("cannot open tempdir"); - // let mut nodes = vec![]; - // collect(&mut merk.raw_iter(), &mut nodes); - // nodes - // }; + let original_nodes = { + let db = default_rocksdb(tmp_dir.path()); + let mut merk = Merk::open(db, Vec::new()).unwrap(); + let batch = make_batch_seq(1..10_000); + merk.apply(batch.as_slice(), &[]).unwrap(); - // let merk = TempMerk::open(&path).unwrap(); + let mut nodes = vec![]; + collect(&mut merk.raw_iter(), &mut nodes); + nodes + }; + let db = default_rocksdb(tmp_dir.path()); + let mut merk = Merk::open(db, Vec::new()).unwrap(); - // let mut reopen_nodes = vec![]; - // collect(&mut merk.raw_iter(), &mut reopen_nodes); + let mut reopen_nodes = vec![]; + collect(&mut merk.raw_iter(), &mut reopen_nodes); - // assert_eq!(reopen_nodes, original_nodes); - // } + assert_eq!(reopen_nodes, original_nodes); + } // #[test] // fn checkpoint() { - // let mut merk = TempMerk::new().expect("failed to open merk"); + // let mut merk = TempMerk::new(); // merk.apply(&[(vec![1], Op::Put(vec![0]))], &[]) // .expect("apply failed"); diff --git a/merk/src/proofs/chunk.rs b/merk/src/proofs/chunk.rs index ea7ac872c..40f088e78 100644 --- a/merk/src/proofs/chunk.rs +++ b/merk/src/proofs/chunk.rs @@ -403,61 +403,61 @@ mod tests { assert_eq!(counts.kvhash, 0); } - // #[test] - // fn leaf_chunk_roundtrip() { - // let mut merk = TempMerk::new().unwrap(); - // let batch = make_batch_seq(0..31); - // merk.apply(batch.as_slice(), &[]).unwrap(); - - // let root_node = merk.tree.take(); - // let root_key = root_node.as_ref().unwrap().key().to_vec(); - // merk.tree.set(root_node); - - // // whole tree as 1 leaf - // let mut iter = merk.db.raw_iterator(); - // iter.seek_to_first(); - // let chunk = get_next_chunk(&mut iter, None).unwrap(); - // let ops = chunk.into_iter().map(|op| Ok(op)); - // let chunk = verify_leaf(ops, merk.root_hash()).unwrap(); - // let counts = count_node_types(chunk); - // assert_eq!(counts.kv, 31); - // assert_eq!(counts.hash, 0); - // assert_eq!(counts.kvhash, 0); - // drop(iter); - - // let mut iter = merk.db.raw_iterator(); - // iter.seek_to_first(); - - // // left leaf - // let chunk = get_next_chunk(&mut iter, - // Some(root_key.as_slice())).unwrap(); let ops = - // chunk.into_iter().map(|op| Ok(op)); let chunk = verify_leaf( - // ops, - // [ - // 34, 133, 104, 181, 253, 249, 189, 168, 15, 209, 70, 164, 224, - // 192, 18, 36, 1, 74, 79, 9, 158, 188, 98, 47, 53, 32, 109, - // 14, 151, 13, 49, 74, ], - // ) - // .unwrap(); - // let counts = count_node_types(chunk); - // assert_eq!(counts.kv, 15); - // assert_eq!(counts.hash, 0); - // assert_eq!(counts.kvhash, 0); - - // // right leaf - // let chunk = get_next_chunk(&mut iter, None).unwrap(); - // let ops = chunk.into_iter().map(|op| Ok(op)); - // let chunk = verify_leaf( - // ops, - // [ - // 164, 29, 123, 213, 6, 25, 247, 238, 127, 53, 5, 70, 255, 87, - // 87, 204, 188, 169, 181, 4, 185, 180, 74, 52, 244, 134, - // 75, 47, 105, 129, 209, 112, ], - // ) - // .unwrap(); - // let counts = count_node_types(chunk); - // assert_eq!(counts.kv, 15); - // assert_eq!(counts.hash, 0); - // assert_eq!(counts.kvhash, 0); - // } + #[test] + fn leaf_chunk_roundtrip() { + let mut merk = TempMerk::new(); + let batch = make_batch_seq(0..31); + merk.apply(batch.as_slice(), &[]).unwrap(); + + let root_node = merk.tree.take(); + let root_key = root_node.as_ref().unwrap().key().to_vec(); + merk.tree.set(root_node); + + // whole tree as 1 leaf + let mut iter = merk.db.raw_iterator(); + iter.seek_to_first(); + let chunk = get_next_chunk(&mut iter, None).unwrap(); + let ops = chunk.into_iter().map(|op| Ok(op)); + let chunk = verify_leaf(ops, merk.root_hash()).unwrap(); + let counts = count_node_types(chunk); + assert_eq!(counts.kv, 31); + assert_eq!(counts.hash, 0); + assert_eq!(counts.kvhash, 0); + drop(iter); + + let mut iter = merk.db.raw_iterator(); + iter.seek_to_first(); + + // left leaf + let chunk = get_next_chunk(&mut iter, Some(root_key.as_slice())).unwrap(); + let ops = chunk.into_iter().map(|op| Ok(op)); + let chunk = verify_leaf( + ops, + [ + 34, 133, 104, 181, 253, 249, 189, 168, 15, 209, 70, 164, 224, 192, 18, 36, 1, 74, + 79, 9, 158, 188, 98, 47, 53, 32, 109, 14, 151, 13, 49, 74, + ], + ) + .unwrap(); + let counts = count_node_types(chunk); + assert_eq!(counts.kv, 15); + assert_eq!(counts.hash, 0); + assert_eq!(counts.kvhash, 0); + + // right leaf + let chunk = get_next_chunk(&mut iter, None).unwrap(); + let ops = chunk.into_iter().map(|op| Ok(op)); + let chunk = verify_leaf( + ops, + [ + 164, 29, 123, 213, 6, 25, 247, 238, 127, 53, 5, 70, 255, 87, 87, 204, 188, 169, + 181, 4, 185, 180, 74, 52, 244, 134, 75, 47, 105, 129, 209, 112, + ], + ) + .unwrap(); + let counts = count_node_types(chunk); + assert_eq!(counts.kv, 15); + assert_eq!(counts.hash, 0); + assert_eq!(counts.kvhash, 0); + } } diff --git a/merk/src/test_utils/mod.rs b/merk/src/test_utils/mod.rs index 80de96d4f..361f33183 100644 --- a/merk/src/test_utils/mod.rs +++ b/merk/src/test_utils/mod.rs @@ -6,7 +6,7 @@ use std::{convert::TryInto, ops::Range}; use byteorder::{BigEndian, WriteBytesExt}; use rand::prelude::*; // pub use crash_merk::CrashMerk; -pub use temp_merk::TempMerk; +pub use temp_merk::{default_rocksdb, TempMerk}; use crate::tree::{Batch, BatchEntry, NoopCommit, Op, PanicSource, Tree, Walker}; diff --git a/merk/src/test_utils/temp_merk.rs b/merk/src/test_utils/temp_merk.rs index 569aa02ff..c1fc2c06b 100644 --- a/merk/src/test_utils/temp_merk.rs +++ b/merk/src/test_utils/temp_merk.rs @@ -1,11 +1,12 @@ use std::{ ops::{Deref, DerefMut}, + path::Path, rc::Rc, }; use tempdir::TempDir; -use crate::{Merk, Result}; +use crate::Merk; /// Wraps a Merk instance and deletes it from disk it once it goes out of scope. pub struct TempMerk { @@ -15,20 +16,23 @@ pub struct TempMerk { impl TempMerk { /// Opens a `TempMerk` at an autogenerated, temporary file path. - pub fn new() -> Result { - let path = TempDir::new("db")?; - let db = Rc::new(rocksdb::DB::open_cf_descriptors( - &Merk::default_db_opts(), - &path, - crate::column_families(), - )?); - Ok(TempMerk { - inner: Merk::open(db, Vec::new())?, + pub fn new() -> TempMerk { + let path = TempDir::new("db").expect("cannot create tempdir"); + let db = default_rocksdb(path.path()); + TempMerk { + inner: Merk::open(db, Vec::new()).expect("cannot open Merk"), path, - }) + } } } +pub fn default_rocksdb(path: &Path) -> Rc { + Rc::new( + rocksdb::DB::open_cf_descriptors(&Merk::default_db_opts(), &path, crate::column_families()) + .expect("cannot create rocksdb"), + ) +} + impl Deref for TempMerk { type Target = Merk; From 4dbe5f15df9314ec0c3e3ceb52ed86baf7ae72ef Mon Sep 17 00:00:00 2001 From: Wisdom Ogwu Date: Mon, 29 Nov 2021 09:43:44 +0100 Subject: [PATCH 06/20] Updated proof function signature --- grovedb/src/lib.rs | 13 ++++--------- grovedb/src/tests.rs | 41 ++++++++++++++++++++++++++++++++++------- 2 files changed, 38 insertions(+), 16 deletions(-) diff --git a/grovedb/src/lib.rs b/grovedb/src/lib.rs index fcc020264..77821ae4a 100644 --- a/grovedb/src/lib.rs +++ b/grovedb/src/lib.rs @@ -10,7 +10,7 @@ use std::{ }; use merk::{self, proofs::Query, rocksdb, Merk}; -use rs_merkle::{algorithms::Sha256, MerkleProof, MerkleTree}; +use rs_merkle::{algorithms::Sha256, MerkleTree}; use subtree::Element; /// Limit of possible indirections @@ -232,14 +232,9 @@ impl GroveDb { Err(Error::ReferenceLimit) } - pub fn proof( - &self, - path: &[&[u8]], - key: &[u8], - ) -> Result<(MerkleProof, Vec>), Error> { + pub fn proof(&self, path: &[&[u8]], key: &[u8]) -> Result>, Error> { let mut split_path = Some((&key, path)); let mut proofs: Vec> = Vec::new(); - let mut root_proof: Option> = None; while let Some((key, path_slice)) = split_path { if path_slice.is_empty() { @@ -248,7 +243,7 @@ impl GroveDb { .root_leaf_keys .get(*key) .ok_or(Error::InvalidPath("root key not found"))?; - root_proof = Some(self.root_tree.proof(&vec![*root_key_index])); + proofs.push(self.root_tree.proof(&vec![*root_key_index]).to_bytes()); } else { let merk = self .subtrees @@ -268,7 +263,7 @@ impl GroveDb { split_path = path_slice.split_last(); } - Ok((root_proof.expect("must have root proof"), proofs)) + Ok(proofs) } /// Method to propagate updated subtree root hashes up to GroveDB root diff --git a/grovedb/src/tests.rs b/grovedb/src/tests.rs index ef6e28641..2af93a96c 100644 --- a/grovedb/src/tests.rs +++ b/grovedb/src/tests.rs @@ -1,5 +1,6 @@ use std::ops::{Deref, DerefMut}; +use merk::test_utils::TempMerk; use tempdir::TempDir; use super::*; @@ -242,11 +243,6 @@ fn test_root_tree_leafs_are_noted() { #[test] fn test_proof_construction() { - // Create temp db - // Add another subtree to one of the test leafs - // Insert a couple key value pairs to the inner subtree - // Generate the proof - // Assert that it generated the right amount of proofs let mut temp_db = make_grovedb(); temp_db .insert(&[TEST_LEAF], b"innertree".to_vec(), Element::empty_tree()) @@ -258,9 +254,40 @@ fn test_proof_construction() { Element::Item(b"value1".to_vec()), ) .expect("successful item insert"); - let (root_proof, ads_proofs) = temp_db + + // Manually build the ads structures + let mut inner_tree_merk = TempMerk::new().unwrap(); + let value_element = Element::Item(b"value1".to_vec()); + value_element.insert(&mut inner_tree_merk, b"key1".to_vec()); + + let mut test_leaf_merk = TempMerk::new().unwrap(); + let inner_tree_root_element = Element::Tree(inner_tree_merk.root_hash()); + inner_tree_root_element.insert(&mut test_leaf_merk, b"innertree".to_vec()); + + let another_test_leaf_merk = TempMerk::new().unwrap(); + + let leaves = [ + test_leaf_merk.root_hash(), + another_test_leaf_merk.root_hash(), + ]; + let root_tree = MerkleTree::::from_leaves(&leaves); + + // Generate groove db proof + let ads_proofs = temp_db .proof(&[TEST_LEAF, b"innertree"], b"key1") .expect("Successful proof generation"); + + assert_eq!(ads_proofs.len(), 3); + + let mut proof_query = Query::new(); + proof_query.insert_key(b"key1".to_vec()); + assert_eq!(ads_proofs[0], inner_tree_merk.prove(proof_query).unwrap(),); + + let mut proof_query = Query::new(); + proof_query.insert_key(b"innertree".to_vec()); + assert_eq!(ads_proofs[1], test_leaf_merk.prove(proof_query).unwrap(),); + + assert_eq!(ads_proofs[2], root_tree.proof(&vec![0]).to_bytes(),); // dbg!(root_proof); - // dbg!(ads_proofs); + dbg!(ads_proofs); } From 62b6a26bfa070d5a7bd8ed95113b490494abdb96 Mon Sep 17 00:00:00 2001 From: Wisdom Ogwu Date: Mon, 29 Nov 2021 09:51:06 +0100 Subject: [PATCH 07/20] Implemented test for proof construction --- grovedb/src/tests.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/grovedb/src/tests.rs b/grovedb/src/tests.rs index 2af93a96c..83fdf5ddd 100644 --- a/grovedb/src/tests.rs +++ b/grovedb/src/tests.rs @@ -288,6 +288,4 @@ fn test_proof_construction() { assert_eq!(ads_proofs[1], test_leaf_merk.prove(proof_query).unwrap(),); assert_eq!(ads_proofs[2], root_tree.proof(&vec![0]).to_bytes(),); - // dbg!(root_proof); - dbg!(ads_proofs); } From 8a8abd5ade52e714b6123ea73c069027b3de36c0 Mon Sep 17 00:00:00 2001 From: Wisdom Ogwu Date: Mon, 29 Nov 2021 10:14:24 +0100 Subject: [PATCH 08/20] fmt --- grovedb/src/tests.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/grovedb/src/tests.rs b/grovedb/src/tests.rs index 83fdf5ddd..5679168e3 100644 --- a/grovedb/src/tests.rs +++ b/grovedb/src/tests.rs @@ -281,11 +281,11 @@ fn test_proof_construction() { let mut proof_query = Query::new(); proof_query.insert_key(b"key1".to_vec()); - assert_eq!(ads_proofs[0], inner_tree_merk.prove(proof_query).unwrap(),); + assert_eq!(ads_proofs[0], inner_tree_merk.prove(proof_query).unwrap()); let mut proof_query = Query::new(); proof_query.insert_key(b"innertree".to_vec()); - assert_eq!(ads_proofs[1], test_leaf_merk.prove(proof_query).unwrap(),); + assert_eq!(ads_proofs[1], test_leaf_merk.prove(proof_query).unwrap()); - assert_eq!(ads_proofs[2], root_tree.proof(&vec![0]).to_bytes(),); + assert_eq!(ads_proofs[2], root_tree.proof(&vec![0]).to_bytes()); } From 0bd438e144440b375b3f4290cb0c24cbf1c192fc Mon Sep 17 00:00:00 2001 From: Wisdom Ogwu Date: Mon, 29 Nov 2021 16:43:38 +0100 Subject: [PATCH 09/20] Removed unwrap when createing tempmerk --- grovedb/src/tests.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/grovedb/src/tests.rs b/grovedb/src/tests.rs index 5679168e3..441366745 100644 --- a/grovedb/src/tests.rs +++ b/grovedb/src/tests.rs @@ -256,15 +256,15 @@ fn test_proof_construction() { .expect("successful item insert"); // Manually build the ads structures - let mut inner_tree_merk = TempMerk::new().unwrap(); + let mut inner_tree_merk = TempMerk::new(); let value_element = Element::Item(b"value1".to_vec()); value_element.insert(&mut inner_tree_merk, b"key1".to_vec()); - let mut test_leaf_merk = TempMerk::new().unwrap(); + let mut test_leaf_merk = TempMerk::new(); let inner_tree_root_element = Element::Tree(inner_tree_merk.root_hash()); inner_tree_root_element.insert(&mut test_leaf_merk, b"innertree".to_vec()); - let another_test_leaf_merk = TempMerk::new().unwrap(); + let another_test_leaf_merk = TempMerk::new(); let leaves = [ test_leaf_merk.root_hash(), @@ -273,19 +273,19 @@ fn test_proof_construction() { let root_tree = MerkleTree::::from_leaves(&leaves); // Generate groove db proof - let ads_proofs = temp_db + let proof = temp_db .proof(&[TEST_LEAF, b"innertree"], b"key1") .expect("Successful proof generation"); - assert_eq!(ads_proofs.len(), 3); + assert_eq!(proof.len(), 3); let mut proof_query = Query::new(); proof_query.insert_key(b"key1".to_vec()); - assert_eq!(ads_proofs[0], inner_tree_merk.prove(proof_query).unwrap()); + assert_eq!(proof[0], inner_tree_merk.prove(proof_query).unwrap()); let mut proof_query = Query::new(); proof_query.insert_key(b"innertree".to_vec()); - assert_eq!(ads_proofs[1], test_leaf_merk.prove(proof_query).unwrap()); + assert_eq!(proof[1], test_leaf_merk.prove(proof_query).unwrap()); - assert_eq!(ads_proofs[2], root_tree.proof(&vec![0]).to_bytes()); -} + assert_eq!(proof[2], root_tree.proof(&vec![0]).to_bytes()); +} \ No newline at end of file From 8f7bba729a935292b467b2707cc7aeeebbffeadb Mon Sep 17 00:00:00 2001 From: Wisdom Ogwu Date: Mon, 29 Nov 2021 16:48:04 +0100 Subject: [PATCH 10/20] Ignore of grove.db folder not necessary --- .gitignore | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 4b1aa93d0..b169f3d41 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ /target .idea -Cargo.lock -grove.db \ No newline at end of file +Cargo.lock \ No newline at end of file From d28f4570fc9e252b02d2e0bb0e9faff578a0e0c7 Mon Sep 17 00:00:00 2001 From: Wisdom Ogwu Date: Mon, 29 Nov 2021 16:49:39 +0100 Subject: [PATCH 11/20] Removed unnecessary vec! --- grovedb/src/lib.rs | 2 +- grovedb/src/tests.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/grovedb/src/lib.rs b/grovedb/src/lib.rs index f9078d68d..0fcd268a7 100644 --- a/grovedb/src/lib.rs +++ b/grovedb/src/lib.rs @@ -242,7 +242,7 @@ impl GroveDb { .root_leaf_keys .get(*key) .ok_or(Error::InvalidPath("root key not found"))?; - proofs.push(self.root_tree.proof(&vec![*root_key_index]).to_bytes()); + proofs.push(self.root_tree.proof(&[*root_key_index]).to_bytes()); } else { let merk = self .subtrees diff --git a/grovedb/src/tests.rs b/grovedb/src/tests.rs index 441366745..8772a7328 100644 --- a/grovedb/src/tests.rs +++ b/grovedb/src/tests.rs @@ -288,4 +288,4 @@ fn test_proof_construction() { assert_eq!(proof[1], test_leaf_merk.prove(proof_query).unwrap()); assert_eq!(proof[2], root_tree.proof(&vec![0]).to_bytes()); -} \ No newline at end of file +} From b7a268a57b97434ccc2c836bca095e0af2e3ac51 Mon Sep 17 00:00:00 2001 From: Wisdom Ogwu Date: Thu, 2 Dec 2021 13:41:49 +0100 Subject: [PATCH 12/20] Fixed typo --- grovedb/src/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grovedb/src/tests.rs b/grovedb/src/tests.rs index 8772a7328..cad5d8b23 100644 --- a/grovedb/src/tests.rs +++ b/grovedb/src/tests.rs @@ -272,7 +272,7 @@ fn test_proof_construction() { ]; let root_tree = MerkleTree::::from_leaves(&leaves); - // Generate groove db proof + // Generate grove db proof let proof = temp_db .proof(&[TEST_LEAF, b"innertree"], b"key1") .expect("Successful proof generation"); From ecd68a64b34bb84ffb92132021d0e00bb7efc48a Mon Sep 17 00:00:00 2001 From: Wisdom Ogwu Date: Fri, 3 Dec 2021 09:42:33 +0100 Subject: [PATCH 13/20] Added support for range queries --- grovedb/src/lib.rs | 42 ++++++++++++++++++++++++++---------------- grovedb/src/tests.rs | 2 +- 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/grovedb/src/lib.rs b/grovedb/src/lib.rs index 0fcd268a7..0203b3e01 100644 --- a/grovedb/src/lib.rs +++ b/grovedb/src/lib.rs @@ -9,6 +9,7 @@ use std::{ rc::Rc, }; +pub use merk::proofs::query::QueryItem; use merk::{self, proofs::Query, rocksdb, Merk}; use rs_merkle::{algorithms::Sha256, MerkleTree}; use subtree::Element; @@ -231,10 +232,15 @@ impl GroveDb { Err(Error::ReferenceLimit) } - pub fn proof(&self, path: &[&[u8]], key: &[u8]) -> Result>, Error> { - let mut split_path = Some((&key, path)); + pub fn proof(&self, path: &[&[u8]], item: QueryItem) -> Result>, Error> { let mut proofs: Vec> = Vec::new(); + // First prove the query + proofs.push(self.prove_item(path, item)?); + + // Next prove the query path + let mut split_path = path.split_last(); + while let Some((key, path_slice)) = split_path { if path_slice.is_empty() { // Get proof for root tree at current key @@ -244,20 +250,7 @@ impl GroveDb { .ok_or(Error::InvalidPath("root key not found"))?; proofs.push(self.root_tree.proof(&[*root_key_index]).to_bytes()); } else { - let merk = self - .subtrees - .get(&Self::compress_path(path_slice, None)) - .ok_or(Error::InvalidPath("no subtree found under that path"))?; - - // Generate a proof for this merk at the given key - let mut proof_query = Query::new(); - proof_query.insert_key(key.to_vec()); - - let proof_result = merk - .prove(proof_query) - .expect("should prove both inclusion and absence"); - - proofs.push(proof_result); + proofs.push(self.prove_item(path_slice, QueryItem::Key(key.to_vec()))?); } split_path = path_slice.split_last(); } @@ -265,6 +258,23 @@ impl GroveDb { Ok(proofs) } + fn prove_item(&self, path: &[&[u8]], item: QueryItem) -> Result, Error> { + let merk = self + .subtrees + .get(&Self::compress_path(path, None)) + .ok_or(Error::InvalidPath("no subtree found under that path"))?; + + // Generate a proof for this merk at the given key + let mut proof_query = Query::new(); + proof_query.insert_item(item); + + let proof_result = merk + .prove(proof_query) + .expect("should prove both inclusion and absence"); + + Ok(proof_result) + } + /// Method to propagate updated subtree root hashes up to GroveDB root fn propagate_changes(&mut self, path: &[&[u8]]) -> Result<(), Error> { let mut split_path = path.split_last(); diff --git a/grovedb/src/tests.rs b/grovedb/src/tests.rs index cad5d8b23..9d6351d10 100644 --- a/grovedb/src/tests.rs +++ b/grovedb/src/tests.rs @@ -274,7 +274,7 @@ fn test_proof_construction() { // Generate grove db proof let proof = temp_db - .proof(&[TEST_LEAF, b"innertree"], b"key1") + .proof(&[TEST_LEAF, b"innertree"], QueryItem::Key(b"key1".to_vec())) .expect("Successful proof generation"); assert_eq!(proof.len(), 3); From 37482af4003b88d4f2441c0f7164f88055cad366 Mon Sep 17 00:00:00 2001 From: Wisdom Ogwu Date: Fri, 3 Dec 2021 09:45:13 +0100 Subject: [PATCH 14/20] fmt --- grovedb/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/grovedb/src/lib.rs b/grovedb/src/lib.rs index 0203b3e01..dc45e7a60 100644 --- a/grovedb/src/lib.rs +++ b/grovedb/src/lib.rs @@ -240,7 +240,6 @@ impl GroveDb { // Next prove the query path let mut split_path = path.split_last(); - while let Some((key, path_slice)) = split_path { if path_slice.is_empty() { // Get proof for root tree at current key From 08b52a24d7dbb3683064ca08889c4a3eea290f6f Mon Sep 17 00:00:00 2001 From: Wisdom Ogwu Date: Thu, 16 Dec 2021 16:26:38 +0100 Subject: [PATCH 15/20] Adding root key hash map to constructed proof --- grovedb/src/lib.rs | 4 ++++ grovedb/src/tests.rs | 8 +++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/grovedb/src/lib.rs b/grovedb/src/lib.rs index dc45e7a60..e53da9ca9 100644 --- a/grovedb/src/lib.rs +++ b/grovedb/src/lib.rs @@ -254,6 +254,10 @@ impl GroveDb { split_path = path_slice.split_last(); } + // Append the leaf keys to the hash map for proof verification + let aux_data = bincode::serialize(&self.root_leaf_keys)?; + proofs.push(aux_data); + Ok(proofs) } diff --git a/grovedb/src/tests.rs b/grovedb/src/tests.rs index 9d6351d10..c1bf5fec4 100644 --- a/grovedb/src/tests.rs +++ b/grovedb/src/tests.rs @@ -277,7 +277,7 @@ fn test_proof_construction() { .proof(&[TEST_LEAF, b"innertree"], QueryItem::Key(b"key1".to_vec())) .expect("Successful proof generation"); - assert_eq!(proof.len(), 3); + assert_eq!(proof.len(), 4); let mut proof_query = Query::new(); proof_query.insert_key(b"key1".to_vec()); @@ -288,4 +288,10 @@ fn test_proof_construction() { assert_eq!(proof[1], test_leaf_merk.prove(proof_query).unwrap()); assert_eq!(proof[2], root_tree.proof(&vec![0]).to_bytes()); + + let root_leaf_keys: HashMap, usize> = bincode::deserialize(&proof[3][..]).unwrap(); + assert_eq!(root_leaf_keys.len(), temp_db.root_leaf_keys.len()); + for (key, index) in &root_leaf_keys { + assert_eq!(root_leaf_keys[key], temp_db.root_leaf_keys[key]); + } } From 68ef9d9e64d5b0394bc21d50e4811e868a52cdce Mon Sep 17 00:00:00 2001 From: Wisdom Ogwu Date: Thu, 16 Dec 2021 16:51:39 +0100 Subject: [PATCH 16/20] Fixed comment --- grovedb/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grovedb/src/lib.rs b/grovedb/src/lib.rs index e53da9ca9..4f9812b75 100644 --- a/grovedb/src/lib.rs +++ b/grovedb/src/lib.rs @@ -254,7 +254,7 @@ impl GroveDb { split_path = path_slice.split_last(); } - // Append the leaf keys to the hash map for proof verification + // Append the root leaf keys hash map to proof to provide context when verifying proof let aux_data = bincode::serialize(&self.root_leaf_keys)?; proofs.push(aux_data); From 01138b7bd3cd50ee574f99854a0434958d5774b0 Mon Sep 17 00:00:00 2001 From: Wisdom Ogwu Date: Mon, 20 Dec 2021 08:18:06 +0100 Subject: [PATCH 17/20] Added more values to test merk --- grovedb/src/lib.rs | 3 ++- grovedb/src/tests.rs | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/grovedb/src/lib.rs b/grovedb/src/lib.rs index 4f9812b75..8ca8633c5 100644 --- a/grovedb/src/lib.rs +++ b/grovedb/src/lib.rs @@ -254,7 +254,8 @@ impl GroveDb { split_path = path_slice.split_last(); } - // Append the root leaf keys hash map to proof to provide context when verifying proof + // Append the root leaf keys hash map to proof to provide context when verifying + // proof let aux_data = bincode::serialize(&self.root_leaf_keys)?; proofs.push(aux_data); diff --git a/grovedb/src/tests.rs b/grovedb/src/tests.rs index c1bf5fec4..69f34742d 100644 --- a/grovedb/src/tests.rs +++ b/grovedb/src/tests.rs @@ -254,11 +254,20 @@ fn test_proof_construction() { Element::Item(b"value1".to_vec()), ) .expect("successful item insert"); + temp_db + .insert( + &[TEST_LEAF, b"innertree"], + b"key2".to_vec(), + Element::Item(b"value2".to_vec()), + ) + .expect("successful item insert"); // Manually build the ads structures let mut inner_tree_merk = TempMerk::new(); let value_element = Element::Item(b"value1".to_vec()); value_element.insert(&mut inner_tree_merk, b"key1".to_vec()); + let value_element = Element::Item(b"value2".to_vec()); + value_element.insert(&mut inner_tree_merk, b"key2".to_vec()); let mut test_leaf_merk = TempMerk::new(); let inner_tree_root_element = Element::Tree(inner_tree_merk.root_hash()); From fdfb98e9d808538e18d04865c04e27c8754dab0d Mon Sep 17 00:00:00 2001 From: Wisdom Ogwu Date: Mon, 20 Dec 2021 08:24:53 +0100 Subject: [PATCH 18/20] Extended proof function to take a query object instead of a query item --- grovedb/src/lib.rs | 14 ++++++++------ grovedb/src/tests.rs | 4 +++- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/grovedb/src/lib.rs b/grovedb/src/lib.rs index 8ca8633c5..8112c2c29 100644 --- a/grovedb/src/lib.rs +++ b/grovedb/src/lib.rs @@ -232,11 +232,11 @@ impl GroveDb { Err(Error::ReferenceLimit) } - pub fn proof(&self, path: &[&[u8]], item: QueryItem) -> Result>, Error> { + pub fn proof(&self, path: &[&[u8]], proof_query: Query) -> Result>, Error> { let mut proofs: Vec> = Vec::new(); // First prove the query - proofs.push(self.prove_item(path, item)?); + proofs.push(self.prove_item(path, proof_query)?); // Next prove the query path let mut split_path = path.split_last(); @@ -249,7 +249,9 @@ impl GroveDb { .ok_or(Error::InvalidPath("root key not found"))?; proofs.push(self.root_tree.proof(&[*root_key_index]).to_bytes()); } else { - proofs.push(self.prove_item(path_slice, QueryItem::Key(key.to_vec()))?); + let mut path_query = Query::new(); + path_query.insert_item(QueryItem::Key(key.to_vec())); + proofs.push(self.prove_item(path_slice, path_query)?); } split_path = path_slice.split_last(); } @@ -262,15 +264,15 @@ impl GroveDb { Ok(proofs) } - fn prove_item(&self, path: &[&[u8]], item: QueryItem) -> Result, Error> { + fn prove_item(&self, path: &[&[u8]], proof_query: Query) -> Result, Error> { let merk = self .subtrees .get(&Self::compress_path(path, None)) .ok_or(Error::InvalidPath("no subtree found under that path"))?; // Generate a proof for this merk at the given key - let mut proof_query = Query::new(); - proof_query.insert_item(item); + // let mut proof_query = Query::new(); + // proof_query.insert_item(item); let proof_result = merk .prove(proof_query) diff --git a/grovedb/src/tests.rs b/grovedb/src/tests.rs index 69f34742d..e0acd9bc6 100644 --- a/grovedb/src/tests.rs +++ b/grovedb/src/tests.rs @@ -282,8 +282,10 @@ fn test_proof_construction() { let root_tree = MerkleTree::::from_leaves(&leaves); // Generate grove db proof + let mut proof_query = Query::new(); + proof_query.insert_key(b"key1".to_vec()); let proof = temp_db - .proof(&[TEST_LEAF, b"innertree"], QueryItem::Key(b"key1".to_vec())) + .proof(&[TEST_LEAF, b"innertree"], proof_query) .expect("Successful proof generation"); assert_eq!(proof.len(), 4); From c221f7cff51a22aff8d160052c3ca69bfea8d0c8 Mon Sep 17 00:00:00 2001 From: Wisdom Ogwu Date: Mon, 20 Dec 2021 09:35:35 +0100 Subject: [PATCH 19/20] Exposed query and query item for library client --- grovedb/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/grovedb/src/lib.rs b/grovedb/src/lib.rs index 8112c2c29..f1678f6d2 100644 --- a/grovedb/src/lib.rs +++ b/grovedb/src/lib.rs @@ -9,8 +9,8 @@ use std::{ rc::Rc, }; -pub use merk::proofs::query::QueryItem; -use merk::{self, proofs::Query, rocksdb, Merk}; +pub use merk::proofs::{query::QueryItem, Query}; +use merk::{self, rocksdb, Merk}; use rs_merkle::{algorithms::Sha256, MerkleTree}; use subtree::Element; From 55691c3800a135505ba99aa25aa30072778488d7 Mon Sep 17 00:00:00 2001 From: Wisdom Ogwu Date: Mon, 20 Dec 2021 17:41:57 +0100 Subject: [PATCH 20/20] fmt --- grovedb/src/lib.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/grovedb/src/lib.rs b/grovedb/src/lib.rs index b54eff67c..111336d51 100644 --- a/grovedb/src/lib.rs +++ b/grovedb/src/lib.rs @@ -299,10 +299,6 @@ impl GroveDb { .get(&Self::compress_path(path, None)) .ok_or(Error::InvalidPath("no subtree found under that path"))?; - // Generate a proof for this merk at the given key - // let mut proof_query = Query::new(); - // proof_query.insert_item(item); - let proof_result = merk .prove(proof_query) .expect("should prove both inclusion and absence");