diff --git a/grovedb/Cargo.toml b/grovedb/Cargo.toml index 0deefd5e..28ba9995 100644 --- a/grovedb/Cargo.toml +++ b/grovedb/Cargo.toml @@ -23,7 +23,7 @@ derive_more = { version = "0.99.18" } integer-encoding = { version = "4.0.0", optional = true } grovedb-costs = { version = "1.0.0-rc.2", path = "../costs", optional = true } nohash-hasher = { version = "0.2.0", optional = true } -indexmap = { version = "2.2.6", optional = true } +indexmap = { version = "2.2.6"} intmap = { version = "2.0.0", optional = true } grovedb-path = { version = "1.0.0-rc.2", path = "../path" } grovedbg-types = { path = "../grovedbg-types", optional = true } @@ -57,7 +57,6 @@ full = [ "integer-encoding", "grovedb-costs", "nohash-hasher", - "indexmap", "intmap" ] visualize = [ diff --git a/grovedb/src/element/helpers.rs b/grovedb/src/element/helpers.rs index 222bafbd..59cc2563 100644 --- a/grovedb/src/element/helpers.rs +++ b/grovedb/src/element/helpers.rs @@ -43,15 +43,17 @@ use grovedb_merk::{ #[cfg(feature = "full")] use integer_encoding::VarInt; +#[cfg(feature = "full")] +use crate::reference_path::path_from_reference_path_type; #[cfg(any(feature = "full", feature = "verify"))] -use crate::reference_path::{path_from_reference_path_type, ReferencePathType}; -#[cfg(any(feature = "full", feature = "verify"))] -use crate::{element::SUM_ITEM_COST_SIZE, Element, Error}; +use crate::reference_path::ReferencePathType; #[cfg(feature = "full")] use crate::{ - element::{SUM_TREE_COST_SIZE, TREE_COST_SIZE}, + element::{SUM_ITEM_COST_SIZE, SUM_TREE_COST_SIZE, TREE_COST_SIZE}, ElementFlags, }; +#[cfg(any(feature = "full", feature = "verify"))] +use crate::{Element, Error}; impl Element { #[cfg(any(feature = "full", feature = "verify"))] diff --git a/grovedb/src/element/mod.rs b/grovedb/src/element/mod.rs index 90bc34ec..2469ffe2 100644 --- a/grovedb/src/element/mod.rs +++ b/grovedb/src/element/mod.rs @@ -1,31 +1,3 @@ -// MIT LICENSE -// -// Copyright (c) 2021 Dash Core Group -// -// Permission is hereby granted, free of charge, to any -// person obtaining a copy of this software and associated -// documentation files (the "Software"), to deal in the -// Software without restriction, including without -// limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice -// shall be included in all copies or substantial portions -// of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - //! Module for subtrees handling. //! Subtrees handling is isolated so basically this module is about adapting //! Merk API to GroveDB needs. @@ -48,8 +20,8 @@ mod query; pub use query::QueryOptions; #[cfg(any(feature = "full", feature = "verify"))] mod serialize; -#[cfg(feature = "full")] -use core::fmt; +#[cfg(any(feature = "full", feature = "verify"))] +use std::fmt; use bincode::{Decode, Encode}; #[cfg(any(feature = "full", feature = "verify"))] diff --git a/grovedb/src/element/query.rs b/grovedb/src/element/query.rs index 46e2a9ab..2eb8f556 100644 --- a/grovedb/src/element/query.rs +++ b/grovedb/src/element/query.rs @@ -38,13 +38,17 @@ use grovedb_costs::{ }; #[cfg(feature = "full")] use grovedb_merk::proofs::query::query_item::QueryItem; +#[cfg(feature = "full")] use grovedb_merk::proofs::query::SubqueryBranch; #[cfg(any(feature = "full", feature = "verify"))] use grovedb_merk::proofs::Query; +#[cfg(feature = "full")] use grovedb_path::SubtreePath; #[cfg(feature = "full")] use grovedb_storage::{rocksdb_storage::RocksDbStorage, RawIterator, StorageContext}; +#[cfg(feature = "full")] +use crate::operations::proof::util::hex_to_ascii; #[cfg(feature = "full")] use crate::{ element::helpers::raw_decode, @@ -58,9 +62,8 @@ use crate::{ util::{merk_optional_tx, merk_optional_tx_internal_error, storage_context_optional_tx}, Error, PathQuery, TransactionArg, }; -use crate::{operations::proof::util::hex_to_ascii, query_result_type::Path}; #[cfg(any(feature = "full", feature = "verify"))] -use crate::{Element, SizedQuery}; +use crate::{query_result_type::Path, Element, SizedQuery}; #[cfg(any(feature = "full", feature = "verify"))] #[derive(Copy, Clone, Debug)] @@ -130,6 +133,7 @@ where pub offset: &'a mut Option, } +#[cfg(feature = "full")] fn format_query(query: &Query, indent: usize) -> String { let indent_str = " ".repeat(indent); let mut output = format!("{}Query {{\n", indent_str); @@ -165,6 +169,7 @@ fn format_query(query: &Query, indent: usize) -> String { output } +#[cfg(feature = "full")] fn format_subquery_branch(branch: &SubqueryBranch, indent: usize) -> String { let indent_str = " ".repeat(indent); let mut output = format!("SubqueryBranch {{\n"); diff --git a/grovedb/src/lib.rs b/grovedb/src/lib.rs index d901e83c..206ace71 100644 --- a/grovedb/src/lib.rs +++ b/grovedb/src/lib.rs @@ -201,6 +201,7 @@ use grovedb_merk::{ tree::{combine_hash, value_hash}, BatchEntry, CryptoHash, KVIterator, Merk, }; +#[cfg(feature = "full")] use grovedb_path::SubtreePath; #[cfg(feature = "full")] use grovedb_storage::rocksdb_storage::PrefixedRocksDbImmediateStorageContext; @@ -226,7 +227,7 @@ use crate::element::helpers::raw_decode; pub use crate::error::Error; #[cfg(feature = "full")] use crate::util::{root_merk_optional_tx, storage_context_optional_tx}; -#[cfg(any(feature = "full", feature = "verify"))] +#[cfg(feature = "full")] use crate::Error::MerkError; #[cfg(feature = "full")] @@ -238,6 +239,7 @@ pub struct GroveDb { db: RocksDbStorage, } +#[cfg(feature = "full")] pub(crate) type SubtreePrefix = [u8; blake3::OUT_LEN]; /// Transaction diff --git a/grovedb/src/operations/proof/generate.rs b/grovedb/src/operations/proof/generate.rs index 41a0dbe4..5640a70c 100644 --- a/grovedb/src/operations/proof/generate.rs +++ b/grovedb/src/operations/proof/generate.rs @@ -1,19 +1,13 @@ //! Generate proof operations -use std::{collections::BTreeMap, fmt}; +use std::collections::BTreeMap; -use bincode::{Decode, Encode}; -use derive_more::From; use grovedb_costs::{ cost_return_on_error, cost_return_on_error_default, cost_return_on_error_no_add, CostResult, CostsExt, OperationCost, }; use grovedb_merk::{ - proofs::{ - encode_into, - query::{Key, QueryItem}, - Decoder, Node, Op, - }, + proofs::{encode_into, query::QueryItem, Node, Op}, tree::value_hash, Merk, ProofWithoutEncodingResult, }; @@ -22,151 +16,13 @@ use grovedb_storage::StorageContext; #[cfg(feature = "proof_debug")] use crate::query_result_type::QueryResultType; use crate::{ - operations::proof::util::{element_hex_to_ascii, hex_to_ascii}, + operations::proof::{ + util::hex_to_ascii, GroveDBProof, GroveDBProofV0, LayerProof, ProveOptions, + }, reference_path::path_from_reference_path_type, Element, Error, GroveDb, PathQuery, }; -#[derive(Debug, Clone, Copy, Encode, Decode)] -pub struct ProveOptions { - pub decrease_limit_on_empty_sub_query_result: bool, -} - -impl fmt::Display for ProveOptions { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "ProveOptions {{ decrease_limit_on_empty_sub_query_result: {} }}", - self.decrease_limit_on_empty_sub_query_result - ) - } -} - -impl Default for ProveOptions { - fn default() -> Self { - ProveOptions { - decrease_limit_on_empty_sub_query_result: true, - } - } -} - -#[derive(Encode, Decode)] -pub struct LayerProof { - pub merk_proof: Vec, - pub lower_layers: BTreeMap, -} - -#[derive(Encode, Decode, From)] -pub enum GroveDBProof { - V0(GroveDBProofV0), -} - -#[derive(Encode, Decode)] -pub struct GroveDBProofV0 { - pub root_layer: LayerProof, - pub prove_options: ProveOptions, -} - -impl fmt::Display for LayerProof { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - writeln!(f, "LayerProof {{")?; - writeln!(f, " merk_proof: {}", decode_merk_proof(&self.merk_proof))?; - if !self.lower_layers.is_empty() { - writeln!(f, " lower_layers: {{")?; - for (key, layer_proof) in &self.lower_layers { - writeln!(f, " {} => {{", hex_to_ascii(key))?; - for line in format!("{}", layer_proof).lines() { - writeln!(f, " {}", line)?; - } - writeln!(f, " }}")?; - } - writeln!(f, " }}")?; - } - write!(f, "}}") - } -} - -impl fmt::Display for GroveDBProof { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - GroveDBProof::V0(proof) => write!(f, "{}", proof), - } - } -} - -impl fmt::Display for GroveDBProofV0 { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - writeln!(f, "GroveDBProofV0 {{")?; - for line in format!("{}", self.root_layer).lines() { - writeln!(f, " {}", line)?; - } - write!(f, "}}") - } -} - -fn decode_merk_proof(proof: &[u8]) -> String { - let mut result = String::new(); - let ops = Decoder::new(proof); - - for (i, op) in ops.enumerate() { - match op { - Ok(op) => { - result.push_str(&format!("\n {}: {}", i, op_to_string(&op))); - } - Err(e) => { - result.push_str(&format!("\n {}: Error decoding op: {}", i, e)); - } - } - } - - result -} - -fn op_to_string(op: &Op) -> String { - match op { - Op::Push(node) => format!("Push({})", node_to_string(node)), - Op::PushInverted(node) => format!("PushInverted({})", node_to_string(node)), - Op::Parent => "Parent".to_string(), - Op::Child => "Child".to_string(), - Op::ParentInverted => "ParentInverted".to_string(), - Op::ChildInverted => "ChildInverted".to_string(), - } -} - -fn node_to_string(node: &Node) -> String { - match node { - Node::Hash(hash) => format!("Hash(HASH[{}])", hex::encode(hash)), - Node::KVHash(kv_hash) => format!("KVHash(HASH[{}])", hex::encode(kv_hash)), - Node::KV(key, value) => { - format!("KV({}, {})", hex_to_ascii(key), element_hex_to_ascii(value)) - } - Node::KVValueHash(key, value, value_hash) => format!( - "KVValueHash({}, {}, HASH[{}])", - hex_to_ascii(key), - element_hex_to_ascii(value), - hex::encode(value_hash) - ), - Node::KVDigest(key, value_hash) => format!( - "KVDigest({}, HASH[{}])", - hex_to_ascii(key), - hex::encode(value_hash) - ), - Node::KVRefValueHash(key, value, value_hash) => format!( - "KVRefValueHash({}, {}, HASH[{}])", - hex_to_ascii(key), - element_hex_to_ascii(value), - hex::encode(value_hash) - ), - Node::KVValueHashFeatureType(key, value, value_hash, feature_type) => format!( - "KVValueHashFeatureType({}, {}, HASH[{}], {:?})", - hex_to_ascii(key), - element_hex_to_ascii(value), - hex::encode(value_hash), - feature_type - ), - } -} - impl GroveDb { /// Prove one or more path queries. /// If we have more than one path query, we merge into a single path query diff --git a/grovedb/src/operations/proof/mod.rs b/grovedb/src/operations/proof/mod.rs index 7b69b586..306b02d8 100644 --- a/grovedb/src/operations/proof/mod.rs +++ b/grovedb/src/operations/proof/mod.rs @@ -5,5 +5,150 @@ mod generate; pub mod util; mod verify; -#[cfg(feature = "full")] -pub use generate::ProveOptions; +use std::{collections::BTreeMap, fmt}; + +use bincode::{Decode, Encode}; +use derive_more::From; +use grovedb_merk::proofs::{query::Key, Decoder, Node, Op}; + +use crate::operations::proof::util::{element_hex_to_ascii, hex_to_ascii}; + +#[derive(Debug, Clone, Copy, Encode, Decode)] +pub struct ProveOptions { + pub decrease_limit_on_empty_sub_query_result: bool, +} + +impl fmt::Display for ProveOptions { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "ProveOptions {{ decrease_limit_on_empty_sub_query_result: {} }}", + self.decrease_limit_on_empty_sub_query_result + ) + } +} + +impl Default for ProveOptions { + fn default() -> Self { + ProveOptions { + decrease_limit_on_empty_sub_query_result: true, + } + } +} + +#[derive(Encode, Decode)] +pub struct LayerProof { + pub merk_proof: Vec, + pub lower_layers: BTreeMap, +} + +#[derive(Encode, Decode, From)] +pub enum GroveDBProof { + V0(GroveDBProofV0), +} + +#[derive(Encode, Decode)] +pub struct GroveDBProofV0 { + pub root_layer: LayerProof, + pub prove_options: ProveOptions, +} + +impl fmt::Display for LayerProof { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + writeln!(f, "LayerProof {{")?; + writeln!(f, " merk_proof: {}", decode_merk_proof(&self.merk_proof))?; + if !self.lower_layers.is_empty() { + writeln!(f, " lower_layers: {{")?; + for (key, layer_proof) in &self.lower_layers { + writeln!(f, " {} => {{", hex_to_ascii(key))?; + for line in format!("{}", layer_proof).lines() { + writeln!(f, " {}", line)?; + } + writeln!(f, " }}")?; + } + writeln!(f, " }}")?; + } + write!(f, "}}") + } +} + +impl fmt::Display for GroveDBProof { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + GroveDBProof::V0(proof) => write!(f, "{}", proof), + } + } +} + +impl fmt::Display for GroveDBProofV0 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + writeln!(f, "GroveDBProofV0 {{")?; + for line in format!("{}", self.root_layer).lines() { + writeln!(f, " {}", line)?; + } + write!(f, "}}") + } +} + +fn decode_merk_proof(proof: &[u8]) -> String { + let mut result = String::new(); + let ops = Decoder::new(proof); + + for (i, op) in ops.enumerate() { + match op { + Ok(op) => { + result.push_str(&format!("\n {}: {}", i, op_to_string(&op))); + } + Err(e) => { + result.push_str(&format!("\n {}: Error decoding op: {}", i, e)); + } + } + } + + result +} + +fn op_to_string(op: &Op) -> String { + match op { + Op::Push(node) => format!("Push({})", node_to_string(node)), + Op::PushInverted(node) => format!("PushInverted({})", node_to_string(node)), + Op::Parent => "Parent".to_string(), + Op::Child => "Child".to_string(), + Op::ParentInverted => "ParentInverted".to_string(), + Op::ChildInverted => "ChildInverted".to_string(), + } +} + +fn node_to_string(node: &Node) -> String { + match node { + Node::Hash(hash) => format!("Hash(HASH[{}])", hex::encode(hash)), + Node::KVHash(kv_hash) => format!("KVHash(HASH[{}])", hex::encode(kv_hash)), + Node::KV(key, value) => { + format!("KV({}, {})", hex_to_ascii(key), element_hex_to_ascii(value)) + } + Node::KVValueHash(key, value, value_hash) => format!( + "KVValueHash({}, {}, HASH[{}])", + hex_to_ascii(key), + element_hex_to_ascii(value), + hex::encode(value_hash) + ), + Node::KVDigest(key, value_hash) => format!( + "KVDigest({}, HASH[{}])", + hex_to_ascii(key), + hex::encode(value_hash) + ), + Node::KVRefValueHash(key, value, value_hash) => format!( + "KVRefValueHash({}, {}, HASH[{}])", + hex_to_ascii(key), + element_hex_to_ascii(value), + hex::encode(value_hash) + ), + Node::KVValueHashFeatureType(key, value, value_hash, feature_type) => format!( + "KVValueHashFeatureType({}, {}, HASH[{}], {:?})", + hex_to_ascii(key), + element_hex_to_ascii(value), + hex::encode(value_hash), + feature_type + ), + } +} diff --git a/grovedb/src/operations/proof/verify.rs b/grovedb/src/operations/proof/verify.rs index 11bdd754..e8063cea 100644 --- a/grovedb/src/operations/proof/verify.rs +++ b/grovedb/src/operations/proof/verify.rs @@ -15,9 +15,8 @@ use crate::operations::proof::util::{ }; use crate::{ operations::proof::{ - generate::{GroveDBProof, GroveDBProofV0, LayerProof}, util::{ProvedPathKeyOptionalValue, ProvedPathKeyValues}, - ProveOptions, + GroveDBProof, GroveDBProofV0, LayerProof, ProveOptions, }, query_result_type::PathKeyOptionalElementTrio, Element, Error, GroveDb, PathQuery, diff --git a/grovedb/src/query_result_type.rs b/grovedb/src/query_result_type.rs index 356fe92e..c050e38c 100644 --- a/grovedb/src/query_result_type.rs +++ b/grovedb/src/query_result_type.rs @@ -143,7 +143,7 @@ impl QueryResultElements { } /// From elements - pub(crate) fn from_elements(elements: Vec) -> Self { + pub fn from_elements(elements: Vec) -> Self { QueryResultElements { elements } } diff --git a/merk/Cargo.toml b/merk/Cargo.toml index 7b050c9c..2d1c65be 100644 --- a/merk/Cargo.toml +++ b/merk/Cargo.toml @@ -19,15 +19,12 @@ indexmap = "2.2.6" grovedb-costs = { version = "1.0.0-rc.2", path = "../costs" } grovedb-visualize = { version = "1.0.0-rc.2", path = "../visualize" } grovedb-path = { version = "1.0.0-rc.2", path = "../path" } +hex = { version = "0.4.3" } [dependencies.time] version = "0.3.34" optional = true -[dependencies.hex] -version = "0.4.3" -optional = true - [dependencies.colored] version = "2.1.0" optional = true @@ -58,7 +55,6 @@ default = ["full"] proof_debug = [] full = ["rand", "time", - "hex", "colored", "num_cpus", "byteorder", diff --git a/merk/src/lib.rs b/merk/src/lib.rs index e1a35d1d..d746a885 100644 --- a/merk/src/lib.rs +++ b/merk/src/lib.rs @@ -70,7 +70,7 @@ mod visualize; #[cfg(feature = "full")] pub use ed; -#[cfg(feature = "full")] +#[cfg(any(feature = "full", feature = "verify"))] pub use error::Error; #[cfg(feature = "full")] pub use tree::{ diff --git a/merk/src/proofs/query/mod.rs b/merk/src/proofs/query/mod.rs index 37388af4..107a1ec8 100644 --- a/merk/src/proofs/query/mod.rs +++ b/merk/src/proofs/query/mod.rs @@ -14,11 +14,11 @@ pub mod query_item; #[cfg(any(feature = "full", feature = "verify"))] mod verify; -#[cfg(any(feature = "full", feature = "verify"))] +#[cfg(feature = "full")] use std::cmp::Ordering; use std::{collections::HashSet, fmt, ops::RangeFull}; -#[cfg(any(feature = "full", feature = "verify"))] +#[cfg(feature = "full")] use grovedb_costs::{cost_return_on_error, CostContext, CostResult, CostsExt, OperationCost}; #[cfg(any(feature = "full", feature = "verify"))] use indexmap::IndexMap; @@ -28,7 +28,7 @@ pub use map::*; pub use query_item::intersect::QueryItemIntersectionResult; #[cfg(any(feature = "full", feature = "verify"))] pub use query_item::QueryItem; -#[cfg(any(feature = "full", feature = "verify"))] +#[cfg(feature = "full")] use verify::ProofAbsenceLimit; #[cfg(any(feature = "full", feature = "verify"))] pub use verify::VerifyOptions; @@ -37,7 +37,7 @@ pub use verify::{ProofVerificationResult, ProvedKeyOptionalValue, ProvedKeyValue #[cfg(feature = "full")] use {super::Op, std::collections::LinkedList}; -#[cfg(any(feature = "full", feature = "verify"))] +#[cfg(feature = "full")] use super::Node; #[cfg(any(feature = "full", feature = "verify"))] use crate::error::Error; diff --git a/merk/src/proofs/query/query_item/mod.rs b/merk/src/proofs/query/query_item/mod.rs index 6269c239..7c81a27e 100644 --- a/merk/src/proofs/query/query_item/mod.rs +++ b/merk/src/proofs/query/query_item/mod.rs @@ -10,7 +10,7 @@ use std::{ ops::{Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive}, }; -#[cfg(any(feature = "full", feature = "verify"))] +#[cfg(feature = "full")] use grovedb_costs::{CostContext, CostsExt, OperationCost}; #[cfg(feature = "full")] use grovedb_storage::RawIterator; @@ -427,7 +427,7 @@ impl QueryItem { } #[cfg(any(feature = "full", feature = "verify"))] - fn compare(a: &[u8], b: &[u8]) -> cmp::Ordering { + pub fn compare(a: &[u8], b: &[u8]) -> cmp::Ordering { for (ai, bi) in a.iter().zip(b.iter()) { match ai.cmp(bi) { Ordering::Equal => continue, diff --git a/merk/src/proofs/query/verify.rs b/merk/src/proofs/query/verify.rs index 56902ce8..2e1727f4 100644 --- a/merk/src/proofs/query/verify.rs +++ b/merk/src/proofs/query/verify.rs @@ -1,17 +1,22 @@ -use std::{collections::LinkedList, fmt}; +#[cfg(feature = "full")] +use std::collections::LinkedList; +use std::fmt; use grovedb_costs::{cost_return_on_error, CostResult, CostsExt, OperationCost}; #[cfg(feature = "full")] -use crate::proofs::query::{Map, MapBuilder}; +use crate::proofs::{ + query::{Map, MapBuilder}, + Op, +}; use crate::{ error::Error, - proofs::{hex_to_ascii, tree::execute, Decoder, Node, Op, Query}, + proofs::{hex_to_ascii, tree::execute, Decoder, Node, Query}, tree::value_hash, CryptoHash as MerkHash, CryptoHash, }; -#[cfg(any(feature = "full", feature = "verify"))] +#[cfg(feature = "full")] pub type ProofAbsenceLimit = (LinkedList, (bool, bool), Option); #[cfg(feature = "full")]